summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-03-29 10:11:42 +0100
committerChristian Brabandt <cb@256bit.org>2024-03-29 10:11:42 +0100
commitea95f1a5ad2455c7fd1eee2413ac7a3460ef4f8a (patch)
treea41446bee818e0468f4a2f6f6d000e1cb282f575
parentabedca96efa76db2bba74a5264df632da862203d (diff)
patch 9.1.0227: Recording may still be wrong in Select modev9.1.0227
Problem: Recording may still be wrong in Select mode (after 8.2.3993). Solution: Make sure a character isn't split between two buffer blocks. (zeertzjq) closes: #14326 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/getchar.c68
-rw-r--r--src/testdir/test_registers.vim52
-rw-r--r--src/testdir/test_utf8.vim51
-rw-r--r--src/version.c2
4 files changed, 107 insertions, 66 deletions
diff --git a/src/getchar.c b/src/getchar.c
index 49a24f08b8..179c50c8fa 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1283,35 +1283,72 @@ del_typebuf(int len, int offset)
/*
* Write typed characters to script file.
- * If recording is on put the character in the recordbuffer.
+ * If recording is on put the character in the record buffer.
*/
static void
gotchars(char_u *chars, int len)
{
char_u *s = chars;
- int i;
- static char_u buf[4];
- static int buflen = 0;
+ size_t i;
+ int c = NUL;
+ static int prev_c = NUL;
+ static char_u buf[MB_MAXBYTES * 3 + 4];
+ static size_t buflen = 0;
+ static unsigned pending = 0;
+ static int in_special = FALSE;
+ static int in_mbyte = FALSE;
int todo = len;
- while (todo--)
+ for (; todo--; prev_c = c)
{
- buf[buflen++] = *s++;
+ c = buf[buflen++] = *s++;
+ if (pending > 0)
+ pending--;
// When receiving a special key sequence, store it until we have all
// the bytes and we can decide what to do with it.
- if (buflen == 1 && buf[0] == K_SPECIAL)
- continue;
- if (buflen == 2)
- continue;
- if (buflen == 3 && buf[1] == KS_EXTRA
- && (buf[2] == KE_FOCUSGAINED || buf[2] == KE_FOCUSLOST))
+ if ((pending == 0 || in_mbyte)
+ && (c == K_SPECIAL
+#ifdef FEAT_GUI
+ || c == CSI
+#endif
+ ))
{
- // Drop K_FOCUSGAINED and K_FOCUSLOST, they are not useful in a
- // recording.
- buflen = 0;
+ pending += 2;
+ if (!in_mbyte)
+ in_special = TRUE;
+ }
+
+ if (pending > 0)
continue;
+
+ if (!in_mbyte)
+ {
+ if (in_special)
+ {
+ in_special = FALSE;
+ if (prev_c == KS_MODIFIER)
+ // When receiving a modifier, wait for the modified key.
+ continue;
+ c = TO_SPECIAL(prev_c, c);
+ if (c == K_FOCUSGAINED || c == K_FOCUSLOST)
+ // Drop K_FOCUSGAINED and K_FOCUSLOST, they are not useful
+ // in a recording.
+ buflen = 0;
+ }
+ // When receiving a multibyte character, store it until we have all
+ // the bytes, so that it won't be split between two buffer blocks,
+ // and delete_buff_tail() will work properly.
+ pending = MB_BYTE2LEN_CHECK(c) - 1;
+ if (pending > 0)
+ {
+ in_mbyte = TRUE;
+ continue;
+ }
}
+ else
+ // Stored all bytes of a multibyte character.
+ in_mbyte = FALSE;
// Handle one byte at a time; no translation to be done.
for (i = 0; i < buflen; ++i)
@@ -1326,6 +1363,7 @@ gotchars(char_u *chars, int len)
}
buflen = 0;
}
+
may_sync_undo();
#ifdef FEAT_EVAL
diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim
index cb4cee7d99..cbe6fa6805 100644
--- a/src/testdir/test_registers.vim
+++ b/src/testdir/test_registers.vim
@@ -209,6 +209,58 @@ func Test_recording_with_select_mode()
bwipe!
endfunc
+func Run_test_recording_with_select_mode_utf8()
+ new
+
+ " Test with different text lengths: 5, 7, 9, 11, 13, 15, to check that
+ " a character isn't split between two buffer blocks.
+ for s in ['12345', '口=口', '口口口', '口=口=口', '口口=口口', '口口口口口']
+ " 0x80 is K_SPECIAL
+ " 0x9B is CSI
+ " 哦: 0xE5 0x93 0xA6
+ " 洛: 0xE6 0xB4 0x9B
+ " 固: 0xE5 0x9B 0xBA
+ " 四: 0xE5 0x9B 0x9B
+ " 最: 0xE6 0x9C 0x80
+ " 倒: 0xE5 0x80 0x92
+ " 倀: 0xE5 0x80 0x80
+ for c in ['哦', '洛', '固', '四', '最', '倒', '倀']
+ call setline(1, 'asdf')
+ call feedkeys($"qacc{s}\<Esc>gH{c}\<Esc>q", "tx")
+ call assert_equal(c, getline(1))
+ call assert_equal($"cc{s}\<Esc>gH{c}\<Esc>", @a)
+ call setline(1, 'asdf')
+ normal! @a
+ call assert_equal(c, getline(1))
+
+ " Test with Shift modifier.
+ let shift_c = eval($'"\<S-{c}>"')
+ call setline(1, 'asdf')
+ call feedkeys($"qacc{s}\<Esc>gH{shift_c}\<Esc>q", "tx")
+ call assert_equal(c, getline(1))
+ call assert_equal($"cc{s}\<Esc>gH{shift_c}\<Esc>", @a)
+ call setline(1, 'asdf')
+ normal! @a
+ call assert_equal(c, getline(1))
+ endfor
+ endfor
+
+ bwipe!
+endfunc
+
+func Test_recording_with_select_mode_utf8()
+ call Run_test_recording_with_select_mode_utf8()
+endfunc
+
+" This must be done as one of the last tests, because it starts the GUI, which
+" cannot be undone.
+func Test_zz_recording_with_select_mode_utf8_gui()
+ CheckCanRunGui
+
+ gui -f
+ call Run_test_recording_with_select_mode_utf8()
+endfunc
+
" Test for executing the last used register (@)
func Test_last_used_exec_reg()
" Test for the @: command
diff --git a/src/testdir/test_utf8.vim b/src/testdir/test_utf8.vim
index 3bb7459797..112b5a6e98 100644
--- a/src/testdir/test_utf8.vim
+++ b/src/testdir/test_utf8.vim
@@ -292,55 +292,4 @@ func Test_print_overlong()
bwipe!
endfunc
-func Test_recording_with_select_mode_utf8()
- call Run_test_recording_with_select_mode_utf8()
-endfunc
-
-func Run_test_recording_with_select_mode_utf8()
- new
-
- " No escaping
- call feedkeys("qacc12345\<Esc>gH哦\<Esc>q", "tx")
- call assert_equal("哦", getline(1))
- call assert_equal("cc12345\<Esc>gH哦\<Esc>", @a)
- call setline(1, 'asdf')
- normal! @a
- call assert_equal("哦", getline(1))
-
- " 固 is 0xE5 0x9B 0xBA where 0x9B is CSI
- call feedkeys("qacc12345\<Esc>gH固\<Esc>q", "tx")
- call assert_equal("固", getline(1))
- call assert_equal("cc12345\<Esc>gH固\<Esc>", @a)
- call setline(1, 'asdf')
- normal! @a
- call assert_equal("固", getline(1))
-
- " 四 is 0xE5 0x9B 0x9B where 0x9B is CSI
- call feedkeys("qacc12345\<Esc>gH四\<Esc>q", "tx")
- call assert_equal("四", getline(1))
- call assert_equal("cc12345\<Esc>gH四\<Esc>", @a)
- call setline(1, 'asdf')
- normal! @a
- call assert_equal("四", getline(1))
-
- " 倒 is 0xE5 0x80 0x92 where 0x80 is K_SPECIAL
- call feedkeys("qacc12345\<Esc>gH倒\<Esc>q", "tx")
- call assert_equal("倒", getline(1))
- call assert_equal("cc12345\<Esc>gH倒\<Esc>", @a)
- call setline(1, 'asdf')
- normal! @a
- call assert_equal("倒", getline(1))
-
- bwipe!
-endfunc
-
-" This must be done as one of the last tests, because it starts the GUI, which
-" cannot be undone.
-func Test_zz_recording_with_select_mode_utf8_gui()
- CheckCanRunGui
-
- gui -f
- call Run_test_recording_with_select_mode_utf8()
-endfunc
-
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index b56b6d38dc..7acc24d0d4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 227,
+/**/
226,
/**/
225,