changeset 28331:3e707d35d05d v8.2.4691

patch 8.2.4691: solution for <Cmd> in a mapping causes trouble Commit: https://github.com/vim/vim/commit/ca9d8d2cb9fc6b9240f2a74ccd36f9d966488294 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Apr 4 22:09:30 2022 +0100 patch 8.2.4691: solution for <Cmd> in a mapping causes trouble Problem: Solution for <Cmd> in a mapping causes trouble. Solution: Use another solution: put back CTRL-O after reading the <Cmd> sequence.
author Bram Moolenaar <Bram@vim.org>
date Mon, 04 Apr 2022 23:15:03 +0200
parents de5bfa711138
children 609c7fb65969
files src/getchar.c src/version.c
diffstat 2 files changed, 31 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -96,10 +96,6 @@ static void	updatescript(int c);
 static int	vgetorpeek(int);
 static int	inchar(char_u *buf, int maxlen, long wait_time);
 
-// flags for vgetorpeek()
-#define VGOP_ADVANCE	1	// really get the character
-#define VGOP_NO_STUFF	2	// do not use the stuff buffer
-
 /*
  * Free and clear a buffer.
  */
@@ -1724,7 +1720,7 @@ vgetc(void)
 		++allow_keys;
 		did_inc = TRUE;	// mod_mask may change value
 	    }
-	    c = vgetorpeek(VGOP_ADVANCE);
+	    c = vgetorpeek(TRUE);
 	    if (did_inc)
 	    {
 		--no_mapping;
@@ -1742,8 +1738,8 @@ vgetc(void)
 
 		++no_mapping;
 		allow_keys = 0;		// make sure BS is not found
-		c2 = vgetorpeek(VGOP_ADVANCE);	// no mapping for these chars
-		c = vgetorpeek(VGOP_ADVANCE);
+		c2 = vgetorpeek(TRUE);	// no mapping for these chars
+		c = vgetorpeek(TRUE);
 		--no_mapping;
 		allow_keys = save_allow_keys;
 		if (c2 == KS_MODIFIER)
@@ -1766,7 +1762,7 @@ vgetc(void)
 		    int		j;
 
 		    // get menu path, it ends with a <CR>
-		    for (j = 0; (c = vgetorpeek(VGOP_ADVANCE)) != '\r'; )
+		    for (j = 0; (c = vgetorpeek(TRUE)) != '\r'; )
 		    {
 			name[j] = c;
 			if (j < 199)
@@ -1876,7 +1872,7 @@ vgetc(void)
 		buf[0] = c;
 		for (i = 1; i < n; ++i)
 		{
-		    buf[i] = vgetorpeek(VGOP_ADVANCE);
+		    buf[i] = vgetorpeek(TRUE);
 		    if (buf[i] == K_SPECIAL
 #ifdef FEAT_GUI
 			    || (buf[i] == CSI)
@@ -1889,8 +1885,8 @@ vgetc(void)
 			// represents a CSI (0x9B),
 			// or a K_SPECIAL - KS_EXTRA - KE_CSI, which is CSI
 			// too.
-			c = vgetorpeek(VGOP_ADVANCE);
-			if (vgetorpeek(VGOP_ADVANCE) == KE_CSI && c == KS_EXTRA)
+			c = vgetorpeek(TRUE);
+			if (vgetorpeek(TRUE) == KE_CSI && c == KS_EXTRA)
 			    buf[i] = CSI;
 		    }
 		}
@@ -1993,7 +1989,7 @@ vpeekc(void)
 {
     if (old_char != -1)
 	return old_char;
-    return vgetorpeek(0);
+    return vgetorpeek(FALSE);
 }
 
 #if defined(FEAT_TERMRESPONSE) || defined(FEAT_TERMINAL) || defined(PROTO)
@@ -2968,11 +2964,11 @@ vungetc(int c)
  * 3. from the user
  *	This may do a blocking wait if "advance" is TRUE.
  *
- * if "flags & VGOP_ADVANCE" is non-zero (vgetc()):
+ * if "advance" is TRUE (vgetc()):
  *	Really get the character.
  *	KeyTyped is set to TRUE in the case the user typed the key.
  *	KeyStuffed is TRUE if the character comes from the stuff buffer.
- * if "flags & VGOP_ADVANCE" is zero (vpeekc()):
+ * if "advance" is FALSE (vpeekc()):
  *	Just look whether there is a character available.
  *	Return NUL if not.
  *
@@ -2981,9 +2977,8 @@ vungetc(int c)
  * K_SPECIAL and CSI may be escaped, need to get two more bytes then.
  */
     static int
-vgetorpeek(int flags)
+vgetorpeek(int advance)
 {
-    int		advance = flags & VGOP_ADVANCE;
     int		c, c1;
     int		timedout = FALSE;	// waited for more than 1 second
 					// for mapping to complete
@@ -3027,9 +3022,7 @@ vgetorpeek(int flags)
 /*
  * get a character: 1. from the stuffbuffer
  */
-	if (flags & VGOP_NO_STUFF)
-	    c = 0;
-	else if (typeahead_char != 0)
+	if (typeahead_char != 0)
 	{
 	    c = typeahead_char;
 	    if (advance)
@@ -3762,6 +3755,8 @@ getcmdkeycmd(
     int		c2;
     int		cmod = 0;
     int		aborted = FALSE;
+    int		first = TRUE;
+    int		got_ctrl_o = FALSE;
 
     ga_init2(&line_ga, 1, 32);
 
@@ -3777,7 +3772,7 @@ getcmdkeycmd(
 	    break;
 	}
 
-	if (vgetorpeek(0 | VGOP_NO_STUFF) == NUL)
+	if (vgetorpeek(FALSE) == NUL)
 	{
 	    // incomplete <Cmd> is an error, because there is not much the user
 	    // could do in this state.
@@ -3787,13 +3782,22 @@ getcmdkeycmd(
 	}
 
 	// Get one character at a time.
-	c1 = vgetorpeek(VGOP_ADVANCE | VGOP_NO_STUFF);
+	c1 = vgetorpeek(TRUE);
+
+	// do not use Ctrl_O at the start, stuff it back later
+	if (first && c1 == Ctrl_O)
+	{
+	    got_ctrl_o = TRUE;
+	    first = FALSE;
+	    continue;
+	}
+	first = FALSE;
 
 	// Get two extra bytes for special keys
 	if (c1 == K_SPECIAL)
 	{
-	    c1 = vgetorpeek(VGOP_ADVANCE | VGOP_NO_STUFF);
-	    c2 = vgetorpeek(VGOP_ADVANCE | VGOP_NO_STUFF);
+	    c1 = vgetorpeek(TRUE);
+	    c2 = vgetorpeek(TRUE);
 	    if (c1 == KS_MODIFIER)
 	    {
 		cmod = c2;
@@ -3840,6 +3844,8 @@ getcmdkeycmd(
     }
 
     no_mapping--;
+    if (got_ctrl_o)
+	stuffcharReadbuff(Ctrl_O);
 
     if (aborted)
 	ga_clear(&line_ga);
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4691,
+/**/
     4690,
 /**/
     4689,