# HG changeset patch # User Bram Moolenaar # Date 1590785105 -7200 # Node ID 5995db0fe84a88c809e5dc959029cb79da35e06c # Parent c08ee634509281ac0929f1de9fcfdd950d91bc5d patch 8.2.0839: dropping modifier when putting a character back in typeahead Commit: https://github.com/vim/vim/commit/b42c0d54279b1fdb79652db0c84171e213458809 Author: Bram Moolenaar 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) diff --git a/src/getchar.c b/src/getchar.c --- 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; } diff --git a/src/globals.h b/src/globals.h --- 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 diff --git a/src/message.c b/src/message.c --- 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; } diff --git a/src/normal.c b/src/normal.c --- 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 diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro --- 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); diff --git a/src/terminal.c b/src/terminal.c --- 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; diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim --- 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 :echo "hit ctrl-b" + call feedkeys(":ls\", "xt") + call feedkeys("\", "xt") + call assert_match('hit ctrl-b', Screenline(&lines - 1)) + nunmap +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- 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,