vim-patch:8.2.3993: when recording a change in Select mode char appears twice

Problem:    When recording a change in Select mode the first typed character
            appears twice.
Solution:   When putting the character back into typeahead remove it from
            recorded characters. (closes vim/vim#9462)
c88e977862
This commit is contained in:
zeertzjq 2022-01-24 12:46:52 +08:00
parent 7e2ce35e3b
commit 8f1efb018b
3 changed files with 58 additions and 18 deletions

View File

@ -284,9 +284,19 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle
}
}
/*
* Add number "n" to buffer "buf".
*/
/// Delete "slen" bytes from the end of "buf".
/// Only works when it was just added.
static void delete_buff_tail(buffheader_T *buf, int slen)
{
int len = (int)STRLEN(buf->bh_curr->b_str);
if (len >= slen) {
buf->bh_curr->b_str[len - slen] = NUL;
buf->bh_space += (size_t)slen;
}
}
/// Add number "n" to buffer "buf".
static void add_num_buff(buffheader_T *buf, long n)
{
char number[32];
@ -967,31 +977,31 @@ int ins_typebuf(char_u *str, int noremap, int offset, bool nottyped, bool silent
return OK;
}
/*
* Put character "c" back into the typeahead buffer.
* Can be used for a character obtained by vgetc() that needs to be put back.
* Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to
* the char.
*/
void ins_char_typebuf(int c, int modifier)
/// Put character "c" back into the typeahead buffer.
/// Can be used for a character obtained by vgetc() that needs to be put back.
/// Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to
/// the char.
/// @return the length of what was inserted
int ins_char_typebuf(int c, int modifier)
{
char_u buf[MB_MAXBYTES + 4];
int idx = 0;
int len = 0;
if (modifier != 0) {
buf[0] = K_SPECIAL;
buf[1] = KS_MODIFIER;
buf[2] = (char_u)modifier;
buf[3] = NUL;
idx = 3;
len = 3;
}
if (IS_SPECIAL(c)) {
buf[idx] = K_SPECIAL;
buf[idx + 1] = (char_u)K_SECOND(c);
buf[idx + 2] = (char_u)K_THIRD(c);
buf[idx + 3] = NUL;
buf[len] = K_SPECIAL;
buf[len + 1] = (char_u)K_SECOND(c);
buf[len + 2] = (char_u)K_THIRD(c);
buf[len + 3] = NUL;
} else {
char_u *p = buf + idx;
char_u *p = buf + len;
int char_len = utf_char2bytes(c, p);
len += char_len;
// If the character contains K_SPECIAL bytes they need escaping.
for (int i = char_len; --i >= 0; p++) {
if ((uint8_t)(*p) == K_SPECIAL) {
@ -999,11 +1009,13 @@ void ins_char_typebuf(int c, int modifier)
*p++ = K_SPECIAL;
*p++ = KS_SPECIAL;
*p = KE_FILLER;
len += 2;
}
}
*p = NUL;
}
(void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
return len;
}
/// Return TRUE if the typeahead buffer was changed (while waiting for a
@ -1163,6 +1175,18 @@ static void gotchars(const char_u *chars, size_t len)
maptick++;
}
/// 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.
/// Only affects recorded characters.
void ungetchars(int len)
{
if (reg_recording != 0) {
delete_buff_tail(&recordbuff, len);
last_recorded_len -= (size_t)len;
}
}
/*
* Sync undo. Called when typed characters are obtained from the typeahead
* buffer, or when a menu is used.

View File

@ -1010,7 +1010,12 @@ static int normal_execute(VimState *state, int key)
// 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(s->c, mod_mask);
int len = ins_char_typebuf(s->c, mod_mask);
// When recording the character will be recorded again, remove the
// previously recording.
ungetchars(len);
if (restart_edit != 0) {
s->c = 'd';
} else {

View File

@ -121,6 +121,17 @@ func Test_recording_esc_sequence()
endif
endfunc
func Test_recording_with_select_mode()
new
call feedkeys("qacc12345\<Esc>gH98765\<Esc>q", "tx")
call assert_equal("98765", getline(1))
call assert_equal("cc12345\<Esc>gH98765\<Esc>", @a)
call setline(1, 'asdf')
normal! @a
call assert_equal("98765", getline(1))
bwipe!
endfunc
" Test for executing the last used register (@)
func Test_last_used_exec_reg()
" Test for the @: command