aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/grid.c19
-rw-r--r--test/functional/legacy/scroll_opt_spec.lua26
-rw-r--r--test/old/testdir/test_scroll_opt.vim61
3 files changed, 98 insertions, 8 deletions
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index aa542c5a2f..f2ceb2ac24 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -500,8 +500,6 @@ static int grid_char_needs_redraw(ScreenGrid *grid, size_t off_from, size_t off_
void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int clear_width,
int rlflag, win_T *wp, int bg_attr, bool wrap)
{
- size_t max_off_from;
- size_t max_off_to;
int col = 0;
bool redraw_next; // redraw_this for next character
bool clear_next = false;
@@ -519,6 +517,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
endcol = grid->cols;
}
+ const size_t max_off_from = (size_t)grid->cols;
grid_adjust(&grid, &row, &coloff);
// Safety check. Avoids clang warnings down the call stack.
@@ -529,8 +528,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
size_t off_from = 0;
size_t off_to = grid->line_offset[row] + (size_t)coloff;
- max_off_from = linebuf_size;
- max_off_to = grid->line_offset[row] + (size_t)grid->cols;
+ const size_t max_off_to = grid->line_offset[row] + (size_t)grid->cols;
// Take care of putting "<<<" on the first line for 'smoothscroll'.
if (topline && wp->w_skipcol > 0
@@ -538,18 +536,23 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
&& *get_showbreak_value(wp) == NUL
// do not overwrite the 'listchars' "precedes" text with "<<<"
&& !(wp->w_p_list && wp->w_p_lcs_chars.prec != 0)) {
- int off = 0;
- int skip = 0;
+ size_t off = 0;
+ size_t skip = 0;
if (wp->w_p_nu && wp->w_p_rnu) {
// do not overwrite the line number, change "123 text" to
// "123>>>xt".
- while (skip < wp->w_width_inner && ascii_isdigit(*linebuf_char[off])) {
+ while (skip < max_off_from && ascii_isdigit(*linebuf_char[off])) {
off++;
skip++;
}
}
- for (int i = 0; i < 3 && i + skip < wp->w_width_inner; i++) {
+ for (size_t i = 0; i < 3 && i + skip < max_off_from; i++) {
+ if (line_off2cells(linebuf_char, off, max_off_from) > 1) {
+ // When the first half of a double-width character is
+ // overwritten, change the second half to a space.
+ schar_from_ascii(linebuf_char[off + 1], ' ');
+ }
schar_from_ascii(linebuf_char[off], '<');
linebuf_attr[off] = HL_ATTR(HLF_AT);
off++;
diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index cd4c2fda8b..3320f96668 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -667,6 +667,32 @@ describe('smoothscroll', function()
screen:expect(s1)
end)
+ -- oldtest: Test_smoothscroll_marker_over_double_width_dump()
+ it('marker is drawn over double-width char correctly', function()
+ screen:try_resize(40, 6)
+ exec([[
+ call setline(1, 'a'->repeat(&columns) .. '口'->repeat(10))
+ setlocal smoothscroll
+ ]])
+ screen:expect([[
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ 口口口口口口口口口口 |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ feed('<C-E>')
+ screen:expect([[
+ <<< 口口口口口口口^口 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ end)
+
-- oldtest: Test_smoothscroll_zero_width()
it("does not divide by zero with a narrow window", function()
screen:try_resize(12, 2)
diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim
index 5ac80764b5..48b8cb301f 100644
--- a/test/old/testdir/test_scroll_opt.vim
+++ b/test/old/testdir/test_scroll_opt.vim
@@ -399,6 +399,67 @@ func Test_smoothscroll_long_line_showbreak()
call StopVimInTerminal(buf)
endfunc
+" Check that 'smoothscroll' marker is drawn over double-width char correctly.
+" Run with multiple encodings.
+func Test_smoothscroll_marker_over_double_width()
+ " Run this in a separate Vim instance to avoid messing up.
+ let after =<< trim [CODE]
+ scriptencoding utf-8
+ call setline(1, 'a'->repeat(&columns) .. '口'->repeat(10))
+ setlocal smoothscroll
+ redraw
+ exe "norm \<C-E>"
+ redraw
+ " Check the chars one by one. Don't check the whole line concatenated.
+ call assert_equal('<', screenstring(1, 1))
+ call assert_equal('<', screenstring(1, 2))
+ call assert_equal('<', screenstring(1, 3))
+ call assert_equal(' ', screenstring(1, 4))
+ call assert_equal('口', screenstring(1, 5))
+ call assert_equal('口', screenstring(1, 7))
+ call assert_equal('口', screenstring(1, 9))
+ call assert_equal('口', screenstring(1, 11))
+ call assert_equal('口', screenstring(1, 13))
+ call assert_equal('口', screenstring(1, 15))
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [CODE]
+
+ let encodings = ['utf-8', 'cp932', 'cp936', 'cp949', 'cp950']
+ if !has('win32')
+ let encodings += ['euc-jp']
+ endif
+ if has('nvim')
+ let encodings = ['utf-8']
+ endif
+ for enc in encodings
+ let msg = 'enc=' .. enc
+ if RunVim([], after, $'--clean --cmd "set encoding={enc}"')
+ call assert_equal([], readfile('Xresult'), msg)
+ endif
+ call delete('Xresult')
+ endfor
+endfunc
+
+" Same as the test above, but check the text actually shown on screen.
+" Only run with UTF-8 encoding.
+func Test_smoothscroll_marker_over_double_width_dump()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, 'a'->repeat(&columns) .. '口'->repeat(10))
+ setlocal smoothscroll
+ END
+ call writefile(lines, 'XSmoothMarkerOverDoubleWidth', 'D')
+ let buf = RunVimInTerminal('-S XSmoothMarkerOverDoubleWidth', #{rows: 6, cols: 40})
+ call VerifyScreenDump(buf, 'Test_smooth_marker_over_double_width_1', {})
+
+ call term_sendkeys(buf, "\<C-E>")
+ call VerifyScreenDump(buf, 'Test_smooth_marker_over_double_width_2', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
func s:check_col_calc(win_col, win_line, buf_col)
call assert_equal(a:win_col, wincol())
call assert_equal(a:win_line, winline())