]> granicus.if.org Git - vim/commitdiff
patch 9.0.0913: only change in current window triggers the WinScrolled event v9.0.0913
authorBram Moolenaar <Bram@vim.org>
Sat, 19 Nov 2022 21:18:11 +0000 (21:18 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 19 Nov 2022 21:18:11 +0000 (21:18 +0000)
Problem:    Only a change in the current window triggers the WinScrolled
            event.
Solution:   Trigger WinScrolled if any window scrolled or changed size.
            (issue #11576)

runtime/doc/autocmd.txt
src/main.c
src/proto/window.pro
src/testdir/dumps/Test_winscrolled_once_only_1.dump [new file with mode: 0644]
src/testdir/test_autocmd.vim
src/version.c
src/window.c

index 5051cc3dc09accb8f631a18568fd193fd520f252..86ae60f67d99b87ae0c2a338b3a7e350a3caa36c 100644 (file)
@@ -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}*
index 16a47b33332cd9061137b4e36e6b45b7db682e59..a01331f16389a87d25dc24eab371321f1374185a 100644 (file)
@@ -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)
index 5316f95a6199ba189d892bbc292abd912ab9082a..5141b05d43f9e497733037a31491a5bbea607a6b 100644 (file)
@@ -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 (file)
index 0000000..56d6401
--- /dev/null
@@ -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
index 637fdb8c8e5d441720cdc8359c9e254cefe506c9..5d3e0acdbe2d6974632194c435df93f215ee7a45 100644 (file)
@@ -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
 
index 764c864e24e6d8b6f267e9a4fd1ae13f3b7f0938..5505889850d4a15ec387a561241c9f3fe6fcfba3 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    913,
 /**/
     912,
 /**/
index 422f4fabae28037b9475370dbcb62df126f03d9a..b5166db6b8c790739621b4cf7ecb98b1ef431deb 100644 (file)
@@ -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;
        }
-    }
 }
 
 /*