From 14693353d566d126d1e8f28a8e6cbc10e27c09d1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 May 2024 17:46:22 +0800 Subject: vim-patch:9.1.0406: Divide by zero with getmousepos() and 'smoothscroll' (#28701) Problem: Divide by zero with getmousepos() and 'smoothscroll'. Solution: Don't compute skip_lines when width1 is zero. (zeertzjq) closes: vim/vim#14747 https://github.com/vim/vim/commit/031a745608d615d56f9d79bb0f76e2a74b2eaf14 --- src/nvim/mouse.c | 21 +++++++----- src/nvim/move.c | 6 ++-- test/old/testdir/test_functions.vim | 67 +++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 9d30d7d5ab..f393b0fd0f 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -1621,16 +1621,21 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) } 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_inner - 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; + + if (width1 > 0) { + int skip_lines = 0; + + // Adjust for 'smoothscroll' clipping the top screen lines. + // A similar formula is used in curs_columns(). + 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; } - count -= skip_lines; } if (count > row) { diff --git a/src/nvim/move.c b/src/nvim/move.c index 078ce3d72c..66667cecc4 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -1974,11 +1974,13 @@ void scroll_cursor_bot(win_T *wp, int min_scroll, bool set_topbot) // need to scroll the additional clipped lines to scroll past the // top line before we can move on to the other lines. int top_plines = plines_win_nofill(wp, wp->w_topline, false); - int skip_lines = 0; int width1 = wp->w_width_inner - win_col_off(wp); + if (width1 > 0) { int width2 = width1 + win_col_off2(wp); - // similar formula is used in curs_columns() + int skip_lines = 0; + + // A similar formula is used in curs_columns(). if (wp->w_skipcol > width1) { skip_lines += (wp->w_skipcol - width1) / width2 + 1; } else if (wp->w_skipcol > 0) { diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim index ea0e3790cc..7c712818f9 100644 --- a/test/old/testdir/test_functions.vim +++ b/test/old/testdir/test_functions.vim @@ -3399,6 +3399,73 @@ func Test_getmousepos() \ column: 8, \ coladd: 21, \ }, getmousepos()) + + 30vnew + setlocal smoothscroll number + call setline(1, join(range(100))) + exe "normal! \" + call Ntest_setmouse(1, 5) + call assert_equal(#{ + \ screenrow: 1, + \ screencol: 5, + \ winid: win_getid(), + \ winrow: 1, + \ wincol: 5, + \ line: 1, + \ column: 27, + \ coladd: 0, + \ }, getmousepos()) + call Ntest_setmouse(2, 5) + call assert_equal(#{ + \ screenrow: 2, + \ screencol: 5, + \ winid: win_getid(), + \ winrow: 2, + \ wincol: 5, + \ line: 1, + \ column: 53, + \ coladd: 0, + \ }, getmousepos()) + + exe "normal! \" + call Ntest_setmouse(1, 5) + call assert_equal(#{ + \ screenrow: 1, + \ screencol: 5, + \ winid: win_getid(), + \ winrow: 1, + \ wincol: 5, + \ line: 1, + \ column: 53, + \ coladd: 0, + \ }, getmousepos()) + call Ntest_setmouse(2, 5) + call assert_equal(#{ + \ screenrow: 2, + \ screencol: 5, + \ winid: win_getid(), + \ winrow: 2, + \ wincol: 5, + \ line: 1, + \ column: 79, + \ coladd: 0, + \ }, getmousepos()) + + vert resize 4 + call Ntest_setmouse(2, 2) + " This used to crash Vim + call assert_equal(#{ + \ screenrow: 2, + \ screencol: 2, + \ winid: win_getid(), + \ winrow: 2, + \ wincol: 2, + \ line: 1, + \ column: 53, + \ coladd: 0, + \ }, getmousepos()) + + bwipe! bwipe! endfunc -- cgit