diff options
-rw-r--r-- | src/nvim/grid.c | 19 | ||||
-rw-r--r-- | test/functional/legacy/scroll_opt_spec.lua | 26 | ||||
-rw-r--r-- | test/old/testdir/test_scroll_opt.vim | 61 |
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()) |