#include "eel.h" /* Written by Bob Wilber bwilber@descartes.com The functions decorate_character() and exchange_with_mate() are used to enter characters in the upper half of an 8-bit character set with a standard ASCII keyboard by using easy to remember sequences. No more memorizing arbitrary numeric codes! The current tables are set up for the ISO 8859 Latin-1 character set. If you use a different 8-bit character set you'll have to change the tables. WARNING: Some of the characters in the comments are Latin-1 non-ASCII characters. So you won't be able to read all of the comments if you can't display Latin-1. However no non-ASCII characters are in the code -- any Latin-1 character with high bit 1 is represented as a hexadecimal integer. decorate_character() (Alt-Ctrl-D) operates upon the two characters before point. (If point is at the start of a line or one character from the start of a line then decorate_character() operates on the first two characters of the line.) It combines two ASCII characters to create a single character in the upper half of an 8-bit character set. Typically the first character is a letter and the second is a punctuation symbol that specifies what diacritical mark to add. For example, if point is after "a'" when decorate_character() is invoked then the two characters are replaced by an accented "a" -- "á". Some of the conversions, with emphasis on the less obvious ones, are shown here (you won't see this properly unless you can display Latin-1 characters): e: => ë c, => ç u` => ù O/ => Ø Ao => Å ao => å AE (or Ae) => Æ ae => æ D- => Ð d- => ð TH (or Th) => Þ th => þ ss => ß 12 => ½ 14 => ¼ 34 => ¾ You can only create letter-diacritic combinations that are supported in the character set; for example, you can combine "o" and "~" to get "õ" but you can't combine "e" and "~". decorate_character() does nothing if you specify an invalid combination. If you try to decorate a letter that already has a diacritic the old diacritic will be removed before adding the new one. E.g. å^ => â exchange_with_mate() (Alt-Ctrl-X) is used to create punctuation characters in the upper half of an 8-bit character set. The idea is that we pair each such character with an easily remembered character in the lower (ASCII) half of the 8-bit character set, called its *mate*. For example, '?' is mated with '¿', '!' with '¡', and so forth. exchange_with_mate() replaces the character before point with its mate. (If point is at the start of a line, it operates on the first character of the line.) Here is the complete set of mated pairs: ! <=> ¡ ? <=> ¿ $ <=> ¢ P <=> £ # <=> ¤ Y <=> ¥ | <=> ¦ : <=> ¨ ' <=> ´ A <=> ª 0 <=> º (masculine ordinal indicator) o <=> ° (degree sign) < <=> « > <=> » + <=> ± - (dash/minus) <=> ­ (soft hyphen) 1 <=> ¹ 2 <=> ² 3 <=> ³ u <=> µ p <=> ¶ s <=> § . <=> · , <=> ¸ \ <=> ¬ _ <=> ¯ c <=> © r <=> ® * <=> × / <=> ÷ */ /* This table maps most characters to themselves. But letters that have diacritical marks are mapped to their unadorned versions. */ volatile char undecorate_table[256] = { /* 0x */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 1x */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 2x */ ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', /* 3x */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', /* 4x */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 5x */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', /* 6x */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 7x */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7F, /* 8x */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, /* 9x */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, /* Ax */ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, /* Bx */ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, /* Cx */ 'A', 'A', 'A', 'A', 'A', 'A', 0xC6, 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', /* Dx */ 'D', 'N', 'O', 'O', 'O', 'O', 'O', 0xD7, 'O', 'U', 'U', 'U', 'U', 'Y', 0xDE, 0xDF, /* Ex */ 'a', 'a', 'a', 'a', 'a', 'a', 0xE6, 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', /* Fx */ 'd', 'n', 'o', 'o', 'o', 'o', 'o', 0xF7, 'o', 'u', 'u', 'u', 'u', 'y', 0xFE, 'y' }; typedef struct { char from; char to; } DecoratedOperands; volatile DecoratedOperands decorated_operands[] = { /* Conversions for "`". */ { 'A', 0xC0 }, { 'a', 0xE0 }, { 'E', 0xC8 }, { 'e', 0xE8 }, { 'I', 0xCC }, { 'i', 0xEC }, { 'O', 0xD2 }, { 'o', 0xF2 }, { 'U', 0xD9 }, { 'u', 0xF9 }, /* Conversions for "'". */ { 'A', 0xC1 }, { 'a', 0xE1 }, { 'E', 0xC9 }, { 'e', 0xE9 }, { 'I', 0xCD }, { 'i', 0xED }, { 'O', 0xD3 }, { 'o', 0xF3 }, { 'U', 0xDA }, { 'u', 0xFA }, { 'Y', 0xDD }, { 'y', 0xFD }, /* Conversions for "^". */ { 'A', 0xC2 }, { 'a', 0xE2 }, { 'E', 0xCA }, { 'e', 0xEA }, { 'I', 0xCE }, { 'i', 0xEE }, { 'O', 0xD4 }, { 'o', 0xF4 }, { 'U', 0xDB }, { 'u', 0xFB }, /* Conversions for "~". */ { 'A', 0xC3 }, { 'a', 0xE3 }, { 'N', 0xD1 }, { 'n', 0xF1 }, { 'O', 0xD5 }, { 'o', 0xF5 }, /* Conversions for ":" */ { 'A', 0xC4 }, { 'a', 0xE4 }, { 'E', 0xCB }, { 'e', 0xEB }, { 'I', 0xCF }, { 'i', 0xEF }, { 'O', 0xD6 }, { 'o', 0xF6 }, { 'U', 0xDC }, { 'u', 0xFC }, { 'y', 0xFF }, /* Conversions for "o" */ { 'A', 0xC5 }, { 'a', 0xE5 }, /* Conversions for "," */ { 'C', 0xC7 }, { 'c', 0xE7 }, /* Conversions for "/" */ { 'O', 0xD8 }, { 'o', 0xF8 }, /* Conversions for "E" */ { 'A', 0xC6 }, /* Conversions for "e" ("AE" and "Ae" both produce the uppercase combination) */ { 'a', 0xE6 }, { 'A', 0xC6 }, /* Conversions for "s" */ { 's', 0xDF }, /* Conversions for "H" */ { 'T', 0xDE }, /* Conversions for "h" */ { 'T', 0xDE }, { 't', 0xFE }, /* Conversions for "-" */ { 'D', 0xD0 }, { 'd', 0xF0 }, /* Conversions for "2" */ { '1', 0xBD }, /* Conversions for "4" ("12" and "24" both become 1/2) */ { '1', 0xBC }, {'2', 0xBD }, { '3', 0xBE } }; #define N_DECORATORS 16 typedef struct { char dec; int length; int startIndex; } DecoratorList; /* The startIndex field gives the index of the conversion list within decorated_operands[]. */ volatile DecoratorList decorator_list[N_DECORATORS] = { { '`', 10, 0 }, { '\'', 12, 10 }, { '^', 10, 22 }, { '~', 6, 32 }, { ':', 11, 38 }, { 'o', 2, 49 }, { ',', 2, 51 }, { '/', 2, 53 }, { 'E', 1, 55 }, { 'e', 2, 56 }, { 's', 1, 58 }, { 'H', 1, 59 }, { 'h', 2, 60 }, { '-', 2, 62 }, { '2', 1, 64 }, { '4', 3, 65 } }; /* If you change this make sure to maintain the invariant mate_table[mate_table[c]] == c. */ volatile char mate_table[256] = { /* 0x */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 1x */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 2x */ ' ', 0xA1, '"', 0xA4, 0xA2, '%', '&', 0xB4, '(', ')', 0xD7, 0xB1, 0xB8, 0xAD, 0xB7, 0xF7, /* 3x */ '0', 0xB9, 0xB2, 0xB3, '4', '5', '6', '7', '8', '9', 0xA8, ';', 0xAB, '=', 0xBB, 0xBF, /* 4x */ '@', 0xAA, 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 0xBA, /* 5x */ 0xA3, 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 0xA5, 'Z', '[', 0xAC, ']', '^', 0xAF, /* 6x */ '`', 'a', 'b', 0xA9, 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 0xB0, /* 7x */ 0xB6, 'q', 0xAE, 0xA7, 't', 0xB5, 'v', 'w', 'x', 'y', 'z', '{', 0xA6, '}', '~', 0x7F, /* 8x */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, /* 9x */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, /* Ax */ 0xA0, '!', '$', 'P', '#', 'Y', '|', 's', ':', 'c', 'A', '<', '\\', '-', 'r', '_', /* Bx */ 'o', '+', '2', '3', '\'', 'u', 'p', '.', ',', '1', 'O', '>', 0xBC, 0xBD, 0xBE, '?', /* Cx */ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, /* Dx */ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, '*', 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, /* Ex */ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, /* Fx */ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, '/', 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; command decorate_character() on reg_tab[ALT(CTRL('D'))] { int p = point; char operand, decorator; int i, j, cnt; DecoratedOperands* op; if (p == 0 || character(point - 1) == '\n') p += 2; else if (p == 1 || character(point - 2) == '\n') p += 1; if (p > size()) return; operand = undecorate_table[character(p - 2)]; /* Strip off any diacritical marks already on the operand. */ decorator = character(p - 1); for (i = 0; i < N_DECORATORS; ++i) { if (decorator_list[i].dec == decorator) { op = decorated_operands + decorator_list[i].startIndex; cnt = decorator_list[i].length; for (j = 0; j < cnt; ++j) { if (op[j].from == operand) { replace(p - 2, op[j].to); delete(p - 1, p); break; } } break; } } } command exchange_with_mate() on reg_tab[ALT(CTRL('X'))] { int p = point; if (p == 0 || character(p - 1) == '\n') ++p; replace(p - 1, mate_table[character(p - 1)]); }