diff options
-rw-r--r-- | runtime/doc/digraph.txt | 9 | ||||
-rw-r--r-- | runtime/doc/options.txt | 16 | ||||
-rw-r--r-- | runtime/doc/term.txt | 6 | ||||
-rw-r--r-- | runtime/filetype.vim | 4 | ||||
-rw-r--r-- | src/edit.c | 32 | ||||
-rw-r--r-- | src/ex_getln.c | 43 | ||||
-rw-r--r-- | src/getchar.c | 6 | ||||
-rw-r--r-- | src/globals.h | 2 | ||||
-rw-r--r-- | src/keymap.h | 10 | ||||
-rw-r--r-- | src/message.c | 2 | ||||
-rw-r--r-- | src/misc2.c | 50 | ||||
-rw-r--r-- | src/normal.c | 75 | ||||
-rw-r--r-- | src/os_mswin.c | 2 | ||||
-rw-r--r-- | src/os_unix.c | 25 | ||||
-rw-r--r-- | src/quickfix.c | 4 | ||||
-rw-r--r-- | src/regexp.c | 1296 | ||||
-rw-r--r-- | src/term.c | 238 | ||||
-rw-r--r-- | src/testdir/test24.in | bin | 975 -> 1156 bytes | |||
-rw-r--r-- | src/testdir/test24.ok | 5 | ||||
-rw-r--r-- | src/version.h | 4 | ||||
-rw-r--r-- | src/window.c | 4 |
21 files changed, 1199 insertions, 634 deletions
diff --git a/runtime/doc/digraph.txt b/runtime/doc/digraph.txt index ed4527175..201d6a0e5 100644 --- a/runtime/doc/digraph.txt +++ b/runtime/doc/digraph.txt @@ -1,4 +1,4 @@ -*digraph.txt* For Vim version 7.0aa. Last change: 2004 Oct 07 +*digraph.txt* For Vim version 7.0aa. Last change: 2005 Mar 06 VIM REFERENCE MANUAL by Bram Moolenaar @@ -161,8 +161,13 @@ These are the RFC1345 digraphs for the one-byte characters. See the output of ":digraphs" for the others. The characters above 255 are only available when Vim was compiled with the |+multi_byte| feature. +EURO + Exception: RFC1345 doesn't specify the euro sign. In Vim the digraph =e was -added for this. +added for this. Note the difference between latin1, where the digraph Cu is +used for the currency sign, and latin9 (iso-8859-15), where the digraph =e is +used for the euro sign, while both of them are the character 164, 0xa4. + *digraph-table* char digraph hex dec official name ~ ^@ NU 0x00 0 NULL (NUL) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index d0b5abf74..2c52c0475 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 7.0aa. Last change: 2005 Mar 03 +*options.txt* For Vim version 7.0aa. Last change: 2005 Mar 06 VIM REFERENCE MANUAL by Bram Moolenaar @@ -3972,6 +3972,10 @@ A jump table for the options with a short description can be found at |Q_op|. Number of pixel lines inserted between characters. Useful if the font uses the full character cell height, making lines touch each other. When non-zero there is room for underlining. + With some fonts there can be too much room between lines (to have + space for ascents and descents). Then it makes sense to set + 'linespace' to a negative value. This may cause display problems + though! *'lisp'* *'nolisp'* 'lisp' boolean (default off) @@ -4709,8 +4713,8 @@ A jump table for the options with a short description can be found at |Q_op|. 'printmbcharset' 'pmbcs' string (default "") global {not in Vi} - {only available when compiled with the |+printer| - and |+multi_byte| features} + {only available when compiled with the |+printer|, + |+postscript| and |+multi_byte| features} The CJK character set to be used for CJK output from |:hardcopy|. See |pmbcs-option|. @@ -4718,8 +4722,8 @@ A jump table for the options with a short description can be found at |Q_op|. 'printmbfont' 'pmbfn' string (default "") global {not in Vi} - {only available when compiled with the |+printer| - and |+multi_byte| features} + {only available when compiled with the |+printer|, + |+postscript| and |+multi_byte| features} List of font names to be used for CJK output from |:hardcopy|. See |pmbfn-option|. @@ -6344,7 +6348,7 @@ A jump table for the options with a short description can be found at |Q_op|. xterm2 Works like "xterm", but with the xterm reporting the mouse position while the mouse is dragged. This works much faster and more precise. Your xterm must at - least at patchlevel 88 / XFree 3.3.3 for this to + least at patchlevel 88 / XFree 3.3.3 for this to work. See below for how Vim detects this automatically. *netterm-mouse* diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index fba493c70..0ac9697c4 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -1,4 +1,4 @@ -*term.txt* For Vim version 7.0aa. Last change: 2005 Mar 04 +*term.txt* For Vim version 7.0aa. Last change: 2005 Mar 05 VIM REFERENCE MANUAL by Bram Moolenaar @@ -301,6 +301,10 @@ Note: Use the <> form if possible t_kd <Down> arrow down *t_kd* *'t_kd'* t_kr <Right> arrow right *t_kr* *'t_kr'* t_kl <Left> arrow left *t_kl* *'t_kl'* + <xUp> alternate arrow up *<xUp>* + <xDown> alternate arrow down *<xDown>* + <xRight> alternate arrow right *<xRight>* + <xLeft> alternate arrow left *<xLeft>* <S-Up> shift arrow up <S-Down> shift arrow down t_%i <S-Right> shift arrow right *t_%i* *'t_%i'* diff --git a/runtime/filetype.vim b/runtime/filetype.vim index bbbb6d2c1..768fd5ddd 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2005 Feb 18 +" Last Change: 2005 Mar 06 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -91,7 +91,7 @@ au BufNewFile,BufRead build.xml setf ant au BufNewFile,BufRead proftpd.conf* setf apachestyle " Apache config file -au BufNewFile,BufRead httpd.conf*,srm.conf*,access.conf*,.htaccess,apache.conf* setf apache +au BufNewFile,BufRead httpd.conf*,srm.conf*,access.conf*,.htaccess,apache.conf*,apache2.conf*,/etc/apache2/*.conf* setf apache " XA65 MOS6510 cross assembler au BufNewFile,BufRead *.a65 setf a65 diff --git a/src/edit.c b/src/edit.c index ae00c2aba..3a3e86596 100644 --- a/src/edit.c +++ b/src/edit.c @@ -710,9 +710,11 @@ edit(cmdchar, startln, count) switch (c) { case K_LEFT: c = K_RIGHT; break; + case K_XLEFT: c = K_XRIGHT; break; case K_S_LEFT: c = K_S_RIGHT; break; case K_C_LEFT: c = K_C_RIGHT; break; case K_RIGHT: c = K_LEFT; break; + case K_XRIGHT: c = K_XLEFT; break; case K_S_RIGHT: c = K_S_LEFT; break; case K_C_RIGHT: c = K_C_LEFT; break; } @@ -1105,7 +1107,11 @@ doESCkey: break; case K_LEFT: - ins_left(); + case K_XLEFT: + if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) + ins_s_left(); + else + ins_left(); break; case K_S_LEFT: @@ -1114,7 +1120,11 @@ doESCkey: break; case K_RIGHT: - ins_right(); + case K_XRIGHT: + if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) + ins_s_right(); + else + ins_right(); break; case K_S_RIGHT: @@ -1123,7 +1133,11 @@ doESCkey: break; case K_UP: - ins_up(FALSE); + case K_XUP: + if (mod_mask & MOD_MASK_SHIFT) + ins_pageup(); + else + ins_up(FALSE); break; case K_S_UP: @@ -1133,7 +1147,11 @@ doESCkey: break; case K_DOWN: - ins_down(FALSE); + case K_XDOWN: + if (mod_mask & MOD_MASK_SHIFT) + ins_pagedown(); + else + ins_down(FALSE); break; case K_S_DOWN: @@ -6193,12 +6211,14 @@ ins_ctrl_g() { /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */ case K_UP: + case K_XUP: case Ctrl_K: case 'k': ins_up(TRUE); break; /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */ case K_DOWN: + case K_XDOWN: case Ctrl_J: case 'j': ins_down(TRUE); break; @@ -6428,6 +6448,10 @@ ins_start_select(c) case K_KPAGEUP: case K_PAGEDOWN: case K_KPAGEDOWN: + case K_XLEFT: + case K_XRIGHT: + case K_XUP: + case K_XDOWN: # ifdef MACOS case K_LEFT: case K_RIGHT: diff --git a/src/ex_getln.c b/src/ex_getln.c index 4c9d17d78..4c6175b6f 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -320,9 +320,11 @@ getcmdline(firstc, count, indent) switch (c) { case K_RIGHT: c = K_LEFT; break; + case K_XRIGHT: c = K_XLEFT; break; case K_S_RIGHT: c = K_S_LEFT; break; case K_C_RIGHT: c = K_C_LEFT; break; case K_LEFT: c = K_RIGHT; break; + case K_XLEFT: c = K_XRIGHT; break; case K_S_LEFT: c = K_S_RIGHT; break; case K_C_LEFT: c = K_C_RIGHT; break; } @@ -354,10 +356,11 @@ getcmdline(firstc, count, indent) /* free old command line when finished moving around in the history * list */ if (lookfor != NULL - && c != K_S_DOWN && c != K_S_UP && c != K_DOWN && c != K_UP + && c != K_S_DOWN && c != K_S_UP + && c != K_DOWN && c != K_UP && c != K_XDOWN && c != K_XUP && c != K_PAGEDOWN && c != K_PAGEUP && c != K_KPAGEDOWN && c != K_KPAGEUP - && c != K_LEFT && c != K_RIGHT + && c != K_LEFT && c != K_RIGHT && c != K_XLEFT && c != K_XRIGHT && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N))) { vim_free(lookfor); @@ -375,9 +378,9 @@ getcmdline(firstc, count, indent) /* Special translations for 'wildmenu' */ if (did_wild_list && p_wmnu) { - if (c == K_LEFT) + if (c == K_LEFT || c == K_XLEFT) c = Ctrl_P; - else if (c == K_RIGHT) + else if (c == K_RIGHT || c == K_XRIGHT) c = Ctrl_N; } /* Hitting CR after "emenu Name.": complete submenu */ @@ -398,7 +401,8 @@ getcmdline(firstc, count, indent) (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE); did_wild_list = FALSE; #ifdef FEAT_WILDMENU - if (!p_wmnu || (c != K_UP && c != K_DOWN)) + if (!p_wmnu || (c != K_UP && c != K_DOWN + && c != K_XUP && c != K_XDOWN)) #endif xpc.xp_context = EXPAND_NOTHING; wim_index = 0; @@ -443,9 +447,10 @@ getcmdline(firstc, count, indent) if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu) { /* Hitting <Down> after "emenu Name.": complete submenu */ - if (ccline.cmdbuff[ccline.cmdpos - 1] == '.' && c == K_DOWN) + if (ccline.cmdbuff[ccline.cmdpos - 1] == '.' + && (c == K_DOWN || c == K_XDOWN)) c = p_wc; - else if (c == K_UP) + else if (c == K_UP || c == K_XUP) { /* Hitting <Up>: Remove one submenu name in front of the * cursor */ @@ -492,14 +497,15 @@ getcmdline(firstc, count, indent) upseg[4] = NUL; if (ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP - && c == K_DOWN + && (c == K_DOWN || c == K_XDOWN) && (ccline.cmdbuff[ccline.cmdpos - 2] != '.' || ccline.cmdbuff[ccline.cmdpos - 3] != '.')) { /* go down a directory */ c = p_wc; } - else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN) + else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0 + && (c == K_DOWN || c == K_XDOWN)) { /* If in a direct ancestor, strip off one ../ to go down */ int found = FALSE; @@ -527,7 +533,7 @@ getcmdline(firstc, count, indent) c = p_wc; } } - else if (c == K_UP) + else if (c == K_UP || c == K_XUP) { /* go up a directory */ int found = FALSE; @@ -1096,6 +1102,7 @@ getcmdline(firstc, count, indent) continue; /* don't do incremental search now */ case K_RIGHT: + case K_XRIGHT: case K_S_RIGHT: case K_C_RIGHT: do @@ -1114,7 +1121,8 @@ getcmdline(firstc, count, indent) #endif ++ccline.cmdpos; } - while ((c == K_S_RIGHT || c == K_C_RIGHT) + while ((c == K_S_RIGHT || c == K_C_RIGHT + || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))) && ccline.cmdbuff[ccline.cmdpos] != ' '); #ifdef FEAT_MBYTE if (has_mbyte) @@ -1123,6 +1131,7 @@ getcmdline(firstc, count, indent) goto cmdline_not_changed; case K_LEFT: + case K_XLEFT: case K_S_LEFT: case K_C_LEFT: do @@ -1137,7 +1146,8 @@ getcmdline(firstc, count, indent) #endif ccline.cmdspos -= cmdline_charsize(ccline.cmdpos); } - while ((c == K_S_LEFT || c == K_C_LEFT) + while ((c == K_S_LEFT || c == K_C_LEFT + || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))) && ccline.cmdbuff[ccline.cmdpos - 1] != ' '); #ifdef FEAT_MBYTE if (has_mbyte) @@ -1320,7 +1330,9 @@ getcmdline(firstc, count, indent) #ifdef FEAT_CMDHIST case K_UP: + case K_XUP: case K_DOWN: + case K_XDOWN: case K_S_UP: case K_S_DOWN: case K_PAGEUP: @@ -1344,8 +1356,8 @@ getcmdline(firstc, count, indent) for (;;) { /* one step backwards */ - if (c == K_UP || c == K_S_UP || c == Ctrl_P || - c == K_PAGEUP || c == K_KPAGEUP) + if (c == K_UP || c == K_XUP || c == K_S_UP || c == Ctrl_P + || c == K_PAGEUP || c == K_KPAGEUP) { if (hiscnt == hislen) /* first time */ hiscnt = hisidx[histype]; @@ -1381,7 +1393,8 @@ getcmdline(firstc, count, indent) hiscnt = i; break; } - if ((c != K_UP && c != K_DOWN) || hiscnt == i + if ((c != K_UP && c != K_DOWN && c != K_XUP && c != K_XDOWN) + || hiscnt == i || STRNCMP(history[histype][hiscnt].hisstr, lookfor, (size_t)j) == 0) break; diff --git a/src/getchar.c b/src/getchar.c index e93ce0529..c06b60076 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -4530,6 +4530,7 @@ check_map(keys, mode, exact) } #endif +#if defined(MSDOS) || defined(MSWIN) || defined(OS2) || defined(MACOS) /* * Default mappings for some often used keys. */ @@ -4609,6 +4610,7 @@ static struct initmap {(char_u *)"<Backspace> \"-d", VISUAL}, #endif +#if 0 /* Map extra keys to their normal equivalents. */ {(char_u *)"<xF1> <F1>", NORMAL+VISUAL+OP_PENDING}, {(char_u *)"<xF1> <F1>", INSERT+CMDLINE}, @@ -4630,7 +4632,9 @@ static struct initmap {(char_u *)"<xEND> <END>", INSERT+CMDLINE}, {(char_u *)"<xHOME> <HOME>", NORMAL+VISUAL+OP_PENDING}, {(char_u *)"<xHOME> <HOME>", INSERT+CMDLINE}, +#endif }; +#endif /* * Set up default mappings. @@ -4638,10 +4642,12 @@ static struct initmap void init_mappings() { +#if defined(MSDOS) || defined(MSWIN) || defined(OS2) || defined(MACOS) int i; for (i = 0; i < sizeof(initmappings) / sizeof(struct initmap); ++i) add_map(initmappings[i].arg, initmappings[i].mode); +#endif } /* diff --git a/src/globals.h b/src/globals.h index 445b453fc..8251f1831 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1412,9 +1412,11 @@ EXTERN char_u e_nbreadonly[] INIT(=N_("E744: NetBeans does not allow changes in #if defined(FEAT_EVAL) || defined(FEAT_SYN_HL) || defined(PROTO) EXTERN char_u e_intern2[] INIT(=N_("E685: Internal error: %s")); #endif +#if 0 #if defined(HAVE_SETJMP_H) || defined(HAVE_TRY_EXCEPT) || defined(__MINGW32__) EXTERN char_u e_complex[] INIT(=N_("E361: Crash intercepted; regexp too complex?")); #endif +#endif EXTERN char_u e_outofstack[] INIT(=N_("E363: pattern caused out-of-stack error")); EXTERN char_u e_emptybuf[] INIT(=N_("E749: empty buffer")); diff --git a/src/keymap.h b/src/keymap.h index 5babdf4af..e0e46b773 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -207,6 +207,10 @@ enum key_extra , KE_XF4 , KE_XEND /* extra (vt100) end key for xterm */ , KE_XHOME /* extra (vt100) home key for xterm */ + , KE_XUP /* extra vt100 cursor keys for xterm */ + , KE_XDOWN + , KE_XLEFT + , KE_XRIGHT , KE_LEFTMOUSE_NM /* non-mappable Left mouse button click */ , KE_LEFTRELEASE_NM /* non-mappable left mouse button release */ @@ -270,6 +274,12 @@ enum key_extra #define K_XF3 TERMCAP2KEY(KS_EXTRA, KE_XF3) #define K_XF4 TERMCAP2KEY(KS_EXTRA, KE_XF4) +/* extra set of cursor keys for vt100 compatible xterm */ +#define K_XUP TERMCAP2KEY(KS_EXTRA, KE_XUP) +#define K_XDOWN TERMCAP2KEY(KS_EXTRA, KE_XDOWN) +#define K_XLEFT TERMCAP2KEY(KS_EXTRA, KE_XLEFT) +#define K_XRIGHT TERMCAP2KEY(KS_EXTRA, KE_XRIGHT) + #define K_F1 TERMCAP2KEY('k', '1') /* function keys */ #define K_F2 TERMCAP2KEY('k', '2') #define K_F3 TERMCAP2KEY('k', '3') diff --git a/src/message.c b/src/message.c index f6494847f..9b0045d14 100644 --- a/src/message.c +++ b/src/message.c @@ -1953,6 +1953,7 @@ msg_puts_attr_len(str, maxlen, attr) case BS: case 'k': case K_UP: + case K_XUP: if (!more_back_used) { msg_moremsg(TRUE); @@ -1965,6 +1966,7 @@ msg_puts_attr_len(str, maxlen, attr) case NL: case 'j': case K_DOWN: + case K_XDOWN: lines_left = 1; break; case ':': /* start new command line */ diff --git a/src/misc2.c b/src/misc2.c index 9b21168d8..d4d975dda 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1784,6 +1784,10 @@ static struct key_name_entry {K_DOWN, (char_u *)"Down"}, {K_LEFT, (char_u *)"Left"}, {K_RIGHT, (char_u *)"Right"}, + {K_XUP, (char_u *)"xUp"}, + {K_XDOWN, (char_u *)"xDown"}, + {K_XLEFT, (char_u *)"xLeft"}, + {K_XRIGHT, (char_u *)"xRight"}, {K_F1, (char_u *)"F1"}, {K_F2, (char_u *)"F2"}, @@ -1957,20 +1961,6 @@ name_to_mod_mask(c) return 0; } -#if 0 /* not used */ -/* - * Decide whether the given key code (K_*) is a shifted special - * key (by looking at mod_mask). If it is, then return the appropriate shifted - * key code, otherwise just return the character as is. - */ - int -check_shifted_spec_key(c) - int c; -{ - return simplify_key(c, &mod_mask); -} -#endif - /* * Check if if there is a special key code for "key" that includes the * modifiers specified. @@ -2008,6 +1998,35 @@ simplify_key(key, modifiers) } /* + * Change <xHome> to <Home>, <xUp> to <Up>, etc. + * "kp" must point to an array that holds the two characters that represent a + * special key. + */ + int +handle_x_keys(key) + int key; +{ + switch (key) + { + case K_XUP: return K_UP; + case K_XDOWN: return K_DOWN; + case K_XLEFT: return K_LEFT; + case K_XRIGHT: return K_RIGHT; + case K_XHOME: return K_HOME; + case K_XEND: return K_END; + case K_XF1: return K_F1; + case K_XF2: return K_F2; + case K_XF3: return K_F3; + case K_XF4: return K_F4; + case K_S_XF1: return K_S_F1; + case K_S_XF2: return K_S_F2; + case K_S_XF3: return K_S_F3; + case K_S_XF4: return K_S_F4; + } + return key; +} + +/* * Return a string which contains the name of the given key when the given * modifiers are down. */ @@ -2246,7 +2265,10 @@ find_special_key(srcp, modp, keycode) if (modifiers != 0 && last_dash[2] == '>') key = last_dash[1]; else + { key = get_special_key_code(last_dash + 1); + key = handle_x_keys(key); + } /* * get_special_key_code() may return NUL for invalid diff --git a/src/normal.c b/src/normal.c index 9bf2e66b7..df914b5f3 100644 --- a/src/normal.c +++ b/src/normal.c @@ -381,13 +381,17 @@ static const struct nv_cmd {K_KINS, nv_edit, 0, 0}, {K_BS, nv_ctrlh, 0, 0}, {K_UP, nv_up, NV_SSS|NV_STS, FALSE}, + {K_XUP, nv_up, NV_SSS|NV_STS, FALSE}, {K_S_UP, nv_page, NV_SS, BACKWARD}, {K_DOWN, nv_down, NV_SSS|NV_STS, FALSE}, + {K_XDOWN, nv_down, NV_SSS|NV_STS, FALSE}, {K_S_DOWN, nv_page, NV_SS, FORWARD}, {K_LEFT, nv_left, NV_SSS|NV_STS|NV_RL, 0}, + {K_XLEFT, nv_left, NV_SSS|NV_STS|NV_RL, 0}, {K_S_LEFT, nv_bck_word, NV_SS|NV_RL, 0}, {K_C_LEFT, nv_bck_word, NV_SSS|NV_RL|NV_STS, 1}, {K_RIGHT, nv_right, NV_SSS|NV_STS|NV_RL, 0}, + {K_XRIGHT, nv_right, NV_SSS|NV_STS|NV_RL, 0}, {K_S_RIGHT, nv_wordcmd, NV_SS|NV_RL, FALSE}, {K_C_RIGHT, nv_wordcmd, NV_SSS|NV_RL|NV_STS, TRUE}, {K_PAGEUP, nv_page, NV_SSS|NV_STS, BACKWARD}, @@ -832,10 +836,12 @@ getcount: { case 'l': ca.cmdchar = 'h'; break; case K_RIGHT: ca.cmdchar = K_LEFT; break; + case K_XRIGHT: ca.cmdchar = K_XLEFT; break; case K_S_RIGHT: ca.cmdchar = K_S_LEFT; break; case K_C_RIGHT: ca.cmdchar = K_C_LEFT; break; case 'h': ca.cmdchar = 'l'; break; case K_LEFT: ca.cmdchar = K_RIGHT; break; + case K_XLEFT: ca.cmdchar = K_XRIGHT; break; case K_S_LEFT: ca.cmdchar = K_S_RIGHT; break; case K_C_LEFT: ca.cmdchar = K_C_RIGHT; break; case '>': ca.cmdchar = '<'; break; @@ -4316,7 +4322,9 @@ nv_zet(cap) else if (nchar == 'l' || nchar == 'h' || nchar == K_LEFT - || nchar == K_RIGHT) + || nchar == K_XLEFT + || nchar == K_RIGHT + || nchar == K_XRIGHT) { cap->count1 = n ? n * cap->count1 : cap->count1; goto dozet; @@ -4423,6 +4431,7 @@ dozet: /* "zh" - scroll screen to the right */ case 'h': case K_LEFT: + case K_XLEFT: if (!curwin->w_p_wrap) { if ((colnr_T)cap->count1 > curwin->w_leftcol) @@ -4440,6 +4449,7 @@ dozet: /* "zl" - scroll screen to the left */ case 'l': case K_RIGHT: + case K_XRIGHT: if (!curwin->w_p_wrap) { /* scroll the window left */ @@ -5294,6 +5304,15 @@ nv_right(cap) # define PAST_LINE 0 #endif + if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) + { + /* <C-Right> and <S-Right> move a word or WORD right */ + if (mod_mask & MOD_MASK_CTRL) + cap->arg = TRUE; + nv_wordcmd(cap); + return; + } + cap->oap->motion_type = MCHAR; cap->oap->inclusive = FALSE; #ifdef FEAT_VISUAL @@ -5323,7 +5342,7 @@ nv_right(cap) && vim_strchr(p_ww, 's') != NULL) || (cap->cmdchar == 'l' && vim_strchr(p_ww, 'l') != NULL) - || (cap->cmdchar == K_RIGHT + || ((cap->cmdchar == K_RIGHT || cap->cmdchar == K_XRIGHT) && vim_strchr(p_ww, '>') != NULL)) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { @@ -5399,6 +5418,15 @@ nv_left(cap) { long n; + if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) + { + /* <C-Left> and <S-Left> move a word or WORD left */ + if (mod_mask & MOD_MASK_CTRL) + cap->arg = 1; + nv_bck_word(cap); + return; + } + cap->oap->motion_type = MCHAR; cap->oap->inclusive = FALSE; for (n = cap->count1; n > 0; --n) @@ -5414,7 +5442,7 @@ nv_left(cap) && vim_strchr(p_ww, 'b') != NULL) || (cap->cmdchar == 'h' && vim_strchr(p_ww, 'h') != NULL) - || (cap->cmdchar == K_LEFT + || ((cap->cmdchar == K_LEFT || cap->cmdchar == K_XLEFT) && vim_strchr(p_ww, '<') != NULL)) && curwin->w_cursor.lnum > 1) { @@ -5456,11 +5484,20 @@ nv_left(cap) nv_up(cap) cmdarg_T *cap; { - cap->oap->motion_type = MLINE; - if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == FAIL) - clearopbeep(cap->oap); - else if (cap->arg) - beginline(BL_WHITE | BL_FIX); + if (mod_mask & MOD_MASK_SHIFT) + { + /* <S-Up> is page up */ + cap->arg = BACKWARD; + nv_page(cap); + } + else + { + cap->oap->motion_type = MLINE; + if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == FAIL) + clearopbeep(cap->oap); + else if (cap->arg) + beginline(BL_WHITE | BL_FIX); + } } /* @@ -5471,6 +5508,13 @@ nv_up(cap) nv_down(cap) cmdarg_T *cap; { + if (mod_mask & MOD_MASK_SHIFT) + { + /* <S-Down> is page down */ + cap->arg = FORWARD; + nv_page(cap); + } + else #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) /* In a quickfix window a <CR> jumps to the error under the cursor. */ if (bt_quickfix(curbuf) && cap->cmdchar == CAR) @@ -5553,8 +5597,9 @@ nv_gotofile(cap) nv_end(cap) cmdarg_T *cap; { - if (cap->arg) /* CTRL-END = goto last line */ + if (cap->arg || (mod_mask & MOD_MASK_CTRL)) /* CTRL-END = goto last line */ { + cap->arg = TRUE; nv_goto(cap); cap->count1 = 1; /* to end of current line */ } @@ -7205,6 +7250,7 @@ nv_g_cmd(cap) */ case 'j': case K_DOWN: + case K_XDOWN: /* with 'nowrap' it works just like the normal "j" command; also when * in a closed fold */ if (!curwin->w_p_wrap @@ -7224,6 +7270,7 @@ nv_g_cmd(cap) case 'k': case K_UP: + case K_XUP: /* with 'nowrap' it works just like the normal "k" command; also when * in a closed fold */ if (!curwin->w_p_wrap @@ -7761,8 +7808,14 @@ nv_lineop(cap) nv_home(cap) cmdarg_T *cap; { - cap->count0 = 1; - nv_pipe(cap); + /* CTRL-HOME is like "gg" */ + if (mod_mask & MOD_MASK_CTRL) + nv_goto(cap); + else + { + cap->count0 = 1; + nv_pipe(cap); + } } /* diff --git a/src/os_mswin.c b/src/os_mswin.c index 5e96da8af..a5e10be49 100644 --- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -2564,9 +2564,11 @@ Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) switch (data->dwData) { case COPYDATA_ENCODING: +# ifdef FEAT_MBYTE /* Remember the encoding that the client uses. */ vim_free(client_enc); client_enc = enc_canonize((char_u *)data->lpData); +# endif return 1; case COPYDATA_KEYS: diff --git a/src/os_unix.c b/src/os_unix.c index c64a39e02..5df0d35f2 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -610,7 +610,13 @@ mch_delay(msec, ignoreinput) WaitForChar(msec); } -#if defined(HAVE_GETRLIMIT) \ +#if 0 /* disabled, no longer needed now that regmatch() is not recursive */ +# if defined(HAVE_GETRLIMIT) +# define HAVE_STACK_LIMIT +# endif +#endif + +#if defined(HAVE_STACK_LIMIT) \ || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK)) # define HAVE_CHECK_STACK_GROWTH /* @@ -638,7 +644,7 @@ check_stack_growth(p) } #endif -#if defined(HAVE_GETRLIMIT) || defined(PROTO) +#if defined(HAVE_STACK_LIMIT) || defined(PROTO) static char *stack_limit = NULL; #if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H) @@ -951,7 +957,7 @@ deathtrap SIGDEFARG(sigarg) set_vim_var_nr(VV_DYING, (long)entered); #endif -#ifdef HAVE_GETRLIMIT +#ifdef HAVE_STACK_LIMIT /* Since we are now using the signal stack, need to reset the stack * limit. Otherwise using a regexp will fail. */ get_stack_limit(); @@ -2683,12 +2689,10 @@ mch_early_init() { #ifdef HAVE_CHECK_STACK_GROWTH int i; -#endif -#ifdef HAVE_CHECK_STACK_GROWTH check_stack_growth((char *)&i); -# ifdef HAVE_GETRLIMIT +# ifdef HAVE_STACK_LIMIT get_stack_limit(); # endif @@ -3092,7 +3096,8 @@ check_mouse_termcode() ) { set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME) - ? IF_EB("\233M", CSI_STR "M") : IF_EB("\033[M", ESC_STR "[M"))); + ? IF_EB("\233M", CSI_STR "M") + : IF_EB("\033[M", ESC_STR "[M"))); if (*p_mouse != NUL) { /* force mouse off and maybe on to send possibly new mouse @@ -3128,7 +3133,7 @@ check_mouse_termcode() # endif # ifdef FEAT_MOUSE_NET - /* There is no conflict, but one may type ESC } from Insert mode. Don't + /* There is no conflict, but one may type "ESC }" from Insert mode. Don't * define it in the GUI or when using an xterm. */ if (!use_xterm_mouse() # ifdef FEAT_GUI @@ -3148,8 +3153,8 @@ check_mouse_termcode() && !gui.in_use # endif ) - set_mouse_termcode(KS_DEC_MOUSE, - (char_u *)IF_EB("\033[", ESC_STR "[")); + set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME) + ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "["))); else del_mouse_termcode(KS_DEC_MOUSE); # endif diff --git a/src/quickfix.c b/src/quickfix.c index 8d76e2861..d9ce186cf 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -2418,6 +2418,7 @@ ex_vimgrep(eap) else { found_match = FALSE; +#if 0 #ifdef HAVE_SETJMP_H /* * Matching with a regexp may cause a very deep recursive call of @@ -2437,6 +2438,7 @@ ex_vimgrep(eap) goto jumpend; } #endif +#endif /* Try for a match in all lines of the buffer. */ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) { @@ -2475,10 +2477,12 @@ ex_vimgrep(eap) if (got_int) break; } +#if 0 #ifdef HAVE_SETJMP_H jumpend: mch_endjmp(); #endif +#endif if (using_dummy) { diff --git a/src/regexp.c b/src/regexp.c index 36f5bb456..79d3e2a57 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -2962,8 +2962,6 @@ static int need_clear_zsubexpr = FALSE; /* extmatch subexpressions * still need to be cleared */ #endif -static int out_of_stack; /* TRUE when ran out of stack space */ - /* * Structure used to save the current input state, when it needs to be * restored after trying a match. Used by reg_save() and reg_restore(). @@ -3013,7 +3011,7 @@ static void save_se_one __ARGS((save_se_T *savep, char_u **pp)); *(pp) = (savep)->se_u.ptr; } static int re_num_cmp __ARGS((long_u val, char_u *scan)); -static int regmatch __ARGS((char_u *prog, regsave_T *startp)); +static int regmatch __ARGS((char_u *prog)); static int regrepeat __ARGS((char_u *p, long maxcount)); #ifdef DEBUG @@ -3186,41 +3184,20 @@ vim_regexec_multi(rmp, win, buf, lnum, col) return r; } -#if 0 /* this does not appear to work... */ -# ifdef __MINGW32__ -# define MINGW_TRY +#if 0 /* disabled, no longer needed now that regmatch() is not recursive */ +# ifdef HAVE_SETJMP_H +# define USE_SETJMP +# endif +# ifdef HAVE_TRY_EXCEPT +# define USE_TRY_EXCEPT # endif -#endif - -#ifdef MINGW_TRY -/* - * Special assembly code for MingW to simulate __try / __except. - * Does not work with the optimizer! - */ -# include <excpt.h> - -static void *ESP_save; /* used as _ESP below */ -static void *EBP_save; /* used as _EBP below */ - -__attribute__ ((cdecl)) - EXCEPTION_DISPOSITION - _except_regexec_handler( - struct _EXCEPTION_RECORD *ExceptionRecord, - void *EstablisherFrame, - struct _CONTEXT *ContextRecord, - void *DispatcherContext) -{ - __asm__ __volatile__ ( - "jmp regexec_reentry"); - return 0; /* Function does not return */ -} #endif /* * Match a regexp against a string ("line" points to the string) or multiple * lines ("line" is NULL, use reg_getline()). */ -#ifdef HAVE_SETJMP_H +#ifdef USE_SETJMP static long vim_regexec_both(line_arg, col_arg) char_u *line_arg; @@ -3235,7 +3212,7 @@ vim_regexec_both(line, col) regprog_T *prog; char_u *s; long retval; -#ifdef HAVE_SETJMP_H +#ifdef USE_SETJMP char_u *line; colnr_T col; int did_mch_startjmp = FALSE; @@ -3243,7 +3220,7 @@ vim_regexec_both(line, col) reg_tofree = NULL; -#ifdef HAVE_SETJMP_H +#ifdef USE_SETJMP /* Trick to avoid "might be clobbered by `longjmp'" warning from gcc. */ line = line_arg; col = col_arg; @@ -3335,23 +3312,12 @@ vim_regexec_both(line, col) goto theend; } -#ifdef MINGW_TRY - /* Ugly assembly code that is necessary to simulate "__try". */ - __asm__ __volatile__ ( - "movl %esp, _ESP_save" "\n\t" - "movl %ebp, _EBP_save"); - - __asm__ __volatile__ ( - "pushl $__except_regexec_handler" "\n\t" - "pushl %fs:0" "\n\t" - "mov %esp, %fs:0"); -#endif -#ifdef HAVE_TRY_EXCEPT +#ifdef USE_TRY_EXCEPT __try { #endif -#ifdef HAVE_SETJMP_H +#ifdef USE_SETJMP /* * Matching with a regexp may cause a very deep recursive call of * regmatch(). Vim will crash when running out of stack space. Catch @@ -3378,7 +3344,6 @@ vim_regexec_both(line, col) regline = line; reglnum = 0; - out_of_stack = FALSE; /* Simplest case: Anchored match need be tried only once. */ if (prog->reganch) @@ -3406,7 +3371,7 @@ vim_regexec_both(line, col) else { /* Messy cases: unanchored match. */ - while (!got_int && !out_of_stack) + while (!got_int) { if (prog->regstart != NUL) { @@ -3449,15 +3414,12 @@ vim_regexec_both(line, col) } } - if (out_of_stack) - EMSG(_(e_outofstack)); - -#ifdef HAVE_SETJMP_H +#ifdef USE_SETJMP inner_end: if (did_mch_startjmp) mch_endjmp(); #endif -#ifdef HAVE_TRY_EXCEPT +#ifdef USE_TRY_EXCEPT } __except(EXCEPTION_EXECUTE_HANDLER) { @@ -3471,22 +3433,6 @@ inner_end: retval = 0L; } #endif -#ifdef MINGW_TRY - __asm__ __volatile__ ( - "jmp regexec_pop" "\n" - "regexec_reentry:" "\n\t" - "movl _ESP_save, %esp" "\n\t" - "movl _EBP_save, %ebp"); - - EMSG(_(e_complex)); - retval = 0L; - - __asm__ __volatile__ ( - "regexec_pop:" "\n\t" - "mov (%esp), %eax" "\n\t" - "mov %eax, %fs:0" "\n\t" - "add $8, %esp"); -#endif theend: /* Didn't find a match. */ @@ -3559,7 +3505,7 @@ regtry(prog, col) need_clear_zsubexpr = TRUE; #endif - if (regmatch(prog->program + 1, NULL)) + if (regmatch(prog->program + 1)) { cleanup_subexpr(); if (REG_MULTI) @@ -3649,15 +3595,75 @@ reg_prev_class() static long bl_minval; static long bl_maxval; +/* Values for rs_state. */ +typedef enum regstate_E +{ + RS_NOPEN = 0 /* NOPEN and NCLOSE */ + , RS_MOPEN /* MOPEN + [0-9] */ + , RS_MCLOSE /* MCLOSE + [0-9] */ +#ifdef FEAT_SYN_HL + , RS_ZOPEN /* ZOPEN + [0-9] */ + , RS_ZCLOSE /* ZCLOSE + [0-9] */ +#endif + , RS_BRANCH /* BRANCH */ + , RS_BRCPLX_MORE /* BRACE_COMPLEX and trying one more match */ + , RS_BRCPLX_LONG /* BRACE_COMPLEX and trying longest match */ + , RS_BRCPLX_SHORT /* BRACE_COMPLEX and trying shortest match */ + , RS_NOMATCH /* NOMATCH */ + , RS_BEHIND1 /* BEHIND / NOBEHIND matching rest */ + , RS_BEHIND2 /* BEHIND / NOBEHIND matching behind part */ + , RS_STAR_LONG /* STAR/PLUS/BRACE_SIMPLE longest match */ + , RS_STAR_SHORT /* STAR/PLUS/BRACE_SIMPLE shortest match */ +} regstate_T; + +/* + * When there are alternatives a regstate_T is put on the regstack to remember + * what we are doing. + * Before it may be another type of item, depending on rs_state, to remember + * more things. + */ +typedef struct regitem_S +{ + regstate_T rs_state; /* what we are doing, on of RS_ below */ + char_u *rs_scan; /* current node in program */ + long rs_startp; /* start position for BACK (offset) */ + union + { + save_se_T sesave; + regsave_T regsave; + } rs_un; /* room for saving reginput */ + short rs_no; /* submatch nr */ +} regitem_T; + +static regitem_T *regstack_push __ARGS((garray_T *regstack, regstate_T state, char_u *scan, long startp)); +static void regstack_pop __ARGS((garray_T *regstack, char_u **scan, long *startp)); + +/* used for BEHIND and NOBEHIND matching */ +typedef struct regbehind_S +{ + regsave_T save_after; + regsave_T save_behind; +} regbehind_T; + +/* used for STAR, PLUS and BRACE_SIMPLE matching */ +typedef struct regstar_S +{ + int nextb; /* next byte */ + int nextb_ic; /* next byte reverse case */ + long count; + long minval; + long maxval; +} regstar_T; + /* * regmatch - main matching routine * - * Conceptually the strategy is simple: Check to see whether the current - * node matches, call self recursively to see whether the rest matches, - * and then act accordingly. In practice we make some effort to avoid - * recursion, in particular by going through "ordinary" nodes (that don't - * need to know whether the rest of the match failed) by a loop instead of - * by recursion. + * Conceptually the strategy is simple: Check to see whether the current node + * matches, push an item onto the regstack and loop to see whether the rest + * matches, and then act accordingly. In practice we make some effort to + * avoid using the regstack, in particular by going through "ordinary" nodes + * (that don't need to know whether the rest of the match failed) by a nested + * loop. * * Returns TRUE when there is a match. Leaves reginput and reglnum just after * the last matched character. @@ -3665,24 +3671,36 @@ static long bl_maxval; * undefined state! */ static int -regmatch(scan, startp) +regmatch(scan) char_u *scan; /* Current node. */ - regsave_T *startp; /* start position for BACK */ { - char_u *next; /* Next node. */ - int op; - int c; - -#ifdef HAVE_GETRLIMIT - /* Check if we are running out of stack space. Could be caused by - * recursively calling ourselves. */ - if (out_of_stack || mch_stackcheck((char *)&op) == FAIL) - { - out_of_stack = TRUE; - return FALSE; - } -#endif - + char_u *next; /* Next node. */ + int op; + int c; + garray_T regstack; + regitem_T *rp; + int no; + int status; /* one of the RA_ values: */ +#define RA_FAIL 1 /* something failed, abort */ +#define RA_CONT 2 /* continue in inner loop */ +#define RA_BREAK 3 /* break inner loop */ +#define RA_MATCH 4 /* successful match */ +#define RA_NOMATCH 5 /* didn't match */ + long startp = 0; /* start position for BACK, offset to + regstack.ga_data */ +#define STARTP2REGS(startp) (regsave_T *)(((char *)regstack.ga_data) + startp) +#define REGS2STARTP(p) (long)((char *)p - (char *)regstack.ga_data) + + /* Init the regstack empty. Use an item size of 1 byte, since we push + * different things onto it. Use a large grow size to avoid reallocating + * it too often. */ + ga_init2(®stack, 1, 10000); + + /* + * Repeat until the stack is empty. + */ + for (;;) + { /* Some patterns my cause a long time to match, even though they are not * illegal. E.g., "\([a-z]\+\)\+Q". Allow breaking them with CTRL-C. */ fast_breakcheck(); @@ -3694,10 +3712,20 @@ regmatch(scan, startp) mch_errmsg("(\n"); } #endif - while (scan != NULL) + + /* + * Repeat for items that can be matched sequential, without using the + * regstack. + */ + for (;;) { - if (got_int || out_of_stack) - return FALSE; + if (got_int || scan == NULL) + { + status = RA_FAIL; + break; + } + status = RA_CONT; + #ifdef DEBUG if (regnarrate) { @@ -3735,7 +3763,7 @@ regmatch(scan, startp) else { if (WITH_NL(op)) - op -= ADD_NL; + op -= ADD_NL; #ifdef FEAT_MBYTE if (has_mbyte) c = (*mb_ptr2char)(reginput); @@ -3746,12 +3774,12 @@ regmatch(scan, startp) { case BOL: if (reginput != regline) - return FALSE; + status = RA_NOMATCH; break; case EOL: if (c != NUL) - return FALSE; + status = RA_NOMATCH; break; case RE_BOF: @@ -3760,12 +3788,12 @@ regmatch(scan, startp) * line of the file. */ if (reglnum != 0 || reginput != regline || (REG_MULTI && reg_getline((linenr_T)-1) != NULL)) - return FALSE; + status = RA_NOMATCH; break; case RE_EOF: if (reglnum != reg_maxline || c != NUL) - return FALSE; + status = RA_NOMATCH; break; case CURSOR: @@ -3774,237 +3802,262 @@ regmatch(scan, startp) if (reg_win == NULL || (reglnum + reg_firstlnum != reg_win->w_cursor.lnum) || ((colnr_T)(reginput - regline) != reg_win->w_cursor.col)) - return FALSE; + status = RA_NOMATCH; break; case RE_LNUM: if (!REG_MULTI || !re_num_cmp((long_u)(reglnum + reg_firstlnum), scan)) - return FALSE; + status = RA_NOMATCH; break; case RE_COL: if (!re_num_cmp((long_u)(reginput - regline) + 1, scan)) - return FALSE; + status = RA_NOMATCH; break; case RE_VCOL: if (!re_num_cmp((long_u)win_linetabsize( reg_win == NULL ? curwin : reg_win, regline, (colnr_T)(reginput - regline)) + 1, scan)) - return FALSE; + status = RA_NOMATCH; break; case BOW: /* \<word; reginput points to w */ if (c == NUL) /* Can't match at end of line */ - return FALSE; + status = RA_NOMATCH; #ifdef FEAT_MBYTE - if (has_mbyte) + else if (has_mbyte) { int this_class; /* Get class of current and previous char (if it exists). */ this_class = mb_get_class(reginput); if (this_class <= 1) - return FALSE; /* not on a word at all */ - if (reg_prev_class() == this_class) - return FALSE; /* previous char is in same word */ + status = RA_NOMATCH; /* not on a word at all */ + else if (reg_prev_class() == this_class) + status = RA_NOMATCH; /* previous char is in same word */ } #endif else { if (!vim_iswordc(c) || (reginput > regline && vim_iswordc(reginput[-1]))) - return FALSE; + status = RA_NOMATCH; } break; case EOW: /* word\>; reginput points after d */ if (reginput == regline) /* Can't match at start of line */ - return FALSE; + status = RA_NOMATCH; #ifdef FEAT_MBYTE - if (has_mbyte) + else if (has_mbyte) { int this_class, prev_class; /* Get class of current and previous char (if it exists). */ this_class = mb_get_class(reginput); prev_class = reg_prev_class(); - if (this_class == prev_class) - return FALSE; - if (prev_class == 0 || prev_class == 1) - return FALSE; + if (this_class == prev_class + || prev_class == 0 || prev_class == 1) + status = RA_NOMATCH; } - else #endif + else { - if (!vim_iswordc(reginput[-1])) - return FALSE; - if (reginput[0] != NUL && vim_iswordc(c)) - return FALSE; + if (!vim_iswordc(reginput[-1]) + || (reginput[0] != NUL && vim_iswordc(c))) + status = RA_NOMATCH; } break; /* Matched with EOW */ case ANY: if (c == NUL) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case IDENT: if (!vim_isIDc(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case SIDENT: if (VIM_ISDIGIT(*reginput) || !vim_isIDc(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case KWORD: if (!vim_iswordp(reginput)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case SKWORD: if (VIM_ISDIGIT(*reginput) || !vim_iswordp(reginput)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case FNAME: if (!vim_isfilec(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case SFNAME: if (VIM_ISDIGIT(*reginput) || !vim_isfilec(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case PRINT: if (ptr2cells(reginput) != 1) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case SPRINT: if (VIM_ISDIGIT(*reginput) || ptr2cells(reginput) != 1) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case WHITE: if (!vim_iswhite(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NWHITE: if (c == NUL || vim_iswhite(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case DIGIT: if (!ri_digit(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NDIGIT: if (c == NUL || ri_digit(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case HEX: if (!ri_hex(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NHEX: if (c == NUL || ri_hex(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case OCTAL: if (!ri_octal(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NOCTAL: if (c == NUL || ri_octal(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case WORD: if (!ri_word(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NWORD: if (c == NUL || ri_word(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case HEAD: if (!ri_head(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NHEAD: if (c == NUL || ri_head(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case ALPHA: if (!ri_alpha(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NALPHA: if (c == NUL || ri_alpha(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case LOWER: if (!ri_lower(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NLOWER: if (c == NUL || ri_lower(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case UPPER: if (!ri_upper(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case NUPPER: if (c == NUL || ri_upper(c)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; case EXACTLY: @@ -4020,8 +4073,8 @@ regmatch(scan, startp) !enc_utf8 && #endif TOLOWER_LOC(*opnd) != TOLOWER_LOC(*reginput)))) - return FALSE; - if (*opnd == NUL) + status = RA_NOMATCH; + else if (*opnd == NUL) { /* match empty string always works; happens when "~" is * empty. */ @@ -4037,20 +4090,21 @@ regmatch(scan, startp) len = (int)STRLEN(opnd); /* Need to match first byte again for multi-byte. */ if (cstrncmp(opnd, reginput, &len) != 0) - return FALSE; + status = RA_NOMATCH; #ifdef FEAT_MBYTE /* Check for following composing character. */ - if (enc_utf8 && UTF_COMPOSINGLIKE(reginput, reginput + len)) + else if (enc_utf8 + && UTF_COMPOSINGLIKE(reginput, reginput + len)) { /* raaron: This code makes a composing character get * ignored, which is the correct behavior (sometimes) * for voweled Hebrew texts. */ if (!ireg_icombine) - return FALSE; + status = RA_NOMATCH; } - else #endif - reginput += len; + else + reginput += len; } } break; @@ -4058,10 +4112,11 @@ regmatch(scan, startp) case ANYOF: case ANYBUT: if (c == NUL) - return FALSE; - if ((cstrchr(OPERAND(scan), c) == NULL) == (op == ANYOF)) - return FALSE; - ADVANCE_REGINPUT(); + status = RA_NOMATCH; + else if ((cstrchr(OPERAND(scan), c) == NULL) == (op == ANYOF)) + status = RA_NOMATCH; + else + ADVANCE_REGINPUT(); break; #ifdef FEAT_MBYTE @@ -4075,14 +4130,20 @@ regmatch(scan, startp) /* Safety check (just in case 'encoding' was changed since * compiling the program). */ if ((len = (*mb_ptr2len_check)(opnd)) < 2) - return FALSE; + { + status = RA_NOMATCH; + break; + } for (i = 0; i < len; ++i) if (opnd[i] != reginput[i]) - return FALSE; + { + status = RA_NOMATCH; + break; + } reginput += len; } else - return FALSE; + status = RA_NOMATCH; break; #endif @@ -4092,8 +4153,8 @@ regmatch(scan, startp) case BACK: /* When we run into BACK without matching something non-empty, we * fail. */ - if (startp != NULL && reg_save_equal(startp)) - return FALSE; + if (startp != 0 && reg_save_equal(STARTP2REGS(startp))) + status = RA_NOMATCH; break; case BACKP: @@ -4110,27 +4171,27 @@ regmatch(scan, startp) case MOPEN + 8: case MOPEN + 9: { - int no; - save_se_T save; - no = op - MOPEN; cleanup_subexpr(); - save_se(&save, ®_startpos[no], ®_startp[no]); - - if (regmatch(next, startp)) - return TRUE; - - restore_se(&save, ®_startpos[no], ®_startp[no]); - return FALSE; + rp = regstack_push(®stack, RS_MOPEN, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + { + rp->rs_no = no; + save_se(&rp->rs_un.sesave, ®_startpos[no], + ®_startp[no]); + /* We simply continue and handle the result when done. */ + } } - /* break; Not Reached */ + break; case NOPEN: /* \%( */ case NCLOSE: /* \) after \%( */ - if (regmatch(next, startp)) - return TRUE; - return FALSE; - /* break; Not Reached */ + if (regstack_push(®stack, RS_NOPEN, scan, startp) == NULL) + status = RA_FAIL; + /* We simply continue and handle the result when done. */ + break; #ifdef FEAT_SYN_HL case ZOPEN + 1: @@ -4143,20 +4204,20 @@ regmatch(scan, startp) case ZOPEN + 8: case ZOPEN + 9: { - int no; - save_se_T save; - no = op - ZOPEN; cleanup_zsubexpr(); - save_se(&save, ®_startzpos[no], ®_startzp[no]); - - if (regmatch(next, startp)) - return TRUE; - - restore_se(&save, ®_startzpos[no], ®_startzp[no]); - return FALSE; + rp = regstack_push(®stack, RS_ZOPEN, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + { + rp->rs_no = no; + save_se(&rp->rs_un.sesave, ®_startzpos[no], + ®_startzp[no]); + /* We simply continue and handle the result when done. */ + } } - /* break; Not Reached */ + break; #endif case MCLOSE + 0: /* Match end: \ze */ @@ -4170,20 +4231,19 @@ regmatch(scan, startp) case MCLOSE + 8: case MCLOSE + 9: { - int no; - save_se_T save; - no = op - MCLOSE; cleanup_subexpr(); - save_se(&save, ®_endpos[no], ®_endp[no]); - - if (regmatch(next, startp)) - return TRUE; - - restore_se(&save, ®_endpos[no], ®_endp[no]); - return FALSE; + rp = regstack_push(®stack, RS_MCLOSE, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + { + rp->rs_no = no; + save_se(&rp->rs_un.sesave, ®_endpos[no], ®_endp[no]); + /* We simply continue and handle the result when done. */ + } } - /* break; Not Reached */ + break; #ifdef FEAT_SYN_HL case ZCLOSE + 1: /* \) after \z( */ @@ -4196,20 +4256,20 @@ regmatch(scan, startp) case ZCLOSE + 8: case ZCLOSE + 9: { - int no; - save_se_T save; - no = op - ZCLOSE; cleanup_zsubexpr(); - save_se(&save, ®_endzpos[no], ®_endzp[no]); - - if (regmatch(next, startp)) - return TRUE; - - restore_se(&save, ®_endzpos[no], ®_endzp[no]); - return FALSE; + rp = regstack_push(®stack, RS_ZCLOSE, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + { + rp->rs_no = no; + save_se(&rp->rs_un.sesave, ®_endzpos[no], + ®_endzp[no]); + /* We simply continue and handle the result when done. */ + } } - /* break; Not Reached */ + break; #endif case BACKREF + 1: @@ -4222,7 +4282,6 @@ regmatch(scan, startp) case BACKREF + 8: case BACKREF + 9: { - int no; int len; linenr_T clnum; colnr_T ccol; @@ -4243,7 +4302,7 @@ regmatch(scan, startp) * line. */ len = (int)(reg_endp[no] - reg_startp[no]); if (cstrncmp(reg_startp[no], reginput, &len) != 0) - return FALSE; + status = RA_NOMATCH; } } else /* Multi-line regexp */ @@ -4262,7 +4321,7 @@ regmatch(scan, startp) len = reg_endpos[no].col - reg_startpos[no].col; if (cstrncmp(regline + reg_startpos[no].col, reginput, &len) != 0) - return FALSE; + status = RA_NOMATCH; } else { @@ -4284,7 +4343,10 @@ regmatch(scan, startp) vim_free(reg_tofree); reg_tofree = alloc(len); if (reg_tofree == NULL) - return FALSE; /* out of memory! */ + { + status = RA_FAIL; /* outof memory!*/ + break; + } reg_tofreelen = len; } STRCPY(reg_tofree, regline); @@ -4301,18 +4363,27 @@ regmatch(scan, startp) len = (int)STRLEN(p + ccol); if (cstrncmp(p + ccol, reginput, &len) != 0) - return FALSE; /* doesn't match */ + { + status = RA_NOMATCH; /* doesn't match */ + break; + } if (clnum == reg_endpos[no].lnum) break; /* match and at end! */ if (reglnum == reg_maxline) - return FALSE; /* text too short */ + { + status = RA_NOMATCH; /* text too short */ + break; + } /* Advance to next line. */ reg_nextline(); ++clnum; ccol = 0; - if (got_int || out_of_stack) - return FALSE; + if (got_int) + { + status = RA_FAIL; + break; + } } /* found a match! Note that regline may now point @@ -4337,7 +4408,6 @@ regmatch(scan, startp) case ZREF + 8: case ZREF + 9: { - int no; int len; cleanup_zsubexpr(); @@ -4348,8 +4418,9 @@ regmatch(scan, startp) len = (int)STRLEN(re_extmatch_in->matches[no]); if (cstrncmp(re_extmatch_in->matches[no], reginput, &len) != 0) - return FALSE; - reginput += len; + status = RA_NOMATCH; + else + reginput += len; } else { @@ -4363,32 +4434,23 @@ regmatch(scan, startp) { if (OP(next) != BRANCH) /* No choice. */ next = OPERAND(scan); /* Avoid recursion. */ - else if (startp != NULL && OP(OPERAND(scan)) == BACKP - && reg_save_equal(startp)) + else if (startp != 0 && OP(OPERAND(scan)) == BACKP + && reg_save_equal(STARTP2REGS(startp))) /* \+ with something empty before it */ - return FALSE; + status = RA_NOMATCH; else { - regsave_T save; - - do - { - reg_save(&save); - if (regmatch(OPERAND(scan), &save)) - return TRUE; - reg_restore(&save); - scan = regnext(scan); - } while (scan != NULL && OP(scan) == BRANCH); - return FALSE; - /* NOTREACHED */ + rp = regstack_push(®stack, RS_BRANCH, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + status = RA_BREAK; /* rest is below */ } } break; case BRACE_LIMITS: { - int no; - if (OP(next) == BRACE_SIMPLE) { bl_minval = OPERAND_MIN(scan); @@ -4405,7 +4467,7 @@ regmatch(scan, startp) else { EMSG(_(e_internal)); /* Shouldn't happen */ - return FALSE; + status = RA_FAIL; } } break; @@ -4421,22 +4483,25 @@ regmatch(scan, startp) case BRACE_COMPLEX + 8: case BRACE_COMPLEX + 9: { - int no; - regsave_T save; - no = op - BRACE_COMPLEX; ++brace_count[no]; /* If not matched enough times yet, try one more */ if (brace_count[no] <= (brace_min[no] <= brace_max[no] - ? brace_min[no] : brace_max[no])) + ? brace_min[no] : brace_max[no])) { - reg_save(&save); - if (regmatch(OPERAND(scan), &save)) - return TRUE; - reg_restore(&save); - --brace_count[no]; /* failed, decrement match count */ - return FALSE; + rp = regstack_push(®stack, RS_BRCPLX_MORE, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + { + rp->rs_no = no; + reg_save(&rp->rs_un.regsave); + startp = REGS2STARTP(&rp->rs_un.regsave); + next = OPERAND(scan); + /* We continue and handle the result when done. */ + } + break; } /* If matched enough times, may try matching some more */ @@ -4445,12 +4510,18 @@ regmatch(scan, startp) /* Range is the normal way around, use longest match */ if (brace_count[no] <= brace_max[no]) { - reg_save(&save); - if (regmatch(OPERAND(scan), &save)) - return TRUE; /* matched some more times */ - reg_restore(&save); - --brace_count[no]; /* matched just enough times */ - /* { continue with the items after \{} */ + rp = regstack_push(®stack, RS_BRCPLX_LONG, + scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + { + rp->rs_no = no; + reg_save(&rp->rs_un.regsave); + startp = REGS2STARTP(&rp->rs_un.regsave); + next = OPERAND(scan); + /* We continue and handle the result when done. */ + } } } else @@ -4458,12 +4529,16 @@ regmatch(scan, startp) /* Range is backwards, use shortest match first */ if (brace_count[no] <= brace_min[no]) { - reg_save(&save); - if (regmatch(next, &save)) - return TRUE; - reg_restore(&save); - next = OPERAND(scan); - /* must try to match one more item */ + rp = regstack_push(®stack, RS_BRCPLX_SHORT, + scan, startp); + if (rp == NULL) + status = RA_FAIL; + else + { + reg_save(&rp->rs_un.regsave); + startp = REGS2STARTP(&rp->rs_un.regsave); + /* We continue and handle the result when done. */ + } } } } @@ -4473,12 +4548,7 @@ regmatch(scan, startp) case STAR: case PLUS: { - int nextb; /* next byte */ - int nextb_ic; /* next byte reverse case */ - long count; - regsave_T save; - long minval; - long maxval; + regstar_T rst; /* * Lookahead to avoid useless match attempts when we know @@ -4486,31 +4556,31 @@ regmatch(scan, startp) */ if (OP(next) == EXACTLY) { - nextb = *OPERAND(next); + rst.nextb = *OPERAND(next); if (ireg_ic) { - if (isupper(nextb)) - nextb_ic = TOLOWER_LOC(nextb); + if (isupper(rst.nextb)) + rst.nextb_ic = TOLOWER_LOC(rst.nextb); else - nextb_ic = TOUPPER_LOC(nextb); + rst.nextb_ic = TOUPPER_LOC(rst.nextb); } else - nextb_ic = nextb; + rst.nextb_ic = rst.nextb; } else { - nextb = NUL; - nextb_ic = NUL; + rst.nextb = NUL; + rst.nextb_ic = NUL; } if (op != BRACE_SIMPLE) { - minval = (op == STAR) ? 0 : 1; - maxval = MAX_LIMIT; + rst.minval = (op == STAR) ? 0 : 1; + rst.maxval = MAX_LIMIT; } else { - minval = bl_minval; - maxval = bl_maxval; + rst.minval = bl_minval; + rst.maxval = bl_maxval; } /* @@ -4519,228 +4589,516 @@ regmatch(scan, startp) * minimal number (since the range is backwards, that's also * maxval!). */ - count = regrepeat(OPERAND(scan), maxval); + rst.count = regrepeat(OPERAND(scan), rst.maxval); if (got_int) - return FALSE; - if (minval <= maxval) { - /* Range is the normal way around, use longest match */ - while (count >= minval) - { - /* If it could match, try it. */ - if (nextb == NUL || *reginput == nextb - || *reginput == nextb_ic) - { - reg_save(&save); - if (regmatch(next, startp)) - return TRUE; - reg_restore(&save); - } - /* Couldn't or didn't match -- back up one char. */ - if (--count < minval) - break; - if (reginput == regline) - { - /* backup to last char of previous line */ - --reglnum; - regline = reg_getline(reglnum); - /* Just in case regrepeat() didn't count right. */ - if (regline == NULL) - return FALSE; - reginput = regline + STRLEN(regline); - fast_breakcheck(); - if (got_int || out_of_stack) - return FALSE; - } - else - mb_ptr_back(regline, reginput); - } + status = RA_FAIL; + break; } - else + if (rst.minval <= rst.maxval + ? rst.count >= rst.minval : rst.count >= rst.maxval) { - /* Range is backwards, use shortest match first. - * Careful: maxval and minval are exchanged! */ - if (count < maxval) - return FALSE; - for (;;) + /* It could match. Prepare for trying to match what + * follows. The code is below. Parameters are stored in + * a regstar_T on the regstack. */ + if (ga_grow(®stack, sizeof(regstar_T)) == FAIL) + status = RA_FAIL; + else { - /* If it could work, try it. */ - if (nextb == NUL || *reginput == nextb - || *reginput == nextb_ic) + regstack.ga_len += sizeof(regstar_T); + rp = regstack_push(®stack, rst.minval <= rst.maxval + ? RS_STAR_LONG : RS_STAR_SHORT, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else { - reg_save(&save); - if (regmatch(next, &save)) - return TRUE; - reg_restore(&save); + *(((regstar_T *)rp) - 1) = rst; + status = RA_BREAK; /* skip the restore bits */ } - /* Couldn't or didn't match: try advancing one char. */ - if (count == minval - || regrepeat(OPERAND(scan), 1L) == 0) - break; - ++count; - if (got_int || out_of_stack) - return FALSE; } } - return FALSE; - } - /* break; Not Reached */ + else + status = RA_NOMATCH; - case NOMATCH: - { - regsave_T save; - - /* If the operand matches, we fail. Otherwise backup and - * continue with the next item. */ - reg_save(&save); - if (regmatch(OPERAND(scan), startp)) - return FALSE; - reg_restore(&save); } break; + case NOMATCH: case MATCH: case SUBPAT: + rp = regstack_push(®stack, RS_NOMATCH, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else { - regsave_T save; - - /* If the operand doesn't match, we fail. Otherwise backup - * and continue with the next item. */ - reg_save(&save); - if (!regmatch(OPERAND(scan), startp)) - return FALSE; - if (op == MATCH) /* zero-width */ - reg_restore(&save); + rp->rs_no = op; + reg_save(&rp->rs_un.regsave); + next = OPERAND(scan); + /* We continue and handle the result when done. */ } break; case BEHIND: case NOBEHIND: + /* Need a bit of room to store extra positions. */ + if (ga_grow(®stack, sizeof(regbehind_T)) == FAIL) + status = RA_FAIL; + else { - regsave_T save_after, save_start; - regsave_T save_behind_pos; - int needmatch = (op == BEHIND); - - /* - * Look back in the input of the operand matches or not. This - * must be done at every position in the input and checking if - * the match ends at the current position. - * First check if the next item matches, that's probably - * faster. - */ - reg_save(&save_start); - if (regmatch(next, startp)) + regstack.ga_len += sizeof(regbehind_T); + rp = regstack_push(®stack, RS_BEHIND1, scan, startp); + if (rp == NULL) + status = RA_FAIL; + else { - /* save the position after the found match for next */ - reg_save(&save_after); - - /* start looking for a match with operand at the current - * postion. Go back one character until we find the - * result, hitting the start of the line or the previous - * line (for multi-line matching). - * Set behind_pos to where the match should end, BHPOS - * will match it. */ - save_behind_pos = behind_pos; - behind_pos = save_start; - for (;;) - { - reg_restore(&save_start); - if (regmatch(OPERAND(scan), startp) - && reg_save_equal(&behind_pos)) - { - behind_pos = save_behind_pos; - /* found a match that ends where "next" started */ - if (needmatch) - { - reg_restore(&save_after); - return TRUE; - } - return FALSE; - } - /* - * No match: Go back one character. May go to - * previous line once. - */ - if (REG_MULTI) - { - if (save_start.rs_u.pos.col == 0) - { - if (save_start.rs_u.pos.lnum - < behind_pos.rs_u.pos.lnum - || reg_getline( - --save_start.rs_u.pos.lnum) == NULL) - break; - reg_restore(&save_start); - save_start.rs_u.pos.col = - (colnr_T)STRLEN(regline); - } - else - --save_start.rs_u.pos.col; - } - else - { - if (save_start.rs_u.ptr == regline) - break; - --save_start.rs_u.ptr; - } - } - - /* NOBEHIND succeeds when no match was found */ - behind_pos = save_behind_pos; - if (!needmatch) - { - reg_restore(&save_after); - return TRUE; - } + rp->rs_no = op; + reg_save(&rp->rs_un.regsave); + /* First try if what follows matches. If it does then we + * check the behind match by looping. */ } - return FALSE; } + break; case BHPOS: if (REG_MULTI) { if (behind_pos.rs_u.pos.col != (colnr_T)(reginput - regline) || behind_pos.rs_u.pos.lnum != reglnum) - return FALSE; + status = RA_NOMATCH; } else if (behind_pos.rs_u.ptr != reginput) - return FALSE; + status = RA_NOMATCH; break; case NEWL: if ((c != NUL || reglnum == reg_maxline) && (c != '\n' || !reg_line_lbr)) - return FALSE; - if (reg_line_lbr) + status = RA_NOMATCH; + else if (reg_line_lbr) ADVANCE_REGINPUT(); else reg_nextline(); break; case END: - return TRUE; /* Success! */ + status = RA_MATCH; /* Success! */ + break; default: EMSG(_(e_re_corr)); #ifdef DEBUG printf("Illegal op code %d\n", op); #endif - return FALSE; + status = RA_FAIL; + break; } } + /* If we can't continue sequentially, break the inner loop. */ + if (status != RA_CONT) + break; + + /* Continue in inner loop, advance to next item. */ scan = next; + + } /* end of inner loop */ + + /* + * If there is something on the regstack execute the code for the state. + * If the state is popped then loop. + */ + while (regstack.ga_len > 0 && status != RA_FAIL) + { + rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1; + switch (rp->rs_state) + { + case RS_NOPEN: + /* Result is passed on as-is, simply pop the state. */ + regstack_pop(®stack, &scan, &startp); + break; + + case RS_MOPEN: + /* Pop the state. Restore pointers when there is no match. */ + if (status == RA_NOMATCH) + restore_se(&rp->rs_un.sesave, ®_startpos[rp->rs_no], + ®_startp[rp->rs_no]); + regstack_pop(®stack, &scan, &startp); + break; + +#ifdef FEAT_SYN_HL + case RS_ZOPEN: + /* Pop the state. Restore pointers when there is no match. */ + if (status == RA_NOMATCH) + restore_se(&rp->rs_un.sesave, ®_startzpos[rp->rs_no], + ®_startzp[rp->rs_no]); + regstack_pop(®stack, &scan, &startp); + break; +#endif + + case RS_MCLOSE: + /* Pop the state. Restore pointers when there is no match. */ + if (status == RA_NOMATCH) + restore_se(&rp->rs_un.sesave, ®_endpos[rp->rs_no], + ®_endp[rp->rs_no]); + regstack_pop(®stack, &scan, &startp); + break; + +#ifdef FEAT_SYN_HL + case RS_ZCLOSE: + /* Pop the state. Restore pointers when there is no match. */ + if (status == RA_NOMATCH) + restore_se(&rp->rs_un.sesave, ®_endzpos[rp->rs_no], + ®_endzp[rp->rs_no]); + regstack_pop(®stack, &scan, &startp); + break; +#endif + + case RS_BRANCH: + if (status == RA_MATCH) + /* this branch matched, use it */ + regstack_pop(®stack, &scan, &startp); + else + { + if (status != RA_BREAK) + { + /* After a non-matching branch: try next one. */ + reg_restore(&rp->rs_un.regsave); + scan = rp->rs_scan; + } + if (scan == NULL || OP(scan) != BRANCH) + { + /* no more branches, didn't find a match */ + status = RA_NOMATCH; + regstack_pop(®stack, &scan, &startp); + } + else + { + /* Prepare to try a branch. */ + rp->rs_scan = regnext(scan); + reg_save(&rp->rs_un.regsave); + startp = REGS2STARTP(&rp->rs_un.regsave); + scan = OPERAND(scan); + } + } + break; + + case RS_BRCPLX_MORE: + /* Pop the state. Restore pointers when there is no match. */ + if (status == RA_NOMATCH) + { + reg_restore(&rp->rs_un.regsave); + --brace_count[rp->rs_no]; /* decrement match count */ + } + regstack_pop(®stack, &scan, &startp); + break; + + case RS_BRCPLX_LONG: + /* Pop the state. Restore pointers when there is no match. */ + if (status == RA_NOMATCH) + { + /* There was no match, but we did find enough matches. */ + reg_restore(&rp->rs_un.regsave); + --brace_count[rp->rs_no]; + /* continue with the items after "\{}" */ + status = RA_CONT; + } + regstack_pop(®stack, &scan, &startp); + if (status == RA_CONT) + scan = regnext(scan); + break; + + case RS_BRCPLX_SHORT: + /* Pop the state. Restore pointers when there is no match. */ + if (status == RA_NOMATCH) + /* There was no match, try to match one more item. */ + reg_restore(&rp->rs_un.regsave); + regstack_pop(®stack, &scan, &startp); + if (status == RA_NOMATCH) + { + scan = OPERAND(scan); + status = RA_CONT; + } + break; + + case RS_NOMATCH: + /* Pop the state. If the operand matches for NOMATCH or + * doesn't match for MATCH/SUBPAT, we fail. Otherwise backup, + * except for SUBPAT, and continue with the next item. */ + if (status == (rp->rs_no == NOMATCH ? RA_MATCH : RA_NOMATCH)) + status = RA_NOMATCH; + else + { + status = RA_CONT; + if (rp->rs_no != SUBPAT) + reg_restore(&rp->rs_un.regsave); /* zero-width */ + } + regstack_pop(®stack, &scan, &startp); + if (status == RA_CONT) + scan = regnext(scan); + break; + + case RS_BEHIND1: + if (status == RA_NOMATCH) + { + regstack_pop(®stack, &scan, &startp); + regstack.ga_len -= sizeof(regbehind_T); + } + else + { + /* The stuff after BEHIND/NOBEHIND matches. Now try if + * the behind part does (not) match before the current + * position in the input. This must be done at every + * position in the input and checking if the match ends at + * the current position. */ + + /* save the position after the found match for next */ + reg_save(&(((regbehind_T *)rp) - 1)->save_after); + + /* start looking for a match with operand at the current + * postion. Go back one character until we find the + * result, hitting the start of the line or the previous + * line (for multi-line matching). + * Set behind_pos to where the match should end, BHPOS + * will match it. Save the current value. */ + (((regbehind_T *)rp) - 1)->save_behind = behind_pos; + behind_pos = rp->rs_un.regsave; + + rp->rs_state = RS_BEHIND2; + + reg_restore(&rp->rs_un.regsave); + scan = OPERAND(rp->rs_scan); + } + break; + + case RS_BEHIND2: + /* + * Looping for BEHIND / NOBEHIND match. + */ + if (status == RA_MATCH && reg_save_equal(&behind_pos)) + { + /* found a match that ends where "next" started */ + behind_pos = (((regbehind_T *)rp) - 1)->save_behind; + if (rp->rs_no == BEHIND) + reg_restore(&(((regbehind_T *)rp) - 1)->save_after); + else + /* But we didn't want a match. */ + status = RA_NOMATCH; + regstack_pop(®stack, &scan, &startp); + regstack.ga_len -= sizeof(regbehind_T); + } + else + { + /* No match: Go back one character. May go to previous + * line once. */ + no = OK; + if (REG_MULTI) + { + if (rp->rs_un.regsave.rs_u.pos.col == 0) + { + if (rp->rs_un.regsave.rs_u.pos.lnum + < behind_pos.rs_u.pos.lnum + || reg_getline( + --rp->rs_un.regsave.rs_u.pos.lnum) + == NULL) + no = FAIL; + else + { + reg_restore(&rp->rs_un.regsave); + rp->rs_un.regsave.rs_u.pos.col = + (colnr_T)STRLEN(regline); + } + } + else + --rp->rs_un.regsave.rs_u.pos.col; + } + else + { + if (rp->rs_un.regsave.rs_u.ptr == regline) + no = FAIL; + else + --rp->rs_un.regsave.rs_u.ptr; + } + if (no == OK) + { + /* Advanced, prepare for finding match again. */ + reg_restore(&rp->rs_un.regsave); + scan = OPERAND(rp->rs_scan); + } + else + { + /* Can't advance. For NOBEHIND that's a match. */ + behind_pos = (((regbehind_T *)rp) - 1)->save_behind; + if (rp->rs_no == NOBEHIND) + { + reg_restore(&(((regbehind_T *)rp) - 1)->save_after); + status = RA_MATCH; + } + else + status = RA_NOMATCH; + regstack_pop(®stack, &scan, &startp); + regstack.ga_len -= sizeof(regbehind_T); + } + } + break; + + case RS_STAR_LONG: + case RS_STAR_SHORT: + { + regstar_T *rst = ((regstar_T *)rp) - 1; + + if (status == RA_MATCH) + { + regstack_pop(®stack, &scan, &startp); + regstack.ga_len -= sizeof(regstar_T); + break; + } + + /* Tried once already, restore input pointers. */ + if (status != RA_BREAK) + reg_restore(&rp->rs_un.regsave); + + /* Repeat until we found a position where it could match. */ + for (;;) + { + if (status != RA_BREAK) + { + /* Tried first position already, advance. */ + if (rp->rs_state == RS_STAR_LONG) + { + /* Trying for longest matc, but couldn't or didn't + * match -- back up one char. */ + if (--rst->count < rst->minval) + break; + if (reginput == regline) + { + /* backup to last char of previous line */ + --reglnum; + regline = reg_getline(reglnum); + /* Just in case regrepeat() didn't count + * right. */ + if (regline == NULL) + break; + reginput = regline + STRLEN(regline); + fast_breakcheck(); + } + else + mb_ptr_back(regline, reginput); + } + else + { + /* Range is backwards, use shortest match first. + * Careful: maxval and minval are exchanged! + * Couldn't or didn't match: try advancing one + * char. */ + if (rst->count == rst->minval + || regrepeat(OPERAND(rp->rs_scan), 1L) == 0) + break; + ++rst->count; + } + if (got_int) + break; + } + else + status = RA_NOMATCH; + + /* If it could match, try it. */ + if (rst->nextb == NUL || *reginput == rst->nextb + || *reginput == rst->nextb_ic) + { + reg_save(&rp->rs_un.regsave); + scan = regnext(rp->rs_scan); + status = RA_CONT; + break; + } + } + if (status != RA_CONT) + { + /* Failed. */ + regstack_pop(®stack, &scan, &startp); + regstack.ga_len -= sizeof(regstar_T); + status = RA_NOMATCH; + } + } + break; + } + + /* If we want to continue the inner loop or didn't pop a state contine + * matching loop */ + if (status == RA_CONT || rp == (regitem_T *) + ((char *)regstack.ga_data + regstack.ga_len) - 1) + break; } + /* May want to continue with the inner loop. */ + if (status == RA_CONT) + continue; + /* - * We get here only if there's trouble -- normally "case END" is the - * terminating point. + * If the regstack is empty or something failed we are done. */ - EMSG(_(e_re_corr)); + if (regstack.ga_len == 0 || status == RA_FAIL) + { + ga_clear(®stack); + if (scan == NULL) + { + /* + * We get here only if there's trouble -- normally "case END" is + * the terminating point. + */ + EMSG(_(e_re_corr)); #ifdef DEBUG - printf("Premature EOL\n"); + printf("Premature EOL\n"); #endif - return FALSE; + } + return (status == RA_MATCH); + } + + } /* End of loop until the regstack is empty. */ + + /* NOTREACHED */ +} + +/* + * Push an item onto the regstack. + * Returns pointer to new item. Returns NULL when out of memory. + */ + static regitem_T * +regstack_push(regstack, state, scan, startp) + garray_T *regstack; + regstate_T state; + char_u *scan; + long startp; +{ + regitem_T *rp; + + if (ga_grow(regstack, sizeof(regitem_T)) == FAIL) + return NULL; + + rp = (regitem_T *)((char *)regstack->ga_data + regstack->ga_len); + rp->rs_state = state; + rp->rs_scan = scan; + rp->rs_startp = startp; + + regstack->ga_len += sizeof(regitem_T); + return rp; +} + +/* + * Pop an item from the regstack. + */ + static void +regstack_pop(regstack, scan, startp) + garray_T *regstack; + char_u **scan; + long *startp; +{ + regitem_T *rp; + + rp = (regitem_T *)((char *)regstack->ga_data + regstack->ga_len) - 1; + *scan = rp->rs_scan; + *startp = rp->rs_startp; + + regstack->ga_len -= sizeof(regitem_T); } /* diff --git a/src/term.c b/src/term.c index 3097cc324..3c0ecb05b 100644 --- a/src/term.c +++ b/src/term.c @@ -994,21 +994,21 @@ struct builtin_term builtin_termcaps[] = {(int)KS_CWP, IF_EB("\033[3;%d;%dt", ESC_STR "[3;%d;%dt")}, # endif {(int)KS_CRV, IF_EB("\033[>c", ESC_STR "[>c")}, - {K_UP, IF_EB("\033OA", ESC_STR "OA")}, - {K_DOWN, IF_EB("\033OB", ESC_STR "OB")}, - {K_RIGHT, IF_EB("\033OC", ESC_STR "OC")}, - {K_LEFT, IF_EB("\033OD", ESC_STR "OD")}, - {K_S_UP, IF_EB("\033O2A", ESC_STR "O2A")}, - {K_S_DOWN, IF_EB("\033O2B", ESC_STR "O2B")}, - {K_S_RIGHT, IF_EB("\033O2C", ESC_STR "O2C")}, - {K_C_RIGHT, IF_EB("\033O5C", ESC_STR "O5C")}, - {K_S_LEFT, IF_EB("\033O2D", ESC_STR "O2D")}, - {K_C_LEFT, IF_EB("\033O5D", ESC_STR "O5D")}, + + {K_UP, IF_EB("\033O*A", ESC_STR "O*A")}, + {K_DOWN, IF_EB("\033O*B", ESC_STR "O*B")}, + {K_RIGHT, IF_EB("\033O*C", ESC_STR "O*C")}, + {K_LEFT, IF_EB("\033O*D", ESC_STR "O*D")}, + /* An extra set of cursor keys for vt100 mode */ + {K_XUP, IF_EB("\033[1;*A", ESC_STR "[1;*A")}, + {K_XDOWN, IF_EB("\033[1;*B", ESC_STR "[1;*B")}, + {K_XRIGHT, IF_EB("\033[1;*C", ESC_STR "[1;*C")}, + {K_XLEFT, IF_EB("\033[1;*D", ESC_STR "[1;*D")}, /* An extra set of function keys for vt100 mode */ - {K_XF1, IF_EB("\033OP", ESC_STR "OP")}, - {K_XF2, IF_EB("\033OQ", ESC_STR "OQ")}, - {K_XF3, IF_EB("\033OR", ESC_STR "OR")}, - {K_XF4, IF_EB("\033OS", ESC_STR "OS")}, + {K_XF1, IF_EB("\033O*P", ESC_STR "O*P")}, + {K_XF2, IF_EB("\033O*Q", ESC_STR "O*Q")}, + {K_XF3, IF_EB("\033O*R", ESC_STR "O*R")}, + {K_XF4, IF_EB("\033O*S", ESC_STR "O*S")}, {K_F1, IF_EB("\033[11;*~", ESC_STR "[11;*~")}, {K_F2, IF_EB("\033[12;*~", ESC_STR "[12;*~")}, {K_F3, IF_EB("\033[13;*~", ESC_STR "[13;*~")}, @@ -1021,32 +1021,28 @@ struct builtin_term builtin_termcaps[] = {K_F10, IF_EB("\033[21;*~", ESC_STR "[21;*~")}, {K_F11, IF_EB("\033[23;*~", ESC_STR "[23;*~")}, {K_F12, IF_EB("\033[24;*~", ESC_STR "[24;*~")}, - {K_S_XF1, IF_EB("\033O2P", ESC_STR "O2P")}, - {K_S_XF2, IF_EB("\033O2Q", ESC_STR "O2Q")}, - {K_S_XF3, IF_EB("\033O2R", ESC_STR "O2R")}, - {K_S_XF4, IF_EB("\033O2S", ESC_STR "O2S")}, {K_S_TAB, IF_EB("\033[Z", ESC_STR "[Z")}, {K_HELP, IF_EB("\033[28;*~", ESC_STR "[28;*~")}, {K_UNDO, IF_EB("\033[26;*~", ESC_STR "[26;*~")}, {K_INS, IF_EB("\033[2;*~", ESC_STR "[2;*~")}, {K_HOME, IF_EB("\033[1;*H", ESC_STR "[1;*H")}, - {K_S_HOME, IF_EB("\033O2H", ESC_STR "O2H")}, - {K_C_HOME, IF_EB("\033O5H", ESC_STR "O5H")}, + /* {K_S_HOME, IF_EB("\033O2H", ESC_STR "O2H")}, */ + /* {K_C_HOME, IF_EB("\033O5H", ESC_STR "O5H")}, */ {K_KHOME, IF_EB("\033[7;*~", ESC_STR "[7;*~")}, - {K_XHOME, IF_EB("\033OH", ESC_STR "OH")}, /* alternate Home */ + {K_XHOME, IF_EB("\033O*H", ESC_STR "O*H")}, /* other Home */ {K_END, IF_EB("\033[1;*F", ESC_STR "[1;*F")}, - {K_S_END, IF_EB("\033O2F", ESC_STR "O2F")}, - {K_C_END, IF_EB("\033O5F", ESC_STR "O5F")}, + /* {K_S_END, IF_EB("\033O2F", ESC_STR "O2F")}, */ + /* {K_C_END, IF_EB("\033O5F", ESC_STR "O5F")}, */ {K_KEND, IF_EB("\033[4;*~", ESC_STR "[4;*~")}, - {K_XEND, IF_EB("\033OF", ESC_STR "OF")}, /* alternate End */ + {K_XEND, IF_EB("\033O*F", ESC_STR "O*F")}, /* other End */ {K_PAGEUP, IF_EB("\033[5;*~", ESC_STR "[5;*~")}, {K_PAGEDOWN, IF_EB("\033[6;*~", ESC_STR "[6;*~")}, - {K_KPLUS, IF_EB("\033Ok", ESC_STR "Ok")}, /* keypad plus */ - {K_KMINUS, IF_EB("\033Om", ESC_STR "Om")}, /* keypad minus */ - {K_KDIVIDE, IF_EB("\033Oo", ESC_STR "Oo")}, /* keypad / */ - {K_KMULTIPLY, IF_EB("\033Oj", ESC_STR "Oj")}, /* keypad * */ - {K_KENTER, IF_EB("\033OM", ESC_STR "OM")}, /* keypad Enter */ - {K_KPOINT, IF_EB("\033On", ESC_STR "On")}, /* keypad . */ + {K_KPLUS, IF_EB("\033O*k", ESC_STR "O*k")}, /* keypad plus */ + {K_KMINUS, IF_EB("\033O*m", ESC_STR "O*m")}, /* keypad minus */ + {K_KDIVIDE, IF_EB("\033O*o", ESC_STR "O*o")}, /* keypad / */ + {K_KMULTIPLY, IF_EB("\033O*j", ESC_STR "O*j")}, /* keypad * */ + {K_KENTER, IF_EB("\033O*M", ESC_STR "O*M")}, /* keypad Enter */ + {K_KPOINT, IF_EB("\033O*n", ESC_STR "O*n")}, /* keypad . */ {K_KDEL, IF_EB("\033[3;*~", ESC_STR "[3;*~")}, /* keypad Del */ {BT_EXTRA_KEYS, ""}, @@ -1286,6 +1282,10 @@ struct builtin_term builtin_termcaps[] = {K_DOWN, "[KD]"}, {K_LEFT, "[KL]"}, {K_RIGHT, "[KR]"}, + {K_XUP, "[xKU]"}, + {K_XDOWN, "[xKD]"}, + {K_XLEFT, "[xKL]"}, + {K_XRIGHT, "[xKR]"}, {K_S_UP, "[S-KU]"}, {K_S_DOWN, "[S-KD]"}, {K_S_LEFT, "[S-KL]"}, @@ -1570,10 +1570,6 @@ static char *(key_names[]) = "#2", "#4", "%i", "*7", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9", "k;", "F1", "F2", - "F3", "F4", "F5", "F6", "F7", "F8", - "F9", "FA", "FB", "FC", "FD", "FE", - "FF", "FG", "FH", "FI", "FJ", "FK", - "FL", "FM", "FN", "FO", "FP", "FQ", "FR", "%1", "&8", "kb", "kI", "kD", "kh", "@7", "kP", "kN", "K1", "K3", "K4", "K5", "kB", NULL @@ -3497,6 +3493,8 @@ struct termcode static int tc_max_len = 0; /* number of entries that termcodes[] can hold */ static int tc_len = 0; /* current number of entries in termcodes[] */ +static int termcode_star __ARGS((char_u *code, int len)); + void clear_termcodes() { @@ -3516,15 +3514,19 @@ clear_termcodes() need_gather = TRUE; /* need to fill termleader[] */ } +#define ATC_FROM_TERM 55 + /* * Add a new entry to the list of terminal codes. * The list is kept alphabetical for ":set termcap" + * "flags" is TRUE when replacing 7-bit by 8-bit controls is desired. + * "flags" can also be ATC_FROM_TERM for got_code_from_term(). */ void -add_termcode(name, string, use_8bit) +add_termcode(name, string, flags) char_u *name; char_u *string; - int use_8bit; /* replace 7-bit control by 8-bit one */ + int flags; { struct termcode *new_tc; int i, j; @@ -3542,7 +3544,7 @@ add_termcode(name, string, use_8bit) return; /* Change leading <Esc>[ to CSI, change <Esc>O to <M-O>. */ - if (use_8bit && term_7to8bit(string) != 0) + if (flags != 0 && flags != ATC_FROM_TERM && term_7to8bit(string) != 0) { mch_memmove(s, s + 1, STRLEN(s)); s[0] = term_7to8bit(string); @@ -3584,26 +3586,28 @@ add_termcode(name, string, use_8bit) if (termcodes[i].name[1] < name[1]) continue; /* - * Exact match: Replace old code. - * But don't replace ESC[123;*X with another. + * Exact match: May replace old code. */ if (termcodes[i].name[1] == name[1]) { - if (termcodes[i].len >= 4 - && STRNCMP(termcodes[i].code + termcodes[i].len - 3, - ";*", 2) == 0) + if (flags == ATC_FROM_TERM && (j = termcode_star( + termcodes[i].code, termcodes[i].len)) > 0) { - /* if they are equal but for the ";*" don't add it */ - if (len == termcodes[i].len - 2 + /* Don't replace ESC[123;*X or ESC O*X with another when + * invoked from got_code_from_term(). */ + if (len == termcodes[i].len - j && STRNCMP(s, termcodes[i].code, len - 1) == 0 - && s[len - 1] == termcodes[i].code[len + 1]) + && s[len - 1] + == termcodes[i].code[termcodes[i].len - 1]) { + /* They are equal but for the ";*": don't add it. */ vim_free(s); return; } } else { + /* Replace old code. */ vim_free(termcodes[i].code); --tc_len; break; @@ -3622,14 +3626,37 @@ add_termcode(name, string, use_8bit) termcodes[i].name[1] = name[1]; termcodes[i].code = s; termcodes[i].len = len; - /* recognize special code like "ESC[42;*X" that accepts modifiers */ - if (len >= 5 && STRNCMP(s + len - 3, ";*", 2) == 0) - termcodes[i].modlen = len - 3; - else - termcodes[i].modlen = 0; + + /* For xterm we recognize special codes like "ESC[42;*X" and "ESC O*X" that + * accept modifiers. */ + termcodes[i].modlen = 0; + j = termcode_star(s, len); + if (j > 0) + termcodes[i].modlen = len - 1 - j; ++tc_len; } +/* + * Check termcode "code[len]" for ending in ;*X, <Esc>O*X or <M-O>*X. + * The "X" can be any character. + * Return 0 if not found, 2 for ;*X and 1 for O*X and <M-O>*X. + */ + static int +termcode_star(code, len) + char_u *code; + int len; +{ + /* Shortest is <M-O>*X. With ; shortest is <CSI>1;*X */ + if (len >= 3 && code[len - 2] == '*') + { + if (len >= 5 && code[len - 3] == ';') + return 2; + if ((len >= 4 && code[len - 3] == 'O') || code[len - 3] == 'O' + 128) + return 1; + } + return 0; +} + char_u * find_termcode(name) char_u *name; @@ -3762,9 +3789,12 @@ check_termcode(max_offset, buf, buflen) char_u *tp; char_u *p; int slen = 0; /* init for GCC */ + int modslen; int len; int offset; char_u key_name[2]; + int modifiers; + int key; int new_slen; int extra; char_u string[MAX_KEY_CODE_LEN + 1]; @@ -3776,7 +3806,6 @@ check_termcode(max_offset, buf, buflen) int num_bytes; # endif int mouse_code = 0; /* init for GCC */ - int modifiers; int is_click, is_drag; int wheel_code = 0; int current_button; @@ -3859,8 +3888,8 @@ check_termcode(max_offset, buf, buflen) if (*tp == ESC && !p_ek && (State & INSERT)) continue; - new_slen = 0; /* Length of what will replace the termcode */ key_name[0] = NUL; /* no key name found yet */ + modifiers = 0; /* no modifiers yet */ #ifdef FEAT_GUI if (gui.in_use) @@ -3918,69 +3947,60 @@ check_termcode(max_offset, buf, buflen) key_name[0] = termcodes[idx].name[0]; key_name[1] = termcodes[idx].name[1]; - break; } /* * Check for code with modifier, like xterm uses: - * ESC[123;2X (shift) ESC[123;3X (alt), etc. + * <Esc>[123;*X (modslen == slen - 3) + * Also <Esc>O*X and <M-O>*X (modslen == slen - 2). + * When there is a modifier the * matches a number. + * When there is no modifier the ;* or * is omitted. */ if (termcodes[idx].modlen > 0) { - slen = termcodes[idx].modlen; - if (cpo_koffset && offset && len < slen) + modslen = termcodes[idx].modlen; + if (cpo_koffset && offset && len < modslen) continue; if (STRNCMP(termcodes[idx].code, tp, - (size_t)(slen > len ? len : slen)) == 0) + (size_t)(modslen > len ? len : modslen)) == 0) { int n; - int mod; - if (len <= slen) /* got a partial sequence */ + if (len <= modslen) /* got a partial sequence */ return -1; /* need to get more chars */ - if (tp[slen] == termcodes[idx].code[slen + 2]) - ++slen; /* no modifiers */ - else if (tp[slen] != ';') + if (tp[modslen] == termcodes[idx].code[slen - 1]) + slen = modslen + 1; /* no modifiers */ + else if (tp[modslen] != ';' && modslen == slen - 3) continue; /* no match */ else { /* Skip over the digits, the final char must * follow. */ - for (j = slen + 1; j < len && isdigit(tp[j]); ++j) + for (j = slen - 2; j < len && isdigit(tp[j]); ++j) ; ++j; if (len < j) /* got a partial sequence */ return -1; /* need to get more chars */ - if (tp[j - 1] != termcodes[idx].code[slen + 2]) - continue; + if (tp[j - 1] != termcodes[idx].code[slen - 1]) + continue; /* no match */ /* Match! Convert modifier bits. */ - n = atoi((char *)tp + slen + 1) - 1; - mod = 0x0; + n = atoi((char *)tp + slen - 2) - 1; if (n & 1) - mod |= MOD_MASK_SHIFT; + modifiers |= MOD_MASK_SHIFT; if (n & 2) - mod |= MOD_MASK_ALT; + modifiers |= MOD_MASK_ALT; if (n & 4) - mod |= MOD_MASK_CTRL; + modifiers |= MOD_MASK_CTRL; if (n & 8) - mod |= MOD_MASK_META; - - /* Add the modifier codes to our string */ - if (mod != 0) - { - string[new_slen++] = K_SPECIAL; - string[new_slen++] = (int)KS_MODIFIER; - string[new_slen++] = mod; - } + modifiers |= MOD_MASK_META; slen = j; } key_name[0] = termcodes[idx].name[0]; key_name[1] = termcodes[idx].name[1]; - break; } } @@ -4672,7 +4692,6 @@ check_termcode(max_offset, buf, buflen) * Translate the actual mouse event into a pseudo mouse event. * First work out what modifiers are to be used. */ - modifiers = 0x0; if (orig_mouse_code & MOUSE_SHIFT) modifiers |= MOD_MASK_SHIFT; if (orig_mouse_code & MOUSE_CTRL) @@ -4686,14 +4705,6 @@ check_termcode(max_offset, buf, buflen) else if (orig_num_clicks == 4) modifiers |= MOD_MASK_4CLICK; - /* Add the modifier codes to our string */ - if (modifiers != 0) - { - string[new_slen++] = K_SPECIAL; - string[new_slen++] = (int)KS_MODIFIER; - string[new_slen++] = modifiers; - } - /* Work out our pseudo mouse event */ key_name[0] = (int)KS_EXTRA; if (wheel_code != 0) @@ -4785,7 +4796,31 @@ check_termcode(max_offset, buf, buflen) # endif /* !USE_ON_FLY_SCROLL */ #endif /* FEAT_GUI */ + /* + * Change <xHome> to <Home>, <xUp> to <Up>, etc. + */ + key = handle_x_keys(TERMCAP2KEY(key_name[0], key_name[1])); + + /* + * Add any modifier codes to our string. + */ + new_slen = 0; /* Length of what will replace the termcode */ + if (modifiers != 0) + { + /* Some keys have the modifier included. Need to handle that here + * to make mappings work. */ + key = simplify_key(key, &modifiers); + if (modifiers != 0) + { + string[new_slen++] = K_SPECIAL; + string[new_slen++] = (int)KS_MODIFIER; + string[new_slen++] = modifiers; + } + } + /* Finally, add the special key code to our string */ + key_name[0] = KEY2TERMCAP0(key); + key_name[1] = KEY2TERMCAP1(key); if (key_name[0] == KS_KEY) string[new_slen++] = key_name[1]; /* from ":set <M-b>=xx" */ else @@ -5124,7 +5159,8 @@ show_termcodes() int i; int len; -#define INC 27 /* try to make three columns */ +#define INC3 27 /* try to make three columns */ +#define INC2 40 /* try to make two columns */ #define GAP 2 /* spaces between columns */ if (tc_len == 0) /* no terminal codes (must be GUI) */ @@ -5139,9 +5175,10 @@ show_termcodes() /* * do the loop two times: * 1. display the short items (non-strings and short strings) - * 2. display the long items (strings) + * 2. display the medium items (medium length strings) + * 3. display the long items (remaining strings) */ - for (run = 1; run <= 2 && !got_int; ++run) + for (run = 1; run <= 3 && !got_int; ++run) { /* * collect the items in items[] @@ -5151,21 +5188,23 @@ show_termcodes() { len = show_one_termcode(termcodes[i].name, termcodes[i].code, FALSE); - if ((len <= INC - GAP && run == 1) || (len > INC - GAP && run == 2)) + if (len <= INC3 - GAP ? run == 1 + : len <= INC2 - GAP ? run == 2 + : run == 3) items[item_count++] = i; } /* * display the items */ - if (run == 1) + if (run <= 2) { - cols = (Columns + GAP) / INC; + cols = (Columns + GAP) / (run == 1 ? INC3 : INC2); if (cols == 0) cols = 1; rows = (item_count + cols - 1) / cols; } - else /* run == 2 */ + else /* run == 3 */ rows = item_count; for (row = 0; row < rows && !got_int; ++row) { @@ -5178,7 +5217,10 @@ show_termcodes() msg_col = col; /* make columns */ show_one_termcode(termcodes[items[i]].name, termcodes[items[i]].code, TRUE); - col += INC; + if (run == 2) + col += INC2; + else + col += INC3; } out_flush(); ui_breakcheck(); @@ -5343,7 +5385,7 @@ got_code_from_term(code, len) i = find_term_bykeys(str); if (i >= 0) del_termcode_idx(i); - add_termcode(name, str, FALSE); + add_termcode(name, str, ATC_FROM_TERM); } } } diff --git a/src/testdir/test24.in b/src/testdir/test24.in Binary files differindex d9640e5f2..bdcdb4c69 100644 --- a/src/testdir/test24.in +++ b/src/testdir/test24.in diff --git a/src/testdir/test24.ok b/src/testdir/test24.ok index 752dad583..ae9dcb4e2 100644 --- a/src/testdir/test24.ok +++ b/src/testdir/test24.ok @@ -20,3 +20,8 @@ test text test text [\u-z] xx xx a xx aaaaa xx a xx aaaaa xx a +xx Aaa xx +xx Aaaa xx +xx Aaa xx +xx foobar xA xx +xx an A xx diff --git a/src/version.h b/src/version.h index b537d7208..29790b8ef 100644 --- a/src/version.h +++ b/src/version.h @@ -36,5 +36,5 @@ #define VIM_VERSION_NODOT "vim70aa" #define VIM_VERSION_SHORT "7.0aa" #define VIM_VERSION_MEDIUM "7.0aa ALPHA" -#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2005 Mar 4)" -#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2005 Mar 4, compiled " +#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2005 Mar 7)" +#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2005 Mar 7, compiled " diff --git a/src/window.c b/src/window.c index 7cd2f0224..f33903442 100644 --- a/src/window.c +++ b/src/window.c @@ -263,6 +263,7 @@ do_window(nchar, Prenum, xchar) /* cursor to window below */ case 'j': case K_DOWN: + case K_XDOWN: case Ctrl_J: CHECK_CMDWIN #ifdef FEAT_VERTSPLIT @@ -278,6 +279,7 @@ do_window(nchar, Prenum, xchar) /* cursor to window above */ case 'k': case K_UP: + case K_XUP: case Ctrl_K: CHECK_CMDWIN #ifdef FEAT_VERTSPLIT @@ -294,6 +296,7 @@ do_window(nchar, Prenum, xchar) /* cursor to left window */ case 'h': case K_LEFT: + case K_XLEFT: case Ctrl_H: case K_BS: CHECK_CMDWIN @@ -303,6 +306,7 @@ do_window(nchar, Prenum, xchar) /* cursor to right window */ case 'l': case K_RIGHT: + case K_XRIGHT: case Ctrl_L: CHECK_CMDWIN win_goto_hor(FALSE, Prenum1); |