changeset 20571:5995db0fe84a v8.2.0839

patch 8.2.0839: dropping modifier when putting a character back in typeahead Commit: https://github.com/vim/vim/commit/b42c0d54279b1fdb79652db0c84171e213458809 Author: Bram Moolenaar <Bram@vim.org> Date: Fri May 29 22:41:41 2020 +0200 patch 8.2.0839: dropping modifier when putting a character back in typeahead Problem: Dropping modifier when putting a character back in typeahead. Solution: Add modifier to ins_char_typebuf(). (closes https://github.com/vim/vim/issues/6158)
author Bram Moolenaar <Bram@vim.org>
date Fri, 29 May 2020 22:45:05 +0200
parents c08ee6345092
children 8dd549c6de33
files src/getchar.c src/globals.h src/message.c src/normal.c src/proto/getchar.pro src/terminal.c src/testdir/test_messages.vim src/version.c
diffstat 8 files changed, 50 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1101,18 +1101,29 @@ ins_typebuf(
  * the char.
  */
     void
-ins_char_typebuf(int c)
+ins_char_typebuf(int c, int modifier)
 {
-    char_u	buf[MB_MAXBYTES + 1];
-    if (IS_SPECIAL(c))
+    char_u	buf[MB_MAXBYTES + 4];
+    int		idx = 0;
+
+    if (modifier != 0)
     {
 	buf[0] = K_SPECIAL;
-	buf[1] = K_SECOND(c);
-	buf[2] = K_THIRD(c);
+	buf[1] = KS_MODIFIER;
+	buf[2] = modifier;
 	buf[3] = NUL;
+	idx = 3;
+    }
+    if (IS_SPECIAL(c))
+    {
+	buf[idx] = K_SPECIAL;
+	buf[idx + 1] = K_SECOND(c);
+	buf[idx + 2] = K_THIRD(c);
+	buf[idx + 3] = NUL;
+	idx += 3;
     }
     else
-	buf[(*mb_char2bytes)(c, buf)] = NUL;
+	buf[(*mb_char2bytes)(c, buf + idx) + idx] = NUL;
     (void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
 }
 
@@ -1640,8 +1651,11 @@ vgetc(void)
     }
     else
     {
-	mod_mask = 0x0;
+	mod_mask = 0;
+	vgetc_mod_mask = 0;
+	vgetc_char = 0;
 	last_recorded_len = 0;
+
 	for (;;)		// this is done twice if there are modifiers
 	{
 	    int did_inc = FALSE;
@@ -1835,9 +1849,15 @@ vgetc(void)
 	    }
 
 	    if (!no_reduce_keys)
+	    {
 		// A modifier was not used for a mapping, apply it to ASCII
 		// keys.  Shift would already have been applied.
+		// Remember the character and mod_mask from before, in some
+		// cases they are put back in the typeahead buffer.
+		vgetc_mod_mask = mod_mask;
+		vgetc_char = c;
 		c = merge_modifyOtherKeys(c);
+	    }
 
 	    break;
 	}
@@ -2192,7 +2212,7 @@ parse_queued_messages(void)
     // If the current window or buffer changed we need to bail out of the
     // waiting loop.  E.g. when a job exit callback closes the terminal window.
     if (curwin->w_id != old_curwin_id || curbuf->b_fnum != old_curbuf_fnum)
-	ins_char_typebuf(K_IGNORE);
+	ins_char_typebuf(K_IGNORE, 0);
 
     --entered;
 }
--- a/src/globals.h
+++ b/src/globals.h
@@ -120,7 +120,12 @@ EXTERN int	screen_Columns INIT(= 0);   /
  * When vgetc() is called, it sets mod_mask to the set of modifiers that are
  * held down based on the MOD_MASK_* symbols that are read first.
  */
-EXTERN int	mod_mask INIT(= 0x0);		// current key modifiers
+EXTERN int	mod_mask INIT(= 0);		// current key modifiers
+
+// The value of "mod_mask" and the unomdified character before calling
+// merge_modifyOtherKeys().
+EXTERN int	vgetc_mod_mask INIT(= 0);
+EXTERN int	vgetc_char INIT(= 0);
 
 /*
  * Cmdline_row is the row where the command line starts, just below the
--- a/src/message.c
+++ b/src/message.c
@@ -1258,7 +1258,7 @@ wait_return(int redraw)
 	{
 	    // Put the character back in the typeahead buffer.  Don't use the
 	    // stuff buffer, because lmaps wouldn't work.
-	    ins_char_typebuf(c);
+	    ins_char_typebuf(vgetc_char, vgetc_mod_mask);
 	    do_redraw = TRUE;	    // need a redraw even though there is
 				    // typeahead
 	}
@@ -3712,7 +3712,7 @@ do_dialog(
 		if (c == ':' && ex_cmd)
 		{
 		    retval = dfltbutton;
-		    ins_char_typebuf(':');
+		    ins_char_typebuf(':', 0);
 		    break;
 		}
 
--- a/src/normal.c
+++ b/src/normal.c
@@ -595,7 +595,7 @@ normal_cmd(
 	// restart automatically.
 	// Insert the typed character in the typeahead buffer, so that it can
 	// be mapped in Insert mode.  Required for ":lmap" to work.
-	ins_char_typebuf(c);
+	ins_char_typebuf(vgetc_char, vgetc_mod_mask);
 	if (restart_edit != 0)
 	    c = 'd';
 	else
--- a/src/proto/getchar.pro
+++ b/src/proto/getchar.pro
@@ -25,7 +25,7 @@ int start_redo_ins(void);
 void stop_redo_ins(void);
 int noremap_keys(void);
 int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, int silent);
-void ins_char_typebuf(int c);
+void ins_char_typebuf(int c, int modifier);
 int typebuf_changed(int tb_change_cnt);
 int typebuf_typed(void);
 int typebuf_maplen(void);
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -3467,7 +3467,7 @@ term_channel_closed(channel_T *ch)
 	redraw_statuslines();
 
 	// Need to break out of vgetc().
-	ins_char_typebuf(K_IGNORE);
+	ins_char_typebuf(K_IGNORE, 0);
 	typebuf_was_filled = TRUE;
 
 	term = curbuf->b_term;
--- a/src/testdir/test_messages.vim
+++ b/src/testdir/test_messages.vim
@@ -2,6 +2,7 @@
 
 source shared.vim
 source term_util.vim
+source view_util.vim
 
 func Test_messages()
   let oldmore = &more
@@ -305,4 +306,12 @@ func Test_null()
   endif
 endfunc
 
+func Test_mapping_at_hit_return_prompt()
+  nnoremap <C-B> :echo "hit ctrl-b"<CR>
+  call feedkeys(":ls\<CR>", "xt")
+  call feedkeys("\<C-B>", "xt")
+  call assert_match('hit ctrl-b', Screenline(&lines - 1))
+  nunmap <C-B>
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    839,
+/**/
     838,
 /**/
     837,