From bacc83009bc38c9ba0247aaa22b76d1993d57993 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 12 Aug 2023 00:09:31 +0200 Subject: 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 Co-authored-by: zeertzjq --- src/getchar.c | 17 +++++++++++------ src/normal.c | 42 +++++++++++++++++++++++++----------------- src/proto/getchar.pro | 1 + src/testdir/test_registers.vim | 26 +++++++++++++++++++++++++- src/version.c | 2 ++ 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/getchar.c b/src/getchar.c index c5ccdf2e0e..6867b59ed7 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -1338,6 +1338,16 @@ gotchars(char_u *chars, int len) ++maptick; } +/* + * Record a 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 @@ -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 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; diff --git a/src/normal.c b/src/normal.c index 1aad0b1b3a..2eb2c3841a 100644 --- 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 before that to prevent the + // vpeekc() above from applying wrong mappings when replaying. + gotchars_nop(); } - ++no_mapping; } --no_mapping; --allow_keys; diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro index 01746cf700..7e05870a97 100644 --- 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); diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim index 46142d681b..e8bee99d74 100644 --- 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 mapping or a character search. func Test_end_reg_executing() + new nnoremap s let @a = 's' call feedkeys("@aqaq\", '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\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 diff --git a/src/version.c b/src/version.c index 15368d255c..b612dc78ac 100644 --- a/src/version.c +++ b/src/version.c @@ -695,6 +695,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1694, /**/ 1693, /**/ -- cgit v1.2.3