Skip to content

Commit 0a60f79

Browse files
committed
patch 9.0.0913: only change in current window triggers the WinScrolled event
Problem: Only a change in the current window triggers the WinScrolled event. Solution: Trigger WinScrolled if any window scrolled or changed size. (issue #11576)
1 parent c896adb commit 0a60f79

7 files changed

Lines changed: 128 additions & 36 deletions

File tree

runtime/doc/autocmd.txt

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,16 +1372,32 @@ WinNew When a new window was created. Not done for
13721372

13731373
*WinScrolled*
13741374
WinScrolled After scrolling the content of a window or
1375-
resizing a window.
1376-
The pattern is matched against the
1377-
|window-ID|. Both <amatch> and <afile> are
1378-
set to the |window-ID|.
1379-
Non-recursive (the event cannot trigger
1380-
itself). However, if the command causes the
1381-
window to scroll or change size another
1375+
resizing a window in the current tab page.
1376+
1377+
When more than one window scrolled or resized
1378+
only one WinScrolled event is triggered. You
1379+
can use the `winlayout()` and `getwininfo()`
1380+
functions to see what changed.
1381+
1382+
The pattern is matched against the |window-ID|
1383+
of the first window that scrolled or resized.
1384+
Both <amatch> and <afile> are set to the
1385+
|window-ID|.
1386+
1387+
Only starts triggering after startup finished
1388+
and the first screen redraw was done.
1389+
1390+
Non-recursive: the event will not trigger
1391+
while executing commands for the WinScrolled
1392+
event. However, if the command causes a
1393+
window to scroll or change size, then another
13821394
WinScrolled event will be triggered later.
1395+
13831396
Does not trigger when the command is added,
13841397
only after the first scroll or resize.
1398+
*E1312*
1399+
It is not allowed to change the window layout
1400+
here (split, close or move windows).
13851401

13861402
==============================================================================
13871403
6. Patterns *autocmd-patterns* *{aupat}*

src/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,9 @@ main_loop(
14691469
time_fd = NULL;
14701470
}
14711471
#endif
1472+
// After the first screen update may start triggering WinScrolled
1473+
// autocmd events. Store all the scroll positions and sizes now.
1474+
may_make_initial_scroll_size_snapshot();
14721475
}
14731476
#ifdef FEAT_GUI
14741477
if (need_mouse_correct)

src/proto/window.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ void curwin_init(void);
1818
void close_windows(buf_T *buf, int keep_curwin);
1919
int one_window(void);
2020
int win_close(win_T *win, int free_buf);
21+
void may_make_initial_scroll_size_snapshot(void);
2122
void may_trigger_winscrolled(void);
2223
void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp);
2324
void win_free_all(void);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
|a+0&#ffffff0@2| @26||+1&&>b+0&&@2| @25
2+
|b@2| @26||+1&&|~+0#4040ff13&| @27
3+
|~| @28||+1#0000000&|~+0#4040ff13&| @27
4+
|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @1|1|,|1| @8|A|l@1|||~+0#4040ff13&| @27
5+
|a+0#0000000&@2| @26||+1&&|~+0#4040ff13&| @27
6+
|b+0#0000000&@2| @26||+1&&|~+0#4040ff13&| @27
7+
|~| @28||+1#0000000&|~+0#4040ff13&| @27
8+
|[+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
9+
|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|,| |[
10+
|'|l|e|a|f|'|,| |1|0@2|]@2| @44

src/testdir/test_autocmd.vim

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,11 +407,38 @@ func Test_WinScrolled_close_curwin()
407407
call TermWait(buf)
408408
call StopVimInTerminal(buf)
409409

410+
" check the startup script finished to the end
410411
call assert_equal(['123456'], readfile('Xtestout'))
411-
412412
call delete('Xtestout')
413413
endfunc
414414

415+
func Test_WinScrolled_once_only()
416+
CheckRunVimInTerminal
417+
418+
let lines =<< trim END
419+
set cmdheight=2
420+
call setline(1, ['aaa', 'bbb'])
421+
let trigger_count = 0
422+
func ShowInfo(id)
423+
echo g:trigger_count g:winid winlayout()
424+
endfunc
425+
426+
vsplit
427+
split
428+
" use a timer to show the info after a redraw
429+
au WinScrolled * let trigger_count += 1 | let winid = expand('<amatch>') | call timer_start(100, 'ShowInfo')
430+
wincmd j
431+
wincmd l
432+
END
433+
call writefile(lines, 'Xtest_winscrolled_once', 'D')
434+
let buf = RunVimInTerminal('-S Xtest_winscrolled_once', #{rows: 10, cols: 60, statusoff: 2})
435+
436+
call term_sendkeys(buf, "\<C-E>")
437+
call VerifyScreenDump(buf, 'Test_winscrolled_once_only_1', {})
438+
439+
call StopVimInTerminal(buf)
440+
endfunc
441+
415442
func Test_WinScrolled_long_wrapped()
416443
CheckRunVimInTerminal
417444

@@ -2916,6 +2943,7 @@ func Test_SpellFileMissing_bwipe()
29162943
call assert_fails('set spell spelllang=0', 'E937:')
29172944

29182945
au! SpellFileMissing
2946+
set nospell spelllang=en
29192947
bwipe
29202948
endfunc
29212949

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ static char *(features[]) =
695695

696696
static int included_patches[] =
697697
{ /* Add new patch number below this line */
698+
/**/
699+
913,
698700
/**/
699701
912,
700702
/**/

src/window.c

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2843,44 +2843,76 @@ trigger_winclosed(win_T *win)
28432843
}
28442844

28452845
/*
2846-
* Trigger WinScrolled for "curwin" if needed.
2846+
* Make a snapshot of all the window scroll positions and sizes of the current
2847+
* tab page.
2848+
*/
2849+
static void
2850+
snapshot_windows_scroll_size(void)
2851+
{
2852+
win_T *wp;
2853+
FOR_ALL_WINDOWS(wp)
2854+
{
2855+
wp->w_last_topline = wp->w_topline;
2856+
wp->w_last_leftcol = wp->w_leftcol;
2857+
wp->w_last_skipcol = wp->w_skipcol;
2858+
wp->w_last_width = wp->w_width;
2859+
wp->w_last_height = wp->w_height;
2860+
}
2861+
}
2862+
2863+
static int did_initial_scroll_size_snapshot = FALSE;
2864+
2865+
void
2866+
may_make_initial_scroll_size_snapshot(void)
2867+
{
2868+
if (!did_initial_scroll_size_snapshot)
2869+
{
2870+
did_initial_scroll_size_snapshot = TRUE;
2871+
snapshot_windows_scroll_size();
2872+
}
2873+
}
2874+
2875+
/*
2876+
* Trigger WinScrolled if any window scrolled or changed size.
28472877
*/
28482878
void
28492879
may_trigger_winscrolled(void)
28502880
{
28512881
static int recursive = FALSE;
28522882

2853-
if (recursive || !has_winscrolled())
2883+
if (recursive
2884+
|| !has_winscrolled()
2885+
|| !did_initial_scroll_size_snapshot)
28542886
return;
28552887

2856-
win_T *wp = curwin;
2857-
if (wp->w_last_topline != wp->w_topline
2858-
|| wp->w_last_leftcol != wp->w_leftcol
2859-
|| wp->w_last_skipcol != wp->w_skipcol
2860-
|| wp->w_last_width != wp->w_width
2861-
|| wp->w_last_height != wp->w_height)
2862-
{
2863-
// "curwin" may be different from the actual current window, make sure
2864-
// it can be restored.
2865-
window_layout_lock();
2866-
2867-
recursive = TRUE;
2868-
char_u winid[NUMBUFLEN];
2869-
vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id);
2870-
apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE, wp->w_buffer);
2871-
recursive = FALSE;
2872-
window_layout_unlock();
2873-
2874-
// an autocmd may close the window, "wp" may be invalid now
2875-
if (win_valid_any_tab(wp))
2888+
win_T *wp;
2889+
FOR_ALL_WINDOWS(wp)
2890+
if (wp->w_last_topline != wp->w_topline
2891+
|| wp->w_last_leftcol != wp->w_leftcol
2892+
|| wp->w_last_skipcol != wp->w_skipcol
2893+
|| wp->w_last_width != wp->w_width
2894+
|| wp->w_last_height != wp->w_height)
28762895
{
2877-
wp->w_last_topline = wp->w_topline;
2878-
wp->w_last_leftcol = wp->w_leftcol;
2879-
wp->w_last_skipcol = wp->w_skipcol;
2880-
wp->w_last_width = wp->w_width;
2881-
wp->w_last_height = wp->w_height;
2896+
// WinScrolled is triggered only once, even when multiple windows
2897+
// scrolled or changed size. Store the current values before
2898+
// triggering the event, if a scroll or resize happens as a side
2899+
// effect then WinScrolled is triggered again later.
2900+
snapshot_windows_scroll_size();
2901+
2902+
// "curwin" may be different from the actual current window, make
2903+
// sure it can be restored.
2904+
window_layout_lock();
2905+
2906+
recursive = TRUE;
2907+
char_u winid[NUMBUFLEN];
2908+
vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id);
2909+
apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE,
2910+
wp->w_buffer);
2911+
recursive = FALSE;
2912+
window_layout_unlock();
2913+
2914+
break;
28822915
}
2883-
}
28842916
}
28852917

28862918
/*

0 commit comments

Comments
 (0)