From 91c192922da0240be5a8eb4045dae6cd968957e9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 20 Nov 2022 21:11:57 +0800 Subject: [PATCH] vim-patch:9.0.0915: WinScrolled may trigger immediately when defined Problem: WinScrolled may trigger immediately when defined. Solution: Initialize the fields in all windows. (closes vim/vim#11582) https://github.com/vim/vim/commit/29967732761d1ffb5592db5f5aa7036f5b52abf1 Co-authored-by: Bram Moolenaar --- src/nvim/autocmd.c | 16 ++++++---- src/nvim/testdir/test_autocmd.vim | 26 +++++++++++++++ src/nvim/window.c | 33 ++++++++++++++------ test/functional/autocmd/winscrolled_spec.lua | 1 + 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 4df14411c5..54fa57c7a0 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1142,13 +1142,17 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group } // Initialize the fields checked by the WinScrolled trigger to - // stop it from firing right after the first autocmd is defined. + // prevent it from firing right after the first autocmd is + // defined. if (event == EVENT_WINSCROLLED && !has_event(EVENT_WINSCROLLED)) { - curwin->w_last_topline = curwin->w_topline; - curwin->w_last_leftcol = curwin->w_leftcol; - curwin->w_last_skipcol = curwin->w_skipcol; - curwin->w_last_width = curwin->w_width; - curwin->w_last_height = curwin->w_height; + tabpage_T *save_curtab = curtab; + FOR_ALL_TABS(tp) { + unuse_tabpage(curtab); + use_tabpage(tp); + snapshot_windows_scroll_size(); + } + unuse_tabpage(curtab); + use_tabpage(save_curtab); } ap->cmds = NULL; diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index bfb4a23f42..3030ecdfa9 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -428,6 +428,32 @@ func Test_WinScrolled_once_only() call StopVimInTerminal(buf) endfunc +" Check that WinScrolled is not triggered immediately when defined and there +" are split windows. +func Test_WinScrolled_not_when_defined() + CheckRunVimInTerminal + + let lines =<< trim END + call setline(1, ['aaa', 'bbb']) + echo 'nothing happened' + func ShowTriggered(id) + echo 'triggered' + endfunc + END + call writefile(lines, 'Xtest_winscrolled_not', 'D') + let buf = RunVimInTerminal('-S Xtest_winscrolled_not', #{rows: 10, cols: 60, statusoff: 2}) + call term_sendkeys(buf, ":split\") + call TermWait(buf) + " use a timer to show the message after redrawing + call term_sendkeys(buf, ":au WinScrolled * call timer_start(100, 'ShowTriggered')\") + call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_1', {}) + + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_2', {}) + + call StopVimInTerminal(buf) +endfunc + func Test_WinScrolled_long_wrapped() CheckRunVimInTerminal diff --git a/src/nvim/window.c b/src/nvim/window.c index 4a451975a4..f25e25e905 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3868,6 +3868,27 @@ void close_others(int message, int forceit) } } +/// Store the relevant window pointers for tab page "tp". To be used before +/// use_tabpage(). +void unuse_tabpage(tabpage_T *tp) +{ + tp->tp_topframe = topframe; + tp->tp_firstwin = firstwin; + tp->tp_lastwin = lastwin; + tp->tp_curwin = curwin; +} + +/// Set the relevant pointers to use tab page "tp". May want to call +/// unuse_tabpage() first. +void use_tabpage(tabpage_T *tp) +{ + curtab = tp; + topframe = curtab->tp_topframe; + firstwin = curtab->tp_firstwin; + lastwin = curtab->tp_lastwin; + curwin = curtab->tp_curwin; +} + // Allocate the first window and put an empty buffer in it. // Only called from main(). void win_alloc_first(void) @@ -3878,11 +3899,8 @@ void win_alloc_first(void) } first_tabpage = alloc_tabpage(); - first_tabpage->tp_topframe = topframe; curtab = first_tabpage; - curtab->tp_firstwin = firstwin; - curtab->tp_lastwin = lastwin; - curtab->tp_curwin = curwin; + unuse_tabpage(first_tabpage); } // Init `aucmd_win`. This can only be done after the first window @@ -4253,10 +4271,7 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a win_T *next_prevwin = tp->tp_prevwin; tabpage_T *old_curtab = curtab; - curtab = tp; - firstwin = tp->tp_firstwin; - lastwin = tp->tp_lastwin; - topframe = tp->tp_topframe; + use_tabpage(tp); if (old_curtab != curtab) { tabpage_check_windows(old_curtab); @@ -5265,7 +5280,7 @@ void win_new_screen_cols(void) /// Make a snapshot of all the window scroll positions and sizes of the current /// tab page. -static void snapshot_windows_scroll_size(void) +void snapshot_windows_scroll_size(void) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { wp->w_last_topline = wp->w_topline; diff --git a/test/functional/autocmd/winscrolled_spec.lua b/test/functional/autocmd/winscrolled_spec.lua index 6db2d53bbf..cd9c6dd168 100644 --- a/test/functional/autocmd/winscrolled_spec.lua +++ b/test/functional/autocmd/winscrolled_spec.lua @@ -104,6 +104,7 @@ describe('WinScrolled', function() let g:scrolled = 0 au WinScrolled * let g:scrolled += 1 ]]) + eq(0, eval('g:scrolled')) -- With the upper split focused, send a scroll-down event to the unfocused one. meths.input_mouse('wheel', 'down', '', 0, 6, 0)