diff options
-rw-r--r-- | runtime/doc/options.txt | 3 | ||||
-rw-r--r-- | src/edit.c | 4 | ||||
-rw-r--r-- | src/macros.h | 26 | ||||
-rw-r--r-- | src/normal.c | 15 | ||||
-rw-r--r-- | src/option.c | 116 | ||||
-rw-r--r-- | src/proto/option.pro | 1 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/window.c | 2 |
8 files changed, 129 insertions, 40 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 786e83c72..bebaa03b5 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4175,9 +4175,6 @@ A jump table for the options with a short description can be found at |Q_op|. 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 diff --git a/src/edit.c b/src/edit.c index 24f149634..b998f8dfb 100644 --- a/src/edit.c +++ b/src/edit.c @@ -7703,9 +7703,7 @@ ins_reg() */ ++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 */ @@ -7714,9 +7712,7 @@ ins_reg() add_to_showcmd_c(literally); #endif regname = plain_vgetc(); -#ifdef FEAT_LANGMAP LANGMAP_ADJUST(regname, TRUE); -#endif } --no_mapping; diff --git a/src/macros.h b/src/macros.h index f22309959..afe3572bb 100644 --- a/src/macros.h +++ b/src/macros.h @@ -127,15 +127,31 @@ #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. + * 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. */ -# define LANGMAP_ADJUST(c, condition) do { \ - if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0 && (c) < 256) \ - c = langmap_mapchar[c]; \ +# 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 /* diff --git a/src/normal.c b/src/normal.c index 30678a426..324133047 100644 --- a/src/normal.c +++ b/src/normal.c @@ -651,10 +651,7 @@ normal_cmd(oap, toplevel) * Get the command character from the user. */ c = safe_vgetc(); - -#ifdef FEAT_LANGMAP LANGMAP_ADJUST(c, TRUE); -#endif #ifdef FEAT_VISUAL /* @@ -744,9 +741,7 @@ getcount: } ++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) { @@ -769,9 +764,7 @@ getcount: ++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 @@ -959,9 +952,7 @@ getcount: * "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 @@ -1062,10 +1053,8 @@ getcount: } #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) @@ -4630,9 +4619,7 @@ nv_zet(cap) ++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 @@ -4988,9 +4975,7 @@ dozet: ++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 diff --git a/src/option.c b/src/option.c index bd12b8bad..87497ea6a 100644 --- a/src/option.c +++ b/src/option.c @@ -10153,25 +10153,110 @@ wc_use_keyname(varp, wcp) #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). + * 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; +} /* - * 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. + * 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++) /* we init with a-one-to one map */ - langmap_mapchar[i] = 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,7 +10270,10 @@ langmap_set() char_u *p2; int from, to; - langmap_init(); /* back to one-to-one map first */ +#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,7 +10323,13 @@ langmap_set() transchar(from)); return; } - langmap_mapchar[from & 255] = to; + +#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); diff --git a/src/proto/option.pro b/src/proto/option.pro index bb50ef14a..39ee7be21 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -44,6 +44,7 @@ void set_imsearch_global __ARGS((void)); 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)); diff --git a/src/version.c b/src/version.c index 7a8378860..f5f53a5de 100644 --- a/src/version.c +++ b/src/version.c @@ -677,6 +677,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 109, +/**/ 108, /**/ 107, diff --git a/src/window.c b/src/window.c index b360f54e1..2c14e5053 100644 --- a/src/window.c +++ b/src/window.c @@ -594,9 +594,7 @@ wingotofile: ++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 |