changeset 27726:d3ed8b1a7bde v8.2.4389

patch 8.2.4389: screenpos() does not handle a position in a closed fold Commit: https://github.com/vim/vim/commit/4556a2e8681c5c98fb4c7ca0a016924a69b4452a Author: Bram Moolenaar <Bram@vim.org> Date: Tue Feb 15 13:40:17 2022 +0000 patch 8.2.4389: screenpos() does not handle a position in a closed fold Problem: screenpos() does not handle a position in a closed fold. Solution: Check if the position is inside a closed fold. (closes https://github.com/vim/vim/issues/9778)
author Bram Moolenaar <Bram@vim.org>
date Tue, 15 Feb 2022 14:45:03 +0100
parents 8c46546e1e2f
children c4306b7b871d
files src/move.c src/testdir/test_cursor_func.vim src/version.c
diffstat 3 files changed, 64 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/src/move.c
+++ b/src/move.c
@@ -1236,39 +1236,54 @@ textpos2screenpos(
 
     if (pos->lnum >= wp->w_topline && pos->lnum <= wp->w_botline)
     {
-	colnr_T off;
-	colnr_T col;
-	int     width;
-
-	row = plines_m_win(wp, wp->w_topline, pos->lnum - 1) + 1;
-	getvcol(wp, pos, &scol, &ccol, &ecol);
-
-	// similar to what is done in validate_cursor_col()
-	col = scol;
-	off = win_col_off(wp);
-	col += off;
-	width = wp->w_width - off + win_col_off2(wp);
+	colnr_T	    off;
+	colnr_T	    col;
+	int	    width;
+	linenr_T    lnum = pos->lnum;
+#ifdef FEAT_FOLDING
+	int	    is_folded;
 
-	// long line wrapping, adjust row
-	if (wp->w_p_wrap
-		&& col >= (colnr_T)wp->w_width
-		&& width > 0)
+	is_folded = hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
+#endif
+	row = plines_m_win(wp, wp->w_topline, lnum - 1) + 1;
+#ifdef FEAT_FOLDING
+	if (is_folded)
 	{
-	    // use same formula as what is used in curs_columns()
-	    rowoff = ((col - wp->w_width) / width + 1);
-	    col -= rowoff * width;
-	}
-	col -= wp->w_leftcol;
-	if (col >= wp->w_width)
-	    col = -1;
-	if (col >= 0 && row + rowoff <= wp->w_height)
-	{
-	    coloff = col - scol + wp->w_wincol + 1;
 	    row += W_WINROW(wp);
+	    coloff = wp->w_wincol + 1;
 	}
 	else
-	    // character is left, right or below of the window
-	    row = rowoff = scol = ccol = ecol = 0;
+#endif
+	{
+	    getvcol(wp, pos, &scol, &ccol, &ecol);
+
+	    // similar to what is done in validate_cursor_col()
+	    col = scol;
+	    off = win_col_off(wp);
+	    col += off;
+	    width = wp->w_width - off + win_col_off2(wp);
+
+	    // 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);
+		col -= rowoff * width;
+	    }
+	    col -= wp->w_leftcol;
+	    if (col >= wp->w_width)
+		col = -1;
+	    if (col >= 0 && row + rowoff <= 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;
+	}
     }
     *rowp = row + rowoff;
     *scolp = scol + coloff;
--- a/src/testdir/test_cursor_func.vim
+++ b/src/testdir/test_cursor_func.vim
@@ -1,5 +1,7 @@
 " Tests for cursor() and other functions that get/set the cursor position
 
+source check.vim
+
 func Test_wrong_arguments()
   call assert_fails('call cursor(1. 3)', 'E474:')
   call assert_fails('call cursor(test_null_list())', 'E474:')
@@ -133,12 +135,27 @@ func Test_screenpos()
   bwipe!
   set display&
 
-  call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+  call assert_equal(#{col: 1, row: 1, endcol: 1, curscol: 1}, screenpos(win_getid(), 1, 1))
   nmenu WinBar.TEST :
-  call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+  call assert_equal(#{col: 1, row: 2, endcol: 1, curscol: 1}, screenpos(win_getid(), 1, 1))
   nunmenu WinBar.TEST
 endfunc
 
+func Test_screenpos_fold()
+  CheckFeature folding
+
+  enew!
+  call setline(1, range(10))
+  3,5fold
+  redraw
+  call assert_equal(2, screenpos(1, 2, 1).row)
+  call assert_equal(#{col: 1, row: 3, endcol: 1, curscol: 1}, screenpos(1, 3, 1))
+  call assert_equal(3, screenpos(1, 4, 1).row)
+  call assert_equal(3, screenpos(1, 5, 1).row)
+  call assert_equal(4, screenpos(1, 6, 1).row)
+  bwipe!
+endfunc
+
 func Test_screenpos_number()
   rightbelow new
   rightbelow 73vsplit
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4389,
+/**/
     4388,
 /**/
     4387,