summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-11-19 21:18:11 +0000
committerBram Moolenaar <Bram@vim.org>2022-11-19 21:18:11 +0000
commit0a60f79fd0c328b47b36279a95282e9f8d9e7512 (patch)
tree770ca1ec430efa0379f9bec4e3b50153d5f23041
parentc896adbcdee8b2296433a61c1f009aae9f68a594 (diff)
downloadvim-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.txt30
-rw-r--r--src/main.c3
-rw-r--r--src/proto/window.pro1
-rw-r--r--src/testdir/dumps/Test_winscrolled_once_only_1.dump10
-rw-r--r--src/testdir/test_autocmd.vim30
-rw-r--r--src/version.c2
-rw-r--r--src/window.c88
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;
}
- }
}
/*