mirror of
https://github.com/neovim/neovim.git
synced 2026-09-13 17:41:10 +00:00
vim-patch:9.2.1054: Virtual Replace mode: BS over multi-byte text eats the padding (#41799)
Problem: In Virtual Replace mode, backspacing over a character that
replaced several multi-byte characters deletes the padding
that follows it, so the text after the cursor loses its
alignment.
Solution: In replace_do_bs() advance by the length of the character at
the current offset instead of always measuring the first
restored character (Volodymyr Chernetskyi).
After the original characters are restored, replace_do_bs() adds up
their screen width so it knows how much of the alignment padding to drop
again. The loop advanced "i" by mb_ptr2len(p) - 1, which always returns
the length of the *first* restored character rather than the length of
the character at the offset being looked at.
One backspace can restore more than one character, because a wide
character may have replaced several narrow ones. When those characters
do not all have the same byte length the index lands in the middle of a
character: chartabsize() then measures a trailing byte, counts it as an
unprintable <xx> worth four cells, and the inflated width makes the
following loop delete padding spaces that should have been kept.
call setline(1, 'aé xyz')
call feedkeys("gR\u4e00\<BS>\e", 'xt')
leaves "aéxyz" instead of restoring the original line. Going the other
way round ('éa') happens to work, since there the first character is the
longer one.
This has been wrong since the loop was added in Vim 7.0.
closes: vim/vim#21211
5d934b1bdb
Co-authored-by: Volodymyr Chernetskyi <19735328+chernetskyi@users.noreply.github.com>
This commit is contained in:
@@ -2906,7 +2906,7 @@ static void replace_do_bs(int limit_col)
|
||||
int vcol = start_vcol;
|
||||
for (int i = 0; i < ins_len; i++) {
|
||||
vcol += win_chartabsize(curwin, p + i, vcol);
|
||||
i += utfc_ptr2len(p) - 1;
|
||||
i += utfc_ptr2len(p + i) - 1;
|
||||
}
|
||||
vcol -= start_vcol;
|
||||
|
||||
|
||||
@@ -1824,6 +1824,20 @@ func Test_edit_startinsert_in_terminal()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" Backspacing in Virtual Replace mode over a wide character that replaced
|
||||
" several narrower ones must not eat the padding that follows.
|
||||
func Test_edit_vreplace_bs_multibyte()
|
||||
new
|
||||
call setline(1, 'aé xyz')
|
||||
call feedkeys("gR\u4e00\<BS>\e", 'xt')
|
||||
call assert_equal('aé xyz', getline(1))
|
||||
|
||||
call setline(1, 'a€ xyz')
|
||||
call feedkeys("gR\u4e00\<BS>\e", 'xt')
|
||||
call assert_equal('a€ xyz', getline(1))
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" Test for :startreplace and :startgreplace
|
||||
func Test_edit_startreplace()
|
||||
new
|
||||
|
||||
Reference in New Issue
Block a user