changeset 180:7e70fc748752

updated for version 7.0056
author vimboss
date Sun, 06 Mar 2005 23:38:09 +0000
parents 7fd70926e2e1
children 2aabb26a113f
files runtime/doc/digraph.txt runtime/doc/options.txt runtime/doc/term.txt runtime/filetype.vim src/edit.c src/ex_getln.c src/getchar.c src/globals.h src/keymap.h src/message.c src/misc2.c src/normal.c src/os_mswin.c src/os_unix.c src/quickfix.c src/regexp.c src/term.c src/testdir/test24.in src/testdir/test24.ok src/version.h src/window.c
diffstat 21 files changed, 1205 insertions(+), 640 deletions(-) [+]
line wrap: on
line diff
--- 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 o
 ":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)
--- 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 shor
 	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 shor
 '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 shor
 '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 shor
 	   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*
--- 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'*
--- 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 a
 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
--- 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:
--- 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;
--- 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
 }
 
 /*
--- a/src/globals.h
+++ b/src/globals.h
@@ -1412,9 +1412,11 @@ EXTERN char_u e_nbreadonly[]	INIT(=N_("E
 #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"));
 
--- 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')
--- 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 */
--- 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
--- 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);
+    }
 }
 
 /*
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -2564,9 +2564,11 @@ Messaging_WndProc(HWND hwnd, UINT msg, W
 	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:
--- 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
--- 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)
 	    {
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -2962,8 +2962,6 @@ static int	need_clear_zsubexpr = FALSE;	
 						 * 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_
 	*(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, c
     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
-#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 */
-}
+# ifdef HAVE_TRY_EXCEPT
+#  define USE_TRY_EXCEPT
+# endif
 #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(&regstack, 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;
 	    }
+#endif
 	    else
-#endif
 	    {
-		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;
 		    }
+#endif
 		    else
-#endif
-		    reginput += len;
+			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, &reg_startpos[no], &reg_startp[no]);
-
-		if (regmatch(next, startp))
-		    return TRUE;
-
-		restore_se(&save, &reg_startpos[no], &reg_startp[no]);
-		return FALSE;
+		rp = regstack_push(&regstack, RS_MOPEN, scan, startp);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &reg_startpos[no],
+							     &reg_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(&regstack, 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, &reg_startzpos[no], &reg_startzp[no]);
-
-		if (regmatch(next, startp))
-		    return TRUE;
-
-		restore_se(&save, &reg_startzpos[no], &reg_startzp[no]);
-		return FALSE;
+		rp = regstack_push(&regstack, RS_ZOPEN, scan, startp);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &reg_startzpos[no],
+							     &reg_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, &reg_endpos[no], &reg_endp[no]);
-
-		if (regmatch(next, startp))
-		    return TRUE;
-
-		restore_se(&save, &reg_endpos[no], &reg_endp[no]);
-		return FALSE;
+		rp = regstack_push(&regstack, RS_MCLOSE, scan, startp);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &reg_endpos[no], &reg_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, &reg_endzpos[no], &reg_endzp[no]);
-
-		if (regmatch(next, startp))
-		    return TRUE;
-
-		restore_se(&save, &reg_endzpos[no], &reg_endzp[no]);
-		return FALSE;
+		rp = regstack_push(&regstack, RS_ZCLOSE, scan, startp);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &reg_endzpos[no],
+							      &reg_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(&regstack, 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(&regstack, 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(&regstack, 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(&regstack, 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)
+		{
+		    status = RA_FAIL;
+		    break;
+		}
+		if (rst.minval <= rst.maxval
+			  ? rst.count >= rst.minval : rst.count >= rst.maxval)
 		{
-		    /* Range is the normal way around, use longest match */
-		    while (count >= minval)
+		    /* 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(&regstack, sizeof(regstar_T)) == FAIL)
+			status = RA_FAIL;
+		    else
 		    {
-			/* If it could match, try it. */
-			if (nextb == NUL || *reginput == nextb
-						    || *reginput == nextb_ic)
+			regstack.ga_len += sizeof(regstar_T);
+			rp = regstack_push(&regstack, 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, startp))
-				return TRUE;
-			    reg_restore(&save);
+			    *(((regstar_T *)rp) - 1) = rst;
+			    status = RA_BREAK;	    /* skip the restore bits */
 			}
-			/* 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);
 		    }
 		}
 		else
-		{
-		    /* Range is backwards, use shortest match first.
-		     * Careful: maxval and minval are exchanged! */
-		    if (count < maxval)
-			return FALSE;
-		    for (;;)
-		    {
-			/* If it could work, try it. */
-			if (nextb == NUL || *reginput == nextb
-						    || *reginput == nextb_ic)
-			{
-			    reg_save(&save);
-			    if (regmatch(next, &save))
-				return TRUE;
-			    reg_restore(&save);
-			}
-			/* 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;
+		    status = RA_NOMATCH;
+
 	    }
-	    /* break; Not Reached */
+	    break;
 
 	  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 MATCH:
 	  case SUBPAT:
+	    rp = regstack_push(&regstack, 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(&regstack, 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(&regstack, 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 */
 
     /*
-     * We get here only if there's trouble -- normally "case END" is the
-     * terminating point.
+     * If there is something on the regstack execute the code for the state.
+     * If the state is popped then loop.
      */
-    EMSG(_(e_re_corr));
+    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(&regstack, &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, &reg_startpos[rp->rs_no],
+						  &reg_startp[rp->rs_no]);
+	    regstack_pop(&regstack, &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, &reg_startzpos[rp->rs_no],
+						 &reg_startzp[rp->rs_no]);
+	    regstack_pop(&regstack, &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, &reg_endpos[rp->rs_no],
+						    &reg_endp[rp->rs_no]);
+	    regstack_pop(&regstack, &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, &reg_endzpos[rp->rs_no],
+						   &reg_endzp[rp->rs_no]);
+	    regstack_pop(&regstack, &scan, &startp);
+	    break;
+#endif
+
+	  case RS_BRANCH:
+	    if (status == RA_MATCH)
+		/* this branch matched, use it */
+		regstack_pop(&regstack, &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(&regstack, &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(&regstack, &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(&regstack, &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(&regstack, &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(&regstack, &scan, &startp);
+	    if (status == RA_CONT)
+		scan = regnext(scan);
+	    break;
+
+	  case RS_BEHIND1:
+	    if (status == RA_NOMATCH)
+	    {
+		regstack_pop(&regstack, &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(&regstack, &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(&regstack, &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(&regstack, &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(&regstack, &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;
+
+    /*
+     * If the regstack is empty or something failed we are done.
+     */
+    if (regstack.ga_len == 0 || status == RA_FAIL)
+    {
+	ga_clear(&regstack);
+	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);
 }
 
 /*
--- 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);
 	    }
 	}
     }
index d9640e5f271a25b2fef4e3c13534090aa5cbf5ae..bdcdb4c69256089868476d1ad0948016f6aeb066
GIT binary patch
literal 1156
zc$|%rPjA{l5XE!orF-f}7$hpC5Mmol9igTPZFB9R@h$6AYqP{|jhA|tWJ#6p-u+i>
z43)}ZJ@5Ty7F+XT$_0ldtD&Y3RIcHv5ILkI`^ihfb0F0Mn8;}jd`+{0l#u15CYhi$
zhoa)eg2G*b<|St!)LpGneQ8dm$1<VDs?92;HC;6G=Lp@#^KWr{a~q=>rvfULvDKQ0
zA}uLA7OSFKvf*XrD&*Z^nINei0w<<OwpLrUy*H1(Gv)i>Z{d&B5i0e=*E+hGTEc>G
zva3{+Izy+!Akr0nE5osQvcR9%>wI4k^~SbVR|kILc@M~0qvr$<J<rLFmcPemFV4ZI
z1i#yHr3MFbu-B?)CokT7&l(+g1AH2c6}tY|*h|K=^P!iLy476a?;H;exm*?{)o6Cb
z1*yf=S^ueL_IS=V0?mGr9=iGZ#cT+f4rG>$1(m|?TUXY6eatjo(lL{Nb_#mmG5be4
z$=*1C+O#9-0r5v_^OjCUmqr&bH7tWJ)6vjqA&wz`q@!X+qeC7B5Vb$*Q^RbY+8_M6
z#Z1N;c+$Gm<<2=Ldi0g4-!#}p(XB{spSv$+!@2kGk9f0fah+BqB@q1sUHq>)QU~Lm
RQc+YP1ZfV-E70N7>JL)+bZ`Iw
--- 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
--- 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 "
--- 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);