Mercurial > vim
changeset 32750:dfaddd6f039e v9.0.1694
patch 9.0.1694: wrong mapping applied when replaying a char search
Commit: https://github.com/vim/vim/commit/bacc83009bc38c9ba0247aaa22b76d1993d57993
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sat Aug 12 00:09:31 2023 +0200
patch 9.0.1694: wrong mapping applied when replaying a char search
Problem: wrong mapping applied when replaying a char search
Solution: Store a NOP after the ESC
closes: #12708
closes: #6350
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 12 Aug 2023 00:15:04 +0200 |
parents | 6eb2a929432a |
children | 94401c541ea3 |
files | src/getchar.c src/normal.c src/proto/getchar.pro src/testdir/test_registers.vim src/version.c |
diffstat | 5 files changed, 64 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/src/getchar.c +++ b/src/getchar.c @@ -1339,6 +1339,16 @@ gotchars(char_u *chars, int len) } /* + * Record a <Nop> key. + */ + void +gotchars_nop(void) +{ + char_u nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_NOP }; + gotchars(nop_buf, 3); +} + +/* * Undo the last gotchars() for "len" bytes. To be used when putting a typed * character back into the typeahead buffer, thus gotchars() will be called * again. @@ -3656,14 +3666,9 @@ vgetorpeek(int advance) #endif if (timedout && c == ESC) { - char_u nop_buf[3]; - // When recording there will be no timeout. Add a <Nop> after the ESC // to avoid that it forms a key code with following characters. - nop_buf[0] = K_SPECIAL; - nop_buf[1] = KS_EXTRA; - nop_buf[2] = KE_NOP; - gotchars(nop_buf, 3); + gotchars_nop(); } --vgetc_busy;
--- a/src/normal.c +++ b/src/normal.c @@ -543,27 +543,35 @@ normal_cmd_get_more_chars( } } - // When getting a text character and the next character is a - // multi-byte character, it could be a composing character. - // However, don't wait for it to arrive. Also, do enable mapping, - // because if it's put back with vungetc() it's too late to apply - // mapping. - --no_mapping; - while (enc_utf8 && lang && (c = vpeekc()) > 0 - && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) + if (enc_utf8 && lang) { - c = plain_vgetc(); - if (!utf_iscomposing(c)) + // When getting a text character and the next character is a + // multi-byte character, it could be a composing character. + // However, don't wait for it to arrive. Also, do enable mapping, + // because if it's put back with vungetc() it's too late to apply + // mapping. + --no_mapping; + while ((c = vpeekc()) > 0 + && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) { - vungetc(c); // it wasn't, put it back - break; + c = plain_vgetc(); + if (!utf_iscomposing(c)) + { + vungetc(c); // it wasn't, put it back + break; + } + else if (cap->ncharC1 == 0) + cap->ncharC1 = c; + else + cap->ncharC2 = c; } - else if (cap->ncharC1 == 0) - cap->ncharC1 = c; - else - cap->ncharC2 = c; + ++no_mapping; + // Vim may be in a different mode when the user types the next key, + // but when replaying a recording the next key is already in the + // typeahead buffer, so record a <Nop> before that to prevent the + // vpeekc() above from applying wrong mappings when replaying. + gotchars_nop(); } - ++no_mapping; } --no_mapping; --allow_keys;
--- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -30,6 +30,7 @@ int typebuf_changed(int tb_change_cnt); int typebuf_typed(void); int typebuf_maplen(void); void del_typebuf(int len, int offset); +void gotchars_nop(void); void ungetchars(int len); int save_typebuf(void); void save_typeahead(tasave_T *tp);
--- a/src/testdir/test_registers.vim +++ b/src/testdir/test_registers.vim @@ -797,8 +797,9 @@ func Test_record_in_select_mode() bwipe! endfunc -" mapping that ends macro recording should be removed from recorded macro +" A mapping that ends recording should be removed from the recorded register. func Test_end_record_using_mapping() + new call setline(1, 'aaa') nnoremap s q call feedkeys('safas', 'tx') @@ -818,7 +819,10 @@ func Test_end_record_using_mapping() bwipe! endfunc +" Starting a new recording should work immediately after replaying a recording +" that ends with a <Nop> mapping or a character search. func Test_end_reg_executing() + new nnoremap s <Nop> let @a = 's' call feedkeys("@aqaq\<Esc>", 'tx') @@ -836,6 +840,26 @@ func Test_end_reg_executing() bwipe! endfunc +" An operator-pending mode mapping shouldn't be applied to keys typed in +" Insert mode immediately after a character search when replaying. +func Test_replay_charsearch_omap() + CheckFeature timers + + new + call setline(1, 'foo[blah]') + onoremap , k + call timer_start(10, {-> feedkeys(",bar\<Esc>q", 't')}) + call feedkeys('qrct[', 'xt!') + call assert_equal(',bar[blah]', getline(1)) + undo + call assert_equal('foo[blah]', getline(1)) + call feedkeys('@r', 'xt!') + call assert_equal(',bar[blah]', getline(1)) + + ounmap , + bwipe! +endfunc + " This was causing a crash because y_append was ending up being NULL func Test_zero_y_append() " Run in a separate Vim instance because changing 'encoding' may cause