-*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
":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)
-*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
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)
'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|.
'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|.
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*
-*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
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'*
" 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")
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
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;
}
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:
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:
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:
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:
{
/* 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;
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:
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;
}
/* 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);
/* 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 */
(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;
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 */
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;
c = p_wc;
}
}
- else if (c == K_UP)
+ else if (c == K_UP || c == K_XUP)
{
/* go up a directory */
int found = FALSE;
continue; /* don't do incremental search now */
case K_RIGHT:
+ case K_XRIGHT:
case K_S_RIGHT:
case K_C_RIGHT:
do
#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)
goto cmdline_not_changed;
case K_LEFT:
+ case K_XLEFT:
case K_S_LEFT:
case K_C_LEFT:
do
#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)
#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:
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];
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;
}
#endif
+#if defined(MSDOS) || defined(MSWIN) || defined(OS2) || defined(MACOS)
/*
* Default mappings for some often used keys.
*/
{(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},
{(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.
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
}
/*
#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"));
, 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 */
#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')
case BS:
case 'k':
case K_UP:
+ case K_XUP:
if (!more_back_used)
{
msg_moremsg(TRUE);
case NL:
case 'j':
case K_DOWN:
+ case K_XDOWN:
lines_left = 1;
break;
case ':': /* start new command line */
{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"},
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.
return key;
}
+/*
+ * 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.
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
{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},
{
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;
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;
/* "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)
/* "zl" - scroll screen to the left */
case 'l':
case K_RIGHT:
+ case K_XRIGHT:
if (!curwin->w_p_wrap)
{
/* scroll the window left */
# 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
&& 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)
{
{
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)
&& 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)
{
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);
+ }
}
/*
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)
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 */
}
*/
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
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
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);
+ }
}
/*
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:
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
/*
}
#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)
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();
{
#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
)
{
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
# 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
&& !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
else
{
found_match = FALSE;
+#if 0
#ifdef HAVE_SETJMP_H
/*
* Matching with a regexp may cause a very deep recursive call of
got_int = TRUE;
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)
if (got_int)
break;
}
+#if 0
#ifdef HAVE_SETJMP_H
jumpend:
mch_endjmp();
+#endif
#endif
if (using_dummy)
* 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().
*(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
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;
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;
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;
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
regline = line;
reglnum = 0;
- out_of_stack = FALSE;
/* Simplest case: Anchored match need be tried only once. */
if (prog->reganch)
else
{
/* Messy cases: unanchored match. */
- while (!got_int && !out_of_stack)
+ while (!got_int)
{
if (prog->regstart != NUL)
{
}
}
- 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)
{
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. */
need_clear_zsubexpr = TRUE;
#endif
- if (regmatch(prog->program + 1, NULL))
+ if (regmatch(prog->program + 1))
{
cleanup_subexpr();
if (REG_MULTI)
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.
* 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();
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)
{
else
{
if (WITH_NL(op))
- op -= ADD_NL;
+ op -= ADD_NL;
#ifdef FEAT_MBYTE
if (has_mbyte)
c = (*mb_ptr2char)(reginput);
{
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:
* 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:
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:
!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. */
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;
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
/* 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
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:
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:
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 */
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( */
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:
case BACKREF + 8:
case BACKREF + 9:
{
- int no;
int len;
linenr_T clnum;
colnr_T ccol;
* 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 */
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
{
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);
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
case ZREF + 8:
case ZREF + 9:
{
- int no;
int len;
cleanup_zsubexpr();
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
{
{
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);
else
{
EMSG(_(e_internal)); /* Shouldn't happen */
- return FALSE;
+ status = RA_FAIL;
}
}
break;
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 */
/* 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
/* 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. */
+ }
}
}
}
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
*/
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;
}
/*
* 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);
}
/*
{(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;*~")},
{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, ""},
{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]"},
"#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
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()
{
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;
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);
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;
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;
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];
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;
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)
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;
}
}
* 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)
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)
# 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
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) */
/*
* 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[]
{
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)
{
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();
i = find_term_bykeys(str);
if (i >= 0)
del_termcode_idx(i);
- add_termcode(name, str, FALSE);
+ add_termcode(name, str, ATC_FROM_TERM);
}
}
}
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
#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 "
/* cursor to window below */
case 'j':
case K_DOWN:
+ case K_XDOWN:
case Ctrl_J:
CHECK_CMDWIN
#ifdef FEAT_VERTSPLIT
/* cursor to window above */
case 'k':
case K_UP:
+ case K_XUP:
case Ctrl_K:
CHECK_CMDWIN
#ifdef FEAT_VERTSPLIT
/* cursor to left window */
case 'h':
case K_LEFT:
+ case K_XLEFT:
case Ctrl_H:
case K_BS:
CHECK_CMDWIN
/* cursor to right window */
case 'l':
case K_RIGHT:
+ case K_XRIGHT:
case Ctrl_L:
CHECK_CMDWIN
win_goto_hor(FALSE, Prenum1);