# HG changeset patch # User Christian Brabandt # Date 1692306902 -7200 # Node ID 0503955dcd343ad5412a01ff2c9fee6cad932104 # Parent 6b08d6935217587210d3d9d23edfe9c412498bc3 patch 9.0.1729: screenpos() wrong when w_skipcol and cpoptions+=n Commit: https://github.com/vim/vim/commit/bfe377b8f2d080e5f85c8cbecf3533456e1d6312 Author: zeertzjq Date: Thu Aug 17 22:58:53 2023 +0200 patch 9.0.1729: screenpos() wrong when w_skipcol and cpoptions+=n Problem: screenpos() wrong result with w_skipcol and cpoptions+=n Solution: Use adjust_plines_for_skipcol() instead of subtracting w_skipcol. closes: #12625 Signed-off-by: Christian Brabandt Co-authored-by: zeertzjq diff --git a/src/drawscreen.c b/src/drawscreen.c --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -1792,7 +1792,8 @@ win_update(win_T *wp) j = wp->w_lines[0].wl_lnum - wp->w_topline; if (j < wp->w_height - 2) // not too far off { - i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); + i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1, + TRUE); #ifdef FEAT_DIFF // insert extra lines for previously invisible filler lines if (wp->w_lines[0].wl_lnum != wp->w_topline) diff --git a/src/misc1.c b/src/misc1.c --- a/src/misc1.c +++ b/src/misc1.c @@ -342,12 +342,13 @@ plines(linenr_T lnum) plines_win( win_T *wp, linenr_T lnum, - int winheight) // when TRUE limit to window height + int limit_winheight) // when TRUE limit to window height { #if defined(FEAT_DIFF) || defined(PROTO) // Check for filler lines above this buffer line. When folded the result // is one line anyway. - return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum); + return plines_win_nofill(wp, lnum, limit_winheight) + + diff_check_fill(wp, lnum); } /* @@ -364,7 +365,7 @@ plines_nofill(linenr_T lnum) plines_win_nofill( win_T *wp, linenr_T lnum, - int winheight) // when TRUE limit to window height + int limit_winheight) // when TRUE limit to window height { #endif int lines; @@ -389,7 +390,7 @@ plines_win_nofill( else lines = plines_win_nofold(wp, lnum); - if (winheight > 0 && lines > wp->w_height) + if (limit_winheight && lines > wp->w_height) return wp->w_height; return lines; } @@ -497,7 +498,7 @@ plines_win_col(win_T *wp, linenr_T lnum, } int -plines_m_win(win_T *wp, linenr_T first, linenr_T last) +plines_m_win(win_T *wp, linenr_T first, linenr_T last, int limit_winheight) { int count = 0; @@ -519,10 +520,11 @@ plines_m_win(win_T *wp, linenr_T first, { #ifdef FEAT_DIFF if (first == wp->w_topline) - count += plines_win_nofill(wp, first, TRUE) + wp->w_topfill; + count += plines_win_nofill(wp, first, limit_winheight) + + wp->w_topfill; else #endif - count += plines_win(wp, first, TRUE); + count += plines_win(wp, first, limit_winheight); ++first; } } diff --git a/src/move.c b/src/move.c --- a/src/move.c +++ b/src/move.c @@ -1356,7 +1356,10 @@ curs_columns( // don't skip more than necessary if (n > p_lines - curwin->w_height + 1) n = p_lines - curwin->w_height + 1; - curwin->w_skipcol = n * width2; + if (n > 0) + curwin->w_skipcol = width1 + (n - 1) * width2; + else + curwin->w_skipcol = 0; } else if (extra == 1) { @@ -1443,7 +1446,6 @@ textpos2screenpos( { colnr_T scol = 0, ccol = 0, ecol = 0; int row = 0; - int rowoff = 0; colnr_T coloff = 0; if (pos->lnum >= wp->w_topline && pos->lnum <= wp->w_botline) @@ -1456,7 +1458,10 @@ textpos2screenpos( is_folded = hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL); #endif - 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); #ifdef FEAT_DIFF // Add filler lines above this buffer line. @@ -1481,32 +1486,30 @@ textpos2screenpos( col += off; width = wp->w_width - 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 && width > 0) { // use same formula as what is used in curs_columns() - rowoff = ((col - wp->w_width) / width + 1); + int rowoff = ((col - wp->w_width) / width + 1); col -= rowoff * width; + row += rowoff; } col -= wp->w_leftcol; if (col >= wp->w_width) col = -1; - if (col >= 0 && row + rowoff <= wp->w_height) + if (col >= 0 && row > 0 && row <= wp->w_height) { coloff = col - scol + wp->w_wincol + 1; row += W_WINROW(wp); } else - // character is left, right or below of the window - row = rowoff = scol = ccol = ecol = 0; + // character is out of the window + row = scol = ccol = ecol = 0; } } - *rowp = row + rowoff; + *rowp = row; *scolp = scol + coloff; *ccolp = ccol + coloff; *ecolp = ecol + coloff; diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -654,7 +654,7 @@ popup_show_curline(win_T *wp) wp->w_topline = wp->w_buffer->b_ml.ml_line_count; while (wp->w_topline < wp->w_cursor.lnum && wp->w_topline < wp->w_buffer->b_ml.ml_line_count - && plines_m_win(wp, wp->w_topline, wp->w_cursor.lnum) + && plines_m_win(wp, wp->w_topline, wp->w_cursor.lnum, TRUE) > wp->w_height) ++wp->w_topline; } diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro --- a/src/proto/misc1.pro +++ b/src/proto/misc1.pro @@ -2,12 +2,12 @@ int get_leader_len(char_u *line, char_u **flags, int backward, int include_space); int get_last_leader_offset(char_u *line, char_u **flags); int plines(linenr_T lnum); -int plines_win(win_T *wp, linenr_T lnum, int winheight); +int plines_win(win_T *wp, linenr_T lnum, int limit_winheight); int plines_nofill(linenr_T lnum); -int plines_win_nofill(win_T *wp, linenr_T lnum, int winheight); +int plines_win_nofill(win_T *wp, linenr_T lnum, int limit_winheight); int plines_win_nofold(win_T *wp, linenr_T lnum); int plines_win_col(win_T *wp, linenr_T lnum, long column); -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, int limit_winheight); int gchar_pos(pos_T *pos); int gchar_cursor(void); void pchar_cursor(int c); diff --git a/src/testdir/test_cursor_func.vim b/src/testdir/test_cursor_func.vim --- a/src/testdir/test_cursor_func.vim +++ b/src/testdir/test_cursor_func.vim @@ -130,38 +130,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 \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)) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1729, +/**/ 1728, /**/ 1727,