diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-08-18 09:01:50 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-18 09:01:50 +0800 |
commit | c54682f75aca8785a4ee9e32b8dc44a1012c3e39 (patch) | |
tree | 4d5e1101aac5deb862885d54c6fca4f11a11ce71 | |
parent | f8afa8023ee032dfb2aa9a6489f51484fb276732 (diff) | |
download | rneovim-c54682f75aca8785a4ee9e32b8dc44a1012c3e39.tar.gz rneovim-c54682f75aca8785a4ee9e32b8dc44a1012c3e39.tar.bz2 rneovim-c54682f75aca8785a4ee9e32b8dc44a1012c3e39.zip |
vim-patch:9.0.1729: screenpos() wrong when w_skipcol and cpoptions+=n (#24773)
Problem: screenpos() wrong result with w_skipcol and cpoptions+=n
Solution: Use adjust_plines_for_skipcol() instead of subtracting
w_skipcol.
closes: vim/vim#12625
https://github.com/vim/vim/commit/bfe377b8f2d080e5f85c8cbecf3533456e1d6312
-rw-r--r-- | src/nvim/drawscreen.c | 2 | ||||
-rw-r--r-- | src/nvim/move.c | 27 | ||||
-rw-r--r-- | src/nvim/plines.c | 38 | ||||
-rw-r--r-- | test/old/testdir/test_cursor_func.vim | 79 |
4 files changed, 91 insertions, 55 deletions
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 73dd584fb1..10180eafc1 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1657,7 +1657,7 @@ static void win_update(win_T *wp, DecorProviders *providers) j = wp->w_lines[0].wl_lnum - wp->w_topline; } if (j < wp->w_grid.rows - 2) { // not too far off - int i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); + int i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1, true); // insert extra lines for previously invisible filler lines if (wp->w_lines[0].wl_lnum != wp->w_topline) { i += win_get_fill(wp, wp->w_lines[0].wl_lnum) - wp->w_old_topfill; diff --git a/src/nvim/move.c b/src/nvim/move.c index 6b49f6d6e1..e7bac3c6f5 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -69,7 +69,7 @@ int adjust_plines_for_skipcol(win_T *wp, int n) if (wp->w_skipcol >= width) { off++; int skip = wp->w_skipcol - width; - width -= win_col_off2(wp); + width += win_col_off2(wp); while (skip >= width) { off++; skip -= width; @@ -996,7 +996,11 @@ void curs_columns(win_T *wp, int may_scroll) if (n > plines - wp->w_height_inner + 1) { n = plines - wp->w_height_inner + 1; } - wp->w_skipcol = n * width2; + if (n > 0) { + curwin->w_skipcol = width1 + (n - 1) * width2; + } else { + curwin->w_skipcol = 0; + } } else if (extra == 1) { // less than 'scrolloff' lines above, decrease skipcol assert(so <= INT_MAX); @@ -1064,7 +1068,6 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, { colnr_T scol = 0, ccol = 0, ecol = 0; int row = 0; - int rowoff = 0; colnr_T coloff = 0; bool visible_row = false; bool is_folded = false; @@ -1072,7 +1075,10 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, linenr_T lnum = pos->lnum; if (lnum >= wp->w_topline && lnum <= wp->w_botline) { is_folded = hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); - row = plines_m_win(wp, wp->w_topline, lnum - 1) + 1; + row = plines_m_win(wp, wp->w_topline, lnum - 1, false) + 1; + // "row" should be the screen line where line "lnum" begins, which can + // be negative if "lnum" is "w_topline" and "w_skipcol" is non-zero. + row = adjust_plines_for_skipcol(wp, row); // Add filler lines above this buffer line. row += lnum == wp->w_topline ? wp->w_topfill : win_get_fill(wp, lnum); visible_row = true; @@ -1098,20 +1104,17 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, col += off; int width = wp->w_width_inner - off + win_col_off2(wp); - if (lnum == wp->w_topline) { - col -= wp->w_skipcol; - } - // long line wrapping, adjust row if (wp->w_p_wrap && col >= (colnr_T)wp->w_width_inner && width > 0) { // use same formula as what is used in curs_columns() - rowoff = visible_row ? ((col - wp->w_width_inner) / width + 1) : 0; + int rowoff = visible_row ? ((col - wp->w_width_inner) / width + 1) : 0; col -= rowoff * width; + row += rowoff; } col -= wp->w_leftcol; - if (col >= 0 && col < wp->w_width_inner && row + rowoff <= wp->w_height_inner) { + if (col >= 0 && col < wp->w_width_inner && row > 0 && row <= wp->w_height_inner) { coloff = col - scol + (local ? 0 : wp->w_wincol + wp->w_wincol_off) + 1; row += local ? 0 : wp->w_winrow + wp->w_winrow_off; } else { @@ -1120,12 +1123,12 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, if (local) { coloff = col < 0 ? -1 : wp->w_width_inner + 1; } else { - row = rowoff = 0; + row = 0; } } } } - *rowp = row + rowoff; + *rowp = row; *scolp = scol + coloff; *ccolp = ccol + coloff; *ecolp = ecol + coloff; diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 6925368cf7..431e4cd8c9 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -35,11 +35,11 @@ /// Return the number of window lines occupied by buffer line "lnum". /// Includes any filler lines. /// -/// @param winheight when true limit to window height -int plines_win(win_T *wp, linenr_T lnum, bool winheight) +/// @param limit_winheight when true limit to window height +int plines_win(win_T *wp, linenr_T lnum, bool limit_winheight) { // Check for filler lines above this buffer line. - return plines_win_nofill(wp, lnum, winheight) + win_get_fill(wp, lnum); + return plines_win_nofill(wp, lnum, limit_winheight) + win_get_fill(wp, lnum); } /// Return the number of filler lines above "lnum". @@ -71,8 +71,8 @@ bool win_may_fill(win_T *wp) /// Return the number of window lines occupied by buffer line "lnum". /// Does not include filler lines. /// -/// @param winheight when true limit to window height -int plines_win_nofill(win_T *wp, linenr_T lnum, bool winheight) +/// @param limit_winheight when true limit to window height +int plines_win_nofill(win_T *wp, linenr_T lnum, bool limit_winheight) { if (!wp->w_p_wrap) { return 1; @@ -88,7 +88,7 @@ int plines_win_nofill(win_T *wp, linenr_T lnum, bool winheight) } const int lines = plines_win_nofold(wp, lnum); - if (winheight && lines > wp->w_height_inner) { + if (limit_winheight && lines > wp->w_height_inner) { return wp->w_height_inner; } return lines; @@ -184,22 +184,22 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column) /// /// XXX: Because of topfill, this only makes sense when lnum >= wp->w_topline. /// -/// @param[in] wp window the line is in -/// @param[in] lnum line number -/// @param[out] nextp if not NULL, the line after a fold -/// @param[out] foldedp if not NULL, whether lnum is on a fold -/// @param[in] cache whether to use the window's cache for folds -/// @param[in] winheight when true limit to window height +/// @param[in] wp window the line is in +/// @param[in] lnum line number +/// @param[out] nextp if not NULL, the line after a fold +/// @param[out] foldedp if not NULL, whether lnum is on a fold +/// @param[in] cache whether to use the window's cache for folds +/// @param[in] limit_winheight when true limit to window height /// /// @return the total number of screen lines int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, bool *const foldedp, - const bool cache, const bool winheight) + const bool cache, const bool limit_winheight) { bool folded = hasFoldingWin(wp, lnum, &lnum, nextp, cache, NULL); if (foldedp != NULL) { *foldedp = folded; } - return ((folded ? 1 : plines_win_nofill(wp, lnum, winheight)) + + return ((folded ? 1 : plines_win_nofill(wp, lnum, limit_winheight)) + (lnum == wp->w_topline ? wp->w_topfill : win_get_fill(wp, lnum))); } @@ -207,19 +207,19 @@ int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, bool *const /// This takes care of both folds and topfill. /// /// XXX: Because of topfill, this only makes sense when first >= wp->w_topline. -/// XXX: This limits the size of each line to current window height. /// -/// @param first first line number -/// @param last last line number +/// @param first first line number +/// @param last last line number +/// @param limit_winheight when true limit each line to window height /// /// @see win_text_height -int plines_m_win(win_T *wp, linenr_T first, linenr_T last) +int plines_m_win(win_T *wp, linenr_T first, linenr_T last, bool limit_winheight) { int count = 0; while (first <= last) { linenr_T next = first; - count += plines_win_full(wp, first, &next, NULL, false, true); + count += plines_win_full(wp, first, &next, NULL, false, limit_winheight); first = next + 1; } return count; diff --git a/test/old/testdir/test_cursor_func.vim b/test/old/testdir/test_cursor_func.vim index e8b30226de..65abbf7c85 100644 --- a/test/old/testdir/test_cursor_func.vim +++ b/test/old/testdir/test_cursor_func.vim @@ -128,38 +128,71 @@ func Test_screenpos() \ winid->screenpos(line('$'), 22)) 1split - normal G$ - redraw - " w_skipcol should be subtracted - call assert_equal({'row': winrow + 0, - \ 'col': wincol + 20 - 1, - \ 'curscol': wincol + 20 - 1, - \ 'endcol': wincol + 20 - 1}, - \ screenpos(win_getid(), line('.'), col('.'))) " w_leftcol should be subtracted setlocal nowrap - normal 050zl$ + normal G050zl$ + redraw call assert_equal({'row': winrow + 0, \ 'col': wincol + 10 - 1, \ 'curscol': wincol + 10 - 1, \ 'endcol': wincol + 10 - 1}, \ screenpos(win_getid(), line('.'), col('.'))) - " w_skipcol should only matter for the topline -" FIXME: This fails because pline_m_win() does not take w_skipcol into -" account. If it does, then other tests fail. -" wincmd + -" setlocal wrap smoothscroll -" call setline(line('$') + 1, 'last line') -" exe "normal \<C-E>G$" -" redraw -" call assert_equal({'row': winrow + 1, -" \ 'col': wincol + 9 - 1, -" \ 'curscol': wincol + 9 - 1, -" \ 'endcol': wincol + 9 - 1}, -" \ screenpos(win_getid(), line('.'), col('.'))) - close + " w_skipcol should be taken into account + setlocal wrap + normal $ + redraw + call assert_equal({'row': winrow + 0, + \ 'col': wincol + 20 - 1, + \ 'curscol': wincol + 20 - 1, + \ 'endcol': wincol + 20 - 1}, + \ screenpos(win_getid(), line('.'), col('.'))) + call assert_equal({'row': 0, 'col': 0, 'curscol': 0, 'endcol': 0}, + \ screenpos(win_getid(), line('.'), col('.') - 20)) + setlocal number + redraw + call assert_equal({'row': winrow + 0, + \ 'col': wincol + 16 - 1, + \ 'curscol': wincol + 16 - 1, + \ 'endcol': wincol + 16 - 1}, + \ screenpos(win_getid(), line('.'), col('.'))) + call assert_equal({'row': 0, 'col': 0, 'curscol': 0, 'endcol': 0}, + \ screenpos(win_getid(), line('.'), col('.') - 16)) + set cpoptions+=n + redraw + call assert_equal({'row': winrow + 0, + \ 'col': wincol + 4 - 1, + \ 'curscol': wincol + 4 - 1, + \ 'endcol': wincol + 4 - 1}, + \ screenpos(win_getid(), line('.'), col('.'))) + call assert_equal({'row': 0, 'col': 0, 'curscol': 0, 'endcol': 0}, + \ screenpos(win_getid(), line('.'), col('.') - 4)) + + wincmd + + call setline(line('$') + 1, 'last line') + setlocal smoothscroll + normal G$ + redraw + call assert_equal({'row': winrow + 1, + \ 'col': wincol + 4 + 9 - 1, + \ 'curscol': wincol + 4 + 9 - 1, + \ 'endcol': wincol + 4 + 9 - 1}, + \ screenpos(win_getid(), line('.'), col('.'))) + set cpoptions-=n + redraw + call assert_equal({'row': winrow + 1, + \ 'col': wincol + 4 + 9 - 1, + \ 'curscol': wincol + 4 + 9 - 1, + \ 'endcol': wincol + 4 + 9 - 1}, + \ screenpos(win_getid(), line('.'), col('.'))) + setlocal nonumber + redraw + call assert_equal({'row': winrow + 1, + \ 'col': wincol + 9 - 1, + \ 'curscol': wincol + 9 - 1, + \ 'endcol': wincol + 9 - 1}, + \ screenpos(win_getid(), line('.'), col('.'))) close call assert_equal({}, screenpos(999, 1, 1)) |