diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-11-19 21:18:11 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-11-19 21:18:11 +0000 |
commit | 0a60f79fd0c328b47b36279a95282e9f8d9e7512 (patch) | |
tree | 770ca1ec430efa0379f9bec4e3b50153d5f23041 | |
parent | c896adbcdee8b2296433a61c1f009aae9f68a594 (diff) | |
download | vim-git-0a60f79fd0c328b47b36279a95282e9f8d9e7512.tar.gz |
patch 9.0.0913: only change in current window triggers the WinScrolled eventv9.0.0913
Problem: Only a change in the current window triggers the WinScrolled
event.
Solution: Trigger WinScrolled if any window scrolled or changed size.
(issue #11576)
-rw-r--r-- | runtime/doc/autocmd.txt | 30 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/proto/window.pro | 1 | ||||
-rw-r--r-- | src/testdir/dumps/Test_winscrolled_once_only_1.dump | 10 | ||||
-rw-r--r-- | src/testdir/test_autocmd.vim | 30 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/window.c | 88 |
7 files changed, 128 insertions, 36 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 5051cc3dc..86ae60f67 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -1372,16 +1372,32 @@ WinNew When a new window was created. Not done for *WinScrolled* WinScrolled After scrolling the content of a window or - resizing a window. - The pattern is matched against the - |window-ID|. Both <amatch> and <afile> are - set to the |window-ID|. - Non-recursive (the event cannot trigger - itself). However, if the command causes the - window to scroll or change size another + resizing a window in the current tab page. + + When more than one window scrolled or resized + only one WinScrolled event is triggered. You + can use the `winlayout()` and `getwininfo()` + functions to see what changed. + + The pattern is matched against the |window-ID| + of the first window that scrolled or resized. + Both <amatch> and <afile> are set to the + |window-ID|. + + Only starts triggering after startup finished + and the first screen redraw was done. + + Non-recursive: the event will not trigger + while executing commands for the WinScrolled + event. However, if the command causes a + window to scroll or change size, then another WinScrolled event will be triggered later. + Does not trigger when the command is added, only after the first scroll or resize. + *E1312* + It is not allowed to change the window layout + here (split, close or move windows). ============================================================================== 6. Patterns *autocmd-patterns* *{aupat}* diff --git a/src/main.c b/src/main.c index 16a47b333..a01331f16 100644 --- a/src/main.c +++ b/src/main.c @@ -1469,6 +1469,9 @@ main_loop( time_fd = NULL; } #endif + // After the first screen update may start triggering WinScrolled + // autocmd events. Store all the scroll positions and sizes now. + may_make_initial_scroll_size_snapshot(); } #ifdef FEAT_GUI if (need_mouse_correct) diff --git a/src/proto/window.pro b/src/proto/window.pro index 5316f95a6..5141b05d4 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -18,6 +18,7 @@ void curwin_init(void); void close_windows(buf_T *buf, int keep_curwin); int one_window(void); int win_close(win_T *win, int free_buf); +void may_make_initial_scroll_size_snapshot(void); void may_trigger_winscrolled(void); void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp); void win_free_all(void); diff --git a/src/testdir/dumps/Test_winscrolled_once_only_1.dump b/src/testdir/dumps/Test_winscrolled_once_only_1.dump new file mode 100644 index 000000000..56d640107 --- /dev/null +++ b/src/testdir/dumps/Test_winscrolled_once_only_1.dump @@ -0,0 +1,10 @@ +|a+0&#ffffff0@2| @26||+1&&>b+0&&@2| @25 +|b@2| @26||+1&&|~+0#4040ff13&| @27 +|~| @28||+1#0000000&|~+0#4040ff13&| @27 +|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @1|1|,|1| @8|A|l@1|||~+0#4040ff13&| @27 +|a+0#0000000&@2| @26||+1&&|~+0#4040ff13&| @27 +|b+0#0000000&@2| @26||+1&&|~+0#4040ff13&| @27 +|~| @28||+1#0000000&|~+0#4040ff13&| @27 +|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @1|1|,|1| @8|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @1|2|,|1| @7|B|o|t +|1+0&&| |1|0@2| |[|'|r|o|w|'|,| |[@1|'|c|o|l|'|,| |[@1|'|l|e|a|f|'|,| |1|0@1|2|]|,| |[|'|l|e|a|f|'|,| |1|0@1|1|]@2|,| |[ +|'|l|e|a|f|'|,| |1|0@2|]@2| @44 diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 637fdb8c8..5d3e0acdb 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -407,11 +407,38 @@ func Test_WinScrolled_close_curwin() call TermWait(buf) call StopVimInTerminal(buf) + " check the startup script finished to the end call assert_equal(['123456'], readfile('Xtestout')) - call delete('Xtestout') endfunc +func Test_WinScrolled_once_only() + CheckRunVimInTerminal + + let lines =<< trim END + set cmdheight=2 + call setline(1, ['aaa', 'bbb']) + let trigger_count = 0 + func ShowInfo(id) + echo g:trigger_count g:winid winlayout() + endfunc + + vsplit + split + " use a timer to show the info after a redraw + au WinScrolled * let trigger_count += 1 | let winid = expand('<amatch>') | call timer_start(100, 'ShowInfo') + wincmd j + wincmd l + END + call writefile(lines, 'Xtest_winscrolled_once', 'D') + let buf = RunVimInTerminal('-S Xtest_winscrolled_once', #{rows: 10, cols: 60, statusoff: 2}) + + call term_sendkeys(buf, "\<C-E>") + call VerifyScreenDump(buf, 'Test_winscrolled_once_only_1', {}) + + call StopVimInTerminal(buf) +endfunc + func Test_WinScrolled_long_wrapped() CheckRunVimInTerminal @@ -2916,6 +2943,7 @@ func Test_SpellFileMissing_bwipe() call assert_fails('set spell spelllang=0', 'E937:') au! SpellFileMissing + set nospell spelllang=en bwipe endfunc diff --git a/src/version.c b/src/version.c index 764c864e2..550588985 100644 --- 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 */ /**/ + 913, +/**/ 912, /**/ 911, diff --git a/src/window.c b/src/window.c index 422f4faba..b5166db6b 100644 --- a/src/window.c +++ b/src/window.c @@ -2843,44 +2843,76 @@ trigger_winclosed(win_T *win) } /* - * Trigger WinScrolled for "curwin" if needed. + * Make a snapshot of all the window scroll positions and sizes of the current + * tab page. + */ + static void +snapshot_windows_scroll_size(void) +{ + win_T *wp; + FOR_ALL_WINDOWS(wp) + { + wp->w_last_topline = wp->w_topline; + wp->w_last_leftcol = wp->w_leftcol; + wp->w_last_skipcol = wp->w_skipcol; + wp->w_last_width = wp->w_width; + wp->w_last_height = wp->w_height; + } +} + +static int did_initial_scroll_size_snapshot = FALSE; + + void +may_make_initial_scroll_size_snapshot(void) +{ + if (!did_initial_scroll_size_snapshot) + { + did_initial_scroll_size_snapshot = TRUE; + snapshot_windows_scroll_size(); + } +} + +/* + * Trigger WinScrolled if any window scrolled or changed size. */ void may_trigger_winscrolled(void) { static int recursive = FALSE; - if (recursive || !has_winscrolled()) + if (recursive + || !has_winscrolled() + || !did_initial_scroll_size_snapshot) return; - win_T *wp = curwin; - if (wp->w_last_topline != wp->w_topline - || wp->w_last_leftcol != wp->w_leftcol - || wp->w_last_skipcol != wp->w_skipcol - || wp->w_last_width != wp->w_width - || wp->w_last_height != wp->w_height) - { - // "curwin" may be different from the actual current window, make sure - // it can be restored. - window_layout_lock(); - - recursive = TRUE; - char_u winid[NUMBUFLEN]; - vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id); - apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE, wp->w_buffer); - recursive = FALSE; - window_layout_unlock(); - - // an autocmd may close the window, "wp" may be invalid now - if (win_valid_any_tab(wp)) + win_T *wp; + FOR_ALL_WINDOWS(wp) + if (wp->w_last_topline != wp->w_topline + || wp->w_last_leftcol != wp->w_leftcol + || wp->w_last_skipcol != wp->w_skipcol + || wp->w_last_width != wp->w_width + || wp->w_last_height != wp->w_height) { - wp->w_last_topline = wp->w_topline; - wp->w_last_leftcol = wp->w_leftcol; - wp->w_last_skipcol = wp->w_skipcol; - wp->w_last_width = wp->w_width; - wp->w_last_height = wp->w_height; + // WinScrolled is triggered only once, even when multiple windows + // scrolled or changed size. Store the current values before + // triggering the event, if a scroll or resize happens as a side + // effect then WinScrolled is triggered again later. + snapshot_windows_scroll_size(); + + // "curwin" may be different from the actual current window, make + // sure it can be restored. + window_layout_lock(); + + recursive = TRUE; + char_u winid[NUMBUFLEN]; + vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id); + apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE, + wp->w_buffer); + recursive = FALSE; + window_layout_unlock(); + + break; } - } } /* |