changeset 31154:7e48ddb8b079 v9.0.0911

patch 9.0.0911: with 'smoothscroll' set mouse click position may be wrong Commit: https://github.com/vim/vim/commit/e6392b102151ec69fad232bcf00591230cef8e1c Author: Yee Cheng Chin <ychin.git@gmail.com> Date: Sat Nov 19 14:31:08 2022 +0000 patch 9.0.0911: with 'smoothscroll' set mouse click position may be wrong Problem: With 'smoothscroll' set mouse click position may be wrong. Solution: Adjust computations for w_skipcol. (Yee Cheng Chin, closes https://github.com/vim/vim/issues/11514)
author Bram Moolenaar <Bram@vim.org>
date Sat, 19 Nov 2022 15:45:03 +0100
parents cd02a3926498
children 9173a376f251
files src/mouse.c src/testdir/test_scroll_opt.vim src/version.c
diffstat 3 files changed, 84 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -3034,14 +3034,29 @@ mouse_comp_pos(
 		    row -= win->w_topfill;
 		else
 		    row -= diff_check_fill(win, lnum);
-		count = plines_win_nofill(win, lnum, TRUE);
+		count = plines_win_nofill(win, lnum, FALSE);
 	    }
 	    else
 #endif
-		count = plines_win(win, lnum, TRUE);
+		count = plines_win(win, lnum, FALSE);
 	    if (plines_cache != NULL && cache_idx < Rows)
 		plines_cache[cache_idx] = count;
 	}
+
+	if (win->w_skipcol > 0 && lnum == win->w_topline)
+	{
+	    // Adjust for 'smoothscroll' clipping the top screen lines.
+	    // A similar formula is used in curs_columns().
+	    int width1 = win->w_width - win_col_off(win);
+	    int skip_lines = 0;
+	    if (win->w_skipcol > width1)
+		skip_lines = (win->w_skipcol - width1)
+					    / (width1 + win_col_off2(win)) + 1;
+	    else if (win->w_skipcol > 0)
+		skip_lines = 1;
+	    count -= skip_lines;
+	}
+
 	if (count > row)
 	    break;	// Position is in this buffer line.
 #ifdef FEAT_FOLDING
@@ -3063,8 +3078,10 @@ mouse_comp_pos(
 	if (col < off)
 	    col = off;
 	col += row * (win->w_width - off);
-	// add skip column (for long wrapping line)
-	col += win->w_skipcol;
+
+	// Add skip column for the topline.
+	if (lnum == win->w_topline)
+	    col += win->w_skipcol;
     }
 
     if (!win->w_p_wrap)
--- a/src/testdir/test_scroll_opt.vim
+++ b/src/testdir/test_scroll_opt.vim
@@ -2,6 +2,7 @@
 
 source check.vim
 source screendump.vim
+source mouse.vim
 
 func Test_reset_scroll()
   let scr = &l:scroll
@@ -452,5 +453,65 @@ func Test_smoothscroll_cursor_position()
   bwipeout!
 endfunc
 
+" Test that mouse picking is still accurate when we have smooth scrolled lines
+func Test_smoothscroll_mouse_pos()
+  CheckNotGui
+  CheckUnix
+
+  let save_mouse = &mouse
+  let save_term = &term
+  let save_ttymouse = &ttymouse
+  set mouse=a term=xterm ttymouse=xterm2
+
+  call NewWindow(10, 20)
+  setl smoothscroll wrap
+  " First line will wrap to 3 physical lines. 2nd/3rd lines are short lines.
+  call setline(1, ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "line 2", "line 3"])
+
+  func s:check_mouse_click(row, col, buf_row, buf_col)
+    call MouseLeftClick(a:row, a:col)
+
+    call assert_equal(a:col, wincol())
+    call assert_equal(a:row, winline())
+    call assert_equal(a:buf_row, line('.'))
+    call assert_equal(a:buf_col, col('.'))
+  endfunc
+
+  " Check that clicking without scroll works first.
+  call s:check_mouse_click(3, 5, 1, 45)
+  call s:check_mouse_click(4, 1, 2, 1)
+  call s:check_mouse_click(4, 6, 2, 6)
+  call s:check_mouse_click(5, 1, 3, 1)
+  call s:check_mouse_click(5, 6, 3, 6)
+
+  " Smooth scroll, and checks that this didn't mess up mouse clicking
+  exe "normal \<C-E>"
+  call s:check_mouse_click(2, 5, 1, 45)
+  call s:check_mouse_click(3, 1, 2, 1)
+  call s:check_mouse_click(3, 6, 2, 6)
+  call s:check_mouse_click(4, 1, 3, 1)
+  call s:check_mouse_click(4, 6, 3, 6)
+
+  exe "normal \<C-E>"
+  call s:check_mouse_click(1, 5, 1, 45)
+  call s:check_mouse_click(2, 1, 2, 1)
+  call s:check_mouse_click(2, 6, 2, 6)
+  call s:check_mouse_click(3, 1, 3, 1)
+  call s:check_mouse_click(3, 6, 3, 6)
+
+  " Make a new first line 11 physical lines tall so it's taller than window
+  " height, to test overflow calculations with really long lines wrapping.
+  normal gg
+  call setline(1, "12345678901234567890"->repeat(11))
+  exe "normal 6\<C-E>"
+  call s:check_mouse_click(5, 1, 1, 201)
+  call s:check_mouse_click(6, 1, 2, 1)
+  call s:check_mouse_click(7, 1, 3, 1)
+
+  let &mouse = save_mouse
+  let &term = save_term
+  let &ttymouse = save_ttymouse
+endfunc
+
 
 " vim: shiftwidth=2 sts=2 expandtab
--- 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 */
 /**/
+    911,
+/**/
     910,
 /**/
     909,