# HG changeset patch # User Bram Moolenaar # Date 1665601205 -7200 # Node ID ffa5492137c3e37d9f4e4bebbb3d5830cb434b1b # Parent a87c6faa01e3605dd9b9f13cf33b2ee26295eb2a patch 9.0.0734: cursor position invalid when scrolling with 'smoothscroll' Commit: https://github.com/vim/vim/commit/2fbabd238a94022c99506e920186a5b6cdf15426 Author: Bram Moolenaar Date: Wed Oct 12 19:53:38 2022 +0100 patch 9.0.0734: cursor position invalid when scrolling with 'smoothscroll' Problem: Cursor position invalid when scrolling with 'smoothscroll' set. (Ernie Rael) Solution: Add w_valid_skipcol and clear flags when it changes. Adjust w_skipcol after moving the cursor. diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -2636,6 +2636,7 @@ beginline(int flags) } curwin->w_set_curswant = TRUE; } + adjust_skipcol(); } /* @@ -2683,6 +2684,7 @@ oneright(void) curwin->w_cursor.col += l; curwin->w_set_curswant = TRUE; + adjust_skipcol(); return OK; } @@ -2742,6 +2744,7 @@ oneleft(void) // character, move to its first byte if (has_mbyte) mb_adjust_cursor(); + adjust_skipcol(); return OK; } diff --git a/src/move.c b/src/move.c --- a/src/move.c +++ b/src/move.c @@ -552,6 +552,16 @@ check_cursor_moved(win_T *wp) |VALID_BOTLINE|VALID_BOTLINE_AP); wp->w_valid_cursor = wp->w_cursor; wp->w_valid_leftcol = wp->w_leftcol; + wp->w_valid_skipcol = wp->w_skipcol; + } + else if (wp->w_skipcol != wp->w_valid_skipcol) + { + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL + |VALID_CHEIGHT|VALID_CROW + |VALID_BOTLINE|VALID_BOTLINE_AP); + wp->w_valid_cursor = wp->w_cursor; + wp->w_valid_leftcol = wp->w_leftcol; + wp->w_valid_skipcol = wp->w_skipcol; } else if (wp->w_cursor.col != wp->w_valid_cursor.col || wp->w_leftcol != wp->w_valid_leftcol @@ -878,7 +888,6 @@ curs_rows(win_T *wp) redraw_for_cursorline(curwin); wp->w_valid |= VALID_CROW|VALID_CHEIGHT; - } /* @@ -1092,6 +1101,11 @@ curs_columns( { width = textwidth + curwin_col_off2(); + // skip columns that are not visible + if (curwin->w_cursor.lnum == curwin->w_topline + && curwin->w_wcol >= curwin->w_skipcol) + curwin->w_wcol -= curwin->w_skipcol; + // long line wrapping, adjust curwin->w_wrow if (curwin->w_wcol >= curwin->w_width) { @@ -1265,10 +1279,12 @@ curs_columns( while (endcol > curwin->w_virtcol) endcol -= width; if (endcol > curwin->w_skipcol) + { + curwin->w_wrow -= (endcol - curwin->w_skipcol) / width; curwin->w_skipcol = endcol; + } } - curwin->w_wrow -= curwin->w_skipcol / width; if (curwin->w_wrow >= curwin->w_height) { // small window, make sure cursor is in it @@ -1302,8 +1318,10 @@ curs_columns( curwin->w_flags &= ~(WFLAG_WCOL_OFF_ADDED + WFLAG_WROW_OFF_ADDED); #endif - // now w_leftcol is valid, avoid check_cursor_moved() thinking otherwise + // now w_leftcol and w_skipcol are valid, avoid check_cursor_moved() + // thinking otherwise curwin->w_valid_leftcol = curwin->w_leftcol; + curwin->w_valid_skipcol = curwin->w_skipcol; curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; } @@ -1772,10 +1790,74 @@ scrollup( col += width2; curwin->w_curswant = col; coladvance(curwin->w_curswant); + + // validate_virtcol() marked various things as valid, but after + // moving the cursor they need to be recomputed + curwin->w_valid &= + ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); } } } +/* + * Called after changing the cursor column: make sure that curwin->w_skipcol is + * valid for 'smoothscroll'. + */ + void +adjust_skipcol(void) +{ + if (!curwin->w_p_wrap + || !curwin->w_p_sms + || curwin->w_cursor.lnum != curwin->w_topline) + return; + + int width1 = curwin->w_width - curwin_col_off(); + int width2 = width1 + curwin_col_off2(); + long so = curwin->w_p_so >= 0 ? curwin->w_p_so : p_so; + int scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; + int scrolled = FALSE; + + validate_virtcol(); + while (curwin->w_skipcol > 0 + && curwin->w_virtcol < curwin->w_skipcol + 3 + scrolloff_cols) + { + // scroll a screen line down + if (curwin->w_skipcol >= width1 + width2) + curwin->w_skipcol -= width2; + else + curwin->w_skipcol -= width1; + redraw_later(UPD_NOT_VALID); + scrolled = TRUE; + validate_virtcol(); + } + if (scrolled) + return; // don't scroll in the other direction now + + int col = curwin->w_virtcol - curwin->w_skipcol + scrolloff_cols; + int row = 0; + if (col >= width1) + { + col -= width1; + ++row; + } + if (col > width2) + { + row += col / width2; + col = col % width2; + } + if (row >= curwin->w_height) + { + if (curwin->w_skipcol == 0) + { + curwin->w_skipcol += width1; + --row; + } + if (row >= curwin->w_height) + curwin->w_skipcol += (row - curwin->w_height) * width2; + redraw_later(UPD_NOT_VALID); + } +} + #ifdef FEAT_DIFF /* * Don't end up with too many filler lines in the window. diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -2448,6 +2448,7 @@ nv_screengo(oparg_T *oap, int dir, long if (atend) curwin->w_curswant = MAXCOL; // stick in the last column + adjust_skipcol(); return retval; } diff --git a/src/proto/move.pro b/src/proto/move.pro --- a/src/proto/move.pro +++ b/src/proto/move.pro @@ -35,6 +35,7 @@ void f_screenpos(typval_T *argvars, typv void f_virtcol2col(typval_T *argvars, typval_T *rettv); void scrolldown(long line_count, int byfold); void scrollup(long line_count, int byfold); +void adjust_skipcol(void); void check_topfill(win_T *wp, int down); void scrolldown_clamp(void); void scrollup_clamp(void); diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -3714,6 +3714,7 @@ struct window_S pos_T w_valid_cursor; // last known position of w_cursor, used // to adjust w_valid colnr_T w_valid_leftcol; // last known w_leftcol + colnr_T w_valid_skipcol; // last known w_skipcol /* * w_cline_height is the number of physical lines taken by the buffer line diff --git a/src/testdir/dumps/Test_smooth_long_8.dump b/src/testdir/dumps/Test_smooth_long_8.dump --- a/src/testdir/dumps/Test_smooth_long_8.dump +++ b/src/testdir/dumps/Test_smooth_long_8.dump @@ -3,4 +3,4 @@ |t|s| |o|f| |t|e|x>t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w -| @21|3|,|1|3|0| @8|B|o|t| +|:|s|e|t| |s|c|r|o|l@1|o| @9|3|,|1|3|0| @8|B|o|t| diff --git a/src/testdir/dumps/Test_smooth_long_9.dump b/src/testdir/dumps/Test_smooth_long_9.dump --- a/src/testdir/dumps/Test_smooth_long_9.dump +++ b/src/testdir/dumps/Test_smooth_long_9.dump @@ -1,6 +1,6 @@ -|<+0#4040ff13#ffffff0@2|o+0#0000000&|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o -|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o -|f| |t|e|x|t| |w|i>t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e +|<+0#4040ff13#ffffff0@2|t+0#0000000&|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t +|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o +|t|s| |o|f| |t|e|x>t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o +|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w -|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| -@22|3|,|1|7|0| @8|B|o|t| +|:|s|e|t| |s|c|r|o|l@1|o| @9|3|,|1|3|0| @8|B|o|t| diff --git a/src/testdir/dumps/Test_smooth_one_long_1.dump b/src/testdir/dumps/Test_smooth_one_long_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_smooth_one_long_1.dump @@ -0,0 +1,6 @@ +>w+0&#ffffff0|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h +| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t +|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f +| |t|e|x|t| @34 +|~+0#4040ff13&| @38 +| +0#0000000&@21|1|,|1| @10|A|l@1| diff --git a/src/testdir/dumps/Test_smooth_one_long_2.dump b/src/testdir/dumps/Test_smooth_one_long_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_smooth_one_long_2.dump @@ -0,0 +1,6 @@ +|<+0#4040ff13#ffffff0@2|t+0#0000000&|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t +>s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f +| |t|e|x|t| @34 +|~+0#4040ff13&| @38 +|~| @38 +| +0#0000000&@21|1|,|8|1| @9|A|l@1| diff --git a/src/testdir/test_scroll_opt.vim b/src/testdir/test_scroll_opt.vim --- a/src/testdir/test_scroll_opt.vim +++ b/src/testdir/test_scroll_opt.vim @@ -248,5 +248,26 @@ func Test_smoothscroll_wrap_long_line() call StopVimInTerminal(buf) endfunc +func Test_smoothscroll_one_long_line() + CheckScreendump + + let lines =<< trim END + vim9script + setline(1, 'with lots of text '->repeat(7)) + set smoothscroll scrolloff=0 + END + call writefile(lines, 'XSmoothOneLong', 'D') + let buf = RunVimInTerminal('-S XSmoothOneLong', #{rows: 6, cols: 40}) + call VerifyScreenDump(buf, 'Test_smooth_one_long_1', {}) + + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_smooth_one_long_2', {}) + + call term_sendkeys(buf, "0") + call VerifyScreenDump(buf, 'Test_smooth_one_long_1', {}) + + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 734, +/**/ 733, /**/ 732,