| To: vim-dev@vim.org |
| Subject: Patch 7.2.109 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=ISO-8859-1 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| Patch 7.2.109 |
| Problem: 'langmap' does not work for multi-byte characters. |
| Solution: Add a list of mapped multi-byte characters. (based on work by |
| Konstantin Korikov, Agathoklis Hatzimanikas) |
| Files: runtime/doc/options.txt, src/edit.c, src/getchar.c, src/macros.h, |
| src/normal.c, src/option.c, src/proto/option.pro, src/window.c |
| |
| |
| |
| |
| |
| *** 4175,4183 **** |
| be able to execute Normal mode commands. |
| This is the opposite of the 'keymap' option, where characters are |
| mapped in Insert mode. |
| - This only works for 8-bit characters. The value of 'langmap' may be |
| - specified with multi-byte characters (e.g., UTF-8), but only the lower |
| - 8 bits of each character will be used. |
| |
| Example (for Greek, in UTF-8): *greek* > |
| :set langmap=ΑA,ΒB,ΨC,ΔD,ΕE,ΦF,ΓG,ΗH,ΙI,ΞJ,ΚK,ΛL,ΜM,ΝN,ΟO,ΠP,QQ,ΡR,ΣS,ΤT,ΘU,ΩV,WW,ΧX,ΥY,ΖZ,αa,βb,ψc,δd,εe,φf,γg,ηh,ιi,ξj,κk,λl,μm,νn,οo,πp,qq,ρr,σs,τt,θu,ωv,ςw,χx,υy,ζz |
| --- 4188,4193 ---- |
| |
| |
| |
| *** 7703,7711 **** |
| */ |
| ++no_mapping; |
| regname = plain_vgetc(); |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(regname, TRUE); |
| - #endif |
| if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) |
| { |
| /* Get a third key for literal register insertion */ |
| --- 7703,7709 ---- |
| |
| *** 7714,7722 **** |
| add_to_showcmd_c(literally); |
| #endif |
| regname = plain_vgetc(); |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(regname, TRUE); |
| - #endif |
| } |
| --no_mapping; |
| |
| --- 7712,7718 ---- |
| |
| |
| |
| *** 127,141 **** |
| #ifdef FEAT_LANGMAP |
| /* |
| * Adjust chars in a language according to 'langmap' option. |
| ! * NOTE that there is NO overhead if 'langmap' is not set; but even |
| ! * when set we only have to do 2 ifs and an array lookup. |
| * Don't apply 'langmap' if the character comes from the Stuff buffer. |
| * The do-while is just to ignore a ';' after the macro. |
| */ |
| ! # define LANGMAP_ADJUST(c, condition) do { \ |
| ! if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0 && (c) < 256) \ |
| ! c = langmap_mapchar[c]; \ |
| } while (0) |
| #endif |
| |
| /* |
| --- 127,157 ---- |
| #ifdef FEAT_LANGMAP |
| /* |
| * Adjust chars in a language according to 'langmap' option. |
| ! * NOTE that there is no noticeable overhead if 'langmap' is not set. |
| ! * When set the overhead for characters < 256 is small. |
| * Don't apply 'langmap' if the character comes from the Stuff buffer. |
| * The do-while is just to ignore a ';' after the macro. |
| */ |
| ! # ifdef FEAT_MBYTE |
| ! # define LANGMAP_ADJUST(c, condition) \ |
| ! do { \ |
| ! if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0) \ |
| ! { \ |
| ! if ((c) < 256) \ |
| ! c = langmap_mapchar[c]; \ |
| ! else \ |
| ! c = langmap_adjust_mb(c); \ |
| ! } \ |
| } while (0) |
| + # else |
| + # define LANGMAP_ADJUST(c, condition) \ |
| + do { \ |
| + if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0 && (c) < 256) \ |
| + c = langmap_mapchar[c]; \ |
| + } while (0) |
| + # endif |
| + #else |
| + # define LANGMAP_ADJUST(c, condition) /* nop */ |
| #endif |
| |
| /* |
| |
| |
| |
| *** 651,660 **** |
| * Get the command character from the user. |
| */ |
| c = safe_vgetc(); |
| - |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(c, TRUE); |
| - #endif |
| |
| #ifdef FEAT_VISUAL |
| /* |
| --- 651,657 ---- |
| |
| *** 744,752 **** |
| } |
| ++no_zero_mapping; /* don't map zero here */ |
| c = plain_vgetc(); |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(c, TRUE); |
| - #endif |
| --no_zero_mapping; |
| if (ctrl_w) |
| { |
| --- 741,747 ---- |
| |
| *** 769,777 **** |
| ++no_mapping; |
| ++allow_keys; /* no mapping for nchar, but keys */ |
| c = plain_vgetc(); /* get next character */ |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(c, TRUE); |
| - #endif |
| --no_mapping; |
| --allow_keys; |
| #ifdef FEAT_CMDL_INFO |
| --- 764,770 ---- |
| |
| *** 959,967 **** |
| * "gr", "g'" and "g`". |
| */ |
| ca.nchar = plain_vgetc(); |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(ca.nchar, TRUE); |
| - #endif |
| #ifdef FEAT_CMDL_INFO |
| need_flushbuf |= add_to_showcmd(ca.nchar); |
| #endif |
| --- 952,958 ---- |
| |
| *** 1062,1071 **** |
| } |
| #endif |
| |
| - #ifdef FEAT_LANGMAP |
| /* adjust chars > 127, except after "tTfFr" commands */ |
| LANGMAP_ADJUST(*cp, !lang); |
| - #endif |
| #ifdef FEAT_RIGHTLEFT |
| /* adjust Hebrew mapped char */ |
| if (p_hkmap && lang && KeyTyped) |
| --- 1053,1060 ---- |
| |
| *** 4630,4638 **** |
| ++no_mapping; |
| ++allow_keys; /* no mapping for nchar, but allow key codes */ |
| nchar = plain_vgetc(); |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(nchar, TRUE); |
| - #endif |
| --no_mapping; |
| --allow_keys; |
| #ifdef FEAT_CMDL_INFO |
| --- 4619,4625 ---- |
| |
| *** 4988,4996 **** |
| ++no_mapping; |
| ++allow_keys; /* no mapping for nchar, but allow key codes */ |
| nchar = plain_vgetc(); |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(nchar, TRUE); |
| - #endif |
| --no_mapping; |
| --allow_keys; |
| #ifdef FEAT_CMDL_INFO |
| --- 4975,4981 ---- |
| |
| |
| |
| *** 10153,10177 **** |
| |
| #ifdef FEAT_LANGMAP |
| /* |
| ! * Any character has an equivalent character. This is used for keyboards that |
| ! * have a special language mode that sends characters above 128 (although |
| ! * other characters can be translated too). |
| */ |
| |
| /* |
| ! * char_u langmap_mapchar[256]; |
| ! * Normally maps each of the 128 upper chars to an <128 ascii char; used to |
| ! * "translate" native lang chars in normal mode or some cases of |
| ! * insert mode without having to tediously switch lang mode back&forth. |
| */ |
| |
| static void |
| langmap_init() |
| { |
| int i; |
| |
| ! for (i = 0; i < 256; i++) /* we init with a-one-to one map */ |
| ! langmap_mapchar[i] = i; |
| } |
| |
| /* |
| --- 10153,10262 ---- |
| |
| #ifdef FEAT_LANGMAP |
| /* |
| ! * Any character has an equivalent 'langmap' character. This is used for |
| ! * keyboards that have a special language mode that sends characters above |
| ! * 128 (although other characters can be translated too). The "to" field is a |
| ! * Vim command character. This avoids having to switch the keyboard back to |
| ! * ASCII mode when leaving Insert mode. |
| ! * |
| ! * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim |
| ! * commands. |
| ! * When FEAT_MBYTE is defined langmap_mapga.ga_data is a sorted table of |
| ! * langmap_entry_T. This does the same as langmap_mapchar[] for characters >= |
| ! * 256. |
| ! */ |
| ! # ifdef FEAT_MBYTE |
| ! /* |
| ! * With multi-byte support use growarray for 'langmap' chars >= 256 |
| */ |
| + typedef struct |
| + { |
| + int from; |
| + int to; |
| + } langmap_entry_T; |
| + |
| + static garray_T langmap_mapga; |
| + static void langmap_set_entry __ARGS((int from, int to)); |
| + |
| + /* |
| + * Search for an entry in "langmap_mapga" for "from". If found set the "to" |
| + * field. If not found insert a new entry at the appropriate location. |
| + */ |
| + static void |
| + langmap_set_entry(from, to) |
| + int from; |
| + int to; |
| + { |
| + langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); |
| + int a = 0; |
| + int b = langmap_mapga.ga_len; |
| + |
| + /* Do a binary search for an existing entry. */ |
| + while (a != b) |
| + { |
| + int i = (a + b) / 2; |
| + int d = entries[i].from - from; |
| + |
| + if (d == 0) |
| + { |
| + entries[i].to = to; |
| + return; |
| + } |
| + if (d < 0) |
| + a = i + 1; |
| + else |
| + b = i; |
| + } |
| + |
| + if (ga_grow(&langmap_mapga, 1) != OK) |
| + return; /* out of memory */ |
| + |
| + /* insert new entry at position "a" */ |
| + entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a; |
| + mch_memmove(entries + 1, entries, |
| + (langmap_mapga.ga_len - a) * sizeof(langmap_entry_T)); |
| + ++langmap_mapga.ga_len; |
| + entries[0].from = from; |
| + entries[0].to = to; |
| + } |
| |
| /* |
| ! * Apply 'langmap' to multi-byte character "c" and return the result. |
| */ |
| + int |
| + langmap_adjust_mb(c) |
| + int c; |
| + { |
| + langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); |
| + int a = 0; |
| + int b = langmap_mapga.ga_len; |
| + |
| + while (a != b) |
| + { |
| + int i = (a + b) / 2; |
| + int d = entries[i].from - c; |
| + |
| + if (d == 0) |
| + return entries[i].to; /* found matching entry */ |
| + if (d < 0) |
| + a = i + 1; |
| + else |
| + b = i; |
| + } |
| + return c; /* no entry found, return "c" unmodified */ |
| + } |
| + # endif |
| |
| static void |
| langmap_init() |
| { |
| int i; |
| |
| ! for (i = 0; i < 256; i++) |
| ! langmap_mapchar[i] = i; /* we init with a one-to-one map */ |
| ! # ifdef FEAT_MBYTE |
| ! ga_init2(&langmap_mapga, sizeof(langmap_entry_T), 8); |
| ! # endif |
| } |
| |
| /* |
| |
| *** 10185,10191 **** |
| char_u *p2; |
| int from, to; |
| |
| ! langmap_init(); /* back to one-to-one map first */ |
| |
| for (p = p_langmap; p[0] != NUL; ) |
| { |
| --- 10270,10279 ---- |
| char_u *p2; |
| int from, to; |
| |
| ! #ifdef FEAT_MBYTE |
| ! ga_clear(&langmap_mapga); /* clear the previous map first */ |
| ! #endif |
| ! langmap_init(); /* back to one-to-one map */ |
| |
| for (p = p_langmap; p[0] != NUL; ) |
| { |
| |
| *** 10235,10241 **** |
| transchar(from)); |
| return; |
| } |
| ! langmap_mapchar[from & 255] = to; |
| |
| /* Advance to next pair */ |
| mb_ptr_adv(p); |
| --- 10323,10335 ---- |
| transchar(from)); |
| return; |
| } |
| ! |
| ! #ifdef FEAT_MBYTE |
| ! if (from >= 256) |
| ! langmap_set_entry(from, to); |
| ! else |
| ! #endif |
| ! langmap_mapchar[from & 255] = to; |
| |
| /* Advance to next pair */ |
| mb_ptr_adv(p); |
| |
| |
| |
| *** 44,49 **** |
| --- 44,50 ---- |
| void set_context_in_set_cmd __ARGS((expand_T *xp, char_u *arg, int opt_flags)); |
| int ExpandSettings __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file)); |
| int ExpandOldSetting __ARGS((int *num_file, char_u ***file)); |
| + int langmap_adjust_mb __ARGS((int c)); |
| int has_format_option __ARGS((int x)); |
| int shortmess __ARGS((int x)); |
| void vimrc_found __ARGS((char_u *fname, char_u *envname)); |
| |
| |
| |
| *** 594,602 **** |
| ++allow_keys; /* no mapping for xchar, but allow key codes */ |
| if (xchar == NUL) |
| xchar = plain_vgetc(); |
| - #ifdef FEAT_LANGMAP |
| LANGMAP_ADJUST(xchar, TRUE); |
| - #endif |
| --no_mapping; |
| --allow_keys; |
| #ifdef FEAT_CMDL_INFO |
| --- 594,600 ---- |
| |
| |
| |
| *** 678,679 **** |
| --- 678,681 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 109, |
| /**/ |
| |
| -- |
| hundred-and-one symptoms of being an internet addict: |
| 99. The hum of a cooling fan and the click of keys is comforting to you. |
| |
| /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ |
| /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ |
| \\\ download, build and distribute -- http://www.A-A-P.org /// |
| \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |