diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4c62dac7d0..4f35df0245 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -9690,6 +9690,10 @@ static void f_win_move_separator(typval_T *argvars, typval_T *rettv, EvalFuncDat if (wp == NULL || wp->w_floating) { return; } + if (!win_valid(wp)) { + emsg(_(e_cannot_resize_window_in_another_tab_page)); + return; + } int offset = (int)tv_get_number(&argvars[1]); win_drag_vsep_line(wp, offset); diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 734ece73b4..56b1af5ff5 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -99,6 +99,15 @@ bool is_mouse_key(int c) || c == K_X2DRAG || c == K_X2RELEASE; } + +static win_T *dragwin = NULL; ///< window being dragged + +/// Reset the window being dragged. To be called when switching tab page. +void reset_dragwin(void) +{ + dragwin = NULL; +} + /// Move the cursor to the specified row and column on the screen. /// Change current window if necessary. Returns an integer with the /// CURSOR_MOVED bit set if the cursor has moved or unset otherwise. @@ -135,7 +144,6 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button) static bool on_winbar = false; static int prev_row = -1; static int prev_col = -1; - static win_T *dragwin = NULL; // window being dragged static int did_drag = false; // drag was noticed win_T *wp, *old_curwin; diff --git a/src/nvim/search.c b/src/nvim/search.c index 336dd50292..dd8952ea3f 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -2610,7 +2610,12 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh len += 2; } - memmove(msgbuf + STRLEN(msgbuf) - len, t, len); + size_t msgbuf_len = STRLEN(msgbuf); + if (len > msgbuf_len) { + len = msgbuf_len; + } + memmove(msgbuf + msgbuf_len - len, t, len); + if (dirc == '?' && stat.cur == maxcount + 1) { stat.cur = -1; } diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index bde3624adf..fd840e46fe 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -1048,6 +1048,30 @@ func Test_mouse_drag_mapped_start_select() set mouse& endfunc +func Test_mouse_drag_statusline() + set laststatus=2 + set mouse=a + func ClickExpr() + call Ntest_setmouse(&lines - 1, 1) + return "\" + endfunc + func DragExpr() + call Ntest_setmouse(&lines - 2, 1) + return "\" + endfunc + nnoremap ClickExpr() + nnoremap DragExpr() + + " this was causing a crash in win_drag_status_line() + call feedkeys("\:tabnew\\", 'tx') + + nunmap + nunmap + delfunc ClickExpr + delfunc DragExpr + set laststatus& mouse& +endfunc + " Test for mapping in Insert mode func Test_mouse_drag_insert_map() set mouse=a diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim index 89e09cf85b..1822a0dce6 100644 --- a/src/nvim/testdir/test_search_stat.vim +++ b/src/nvim/testdir/test_search_stat.vim @@ -262,6 +262,29 @@ func Test_searchcount_fails() call assert_fails('echo searchcount("boo!")', 'E715:') endfunc +func Test_search_stat_narrow_screen() + " This used to crash Vim + let save_columns = &columns + try + let after =<< trim [CODE] + set laststatus=2 + set columns=16 + set shortmess-=S showcmd + call setline(1, 'abc') + call feedkeys("/abc\:quit!\") + autocmd VimLeavePre * call writefile(["done"], "Xdone") + [CODE] + + if !RunVim([], after, '--clean') + return + endif + call assert_equal("done", readfile("Xdone")[0]) + call delete('Xdone') + finally + let &columns = save_columns + endtry +endfunc + func Test_searchcount_in_statusline() CheckScreendump diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim index aebc3bf2f3..3dc9837022 100644 --- a/src/nvim/testdir/test_window_cmd.vim +++ b/src/nvim/testdir/test_window_cmd.vim @@ -1385,17 +1385,20 @@ func Test_win_move_separator() call assert_equal(w0, winwidth(0)) call assert_true(win_move_separator(0, -1)) call assert_equal(w0, winwidth(0)) + " check that win_move_separator doesn't error with offsets beyond moving " possibility call assert_true(win_move_separator(id, 5000)) call assert_true(winwidth(id) > w) call assert_true(win_move_separator(id, -5000)) call assert_true(winwidth(id) < w) + " check that win_move_separator returns false for an invalid window wincmd = let w = winwidth(0) call assert_false(win_move_separator(-1, 1)) call assert_equal(w, winwidth(0)) + " check that win_move_separator returns false for a floating window let id = nvim_open_win( \ 0, 0, #{relative: 'editor', row: 2, col: 2, width: 5, height: 3}) @@ -1403,6 +1406,13 @@ func Test_win_move_separator() call assert_false(win_move_separator(id, 1)) call assert_equal(w, winwidth(id)) call nvim_win_close(id, 1) + + " check that using another tabpage fails without crash + let id = win_getid() + tabnew + call assert_fails('call win_move_separator(id, -1)', 'E1308:') + tabclose + %bwipe! endfunc diff --git a/src/nvim/window.c b/src/nvim/window.c index 6660bb4cc0..f0797cfa38 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4230,6 +4230,8 @@ static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds) return FAIL; } } + + reset_dragwin(); tp->tp_curwin = curwin; tp->tp_prevwin = prevwin; tp->tp_firstwin = firstwin; @@ -4292,6 +4294,10 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a clear_cmdline = true; } + // If there was a click in a window, it won't be usable for a following + // drag. + reset_dragwin(); + // The tabpage line may have appeared or disappeared, may need to resize the frames for that. // When the Vim window was resized or ROWS_AVAIL changed need to update frame sizes too. if (curtab->tp_old_Rows_avail != ROWS_AVAIL || (old_off != firstwin->w_winrow)) {