Skip to content

Commit

Permalink
patch 8.2.3591: no event is triggered when closing a window
Browse files Browse the repository at this point in the history
Problem:    No event is triggered when closing a window.
Solution:   Add the WinClosed event. (Naohiro Ono, closes #9110)
  • Loading branch information
obcat authored and brammool committed Nov 13, 2021
1 parent a0fca17 commit 23beefe
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 4 deletions.
7 changes: 7 additions & 0 deletions runtime/doc/autocmd.txt
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ Name triggered by ~

|WinNew| after creating a new window
|TabNew| after creating a new tab page
|WinClosed| after closing a window
|TabClosed| after closing a tab page
|WinEnter| after entering another window
|WinLeave| before leaving a window
Expand Down Expand Up @@ -1280,6 +1281,12 @@ VimResume When the Vim instance is resumed after being
VimSuspend When the Vim instance is suspended. Only when
CTRL-Z was typed inside Vim, not when the
SIGSTOP or SIGTSTP signal was sent to Vim.
*WinClosed*
WinClosed After closing a window. The pattern is
matched against the |window-ID|. Both
<amatch> and <afile> are set to the
|window-ID|. Non-recursive (event cannot
trigger itself).
*WinEnter*
WinEnter After entering another window. Not done for
the first window, when Vim has just started.
Expand Down
4 changes: 3 additions & 1 deletion src/autocmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ static struct event_name
{"VimLeave", EVENT_VIMLEAVE},
{"VimLeavePre", EVENT_VIMLEAVEPRE},
{"WinNew", EVENT_WINNEW},
{"WinClosed", EVENT_WINCLOSED},
{"WinEnter", EVENT_WINENTER},
{"WinLeave", EVENT_WINLEAVE},
{"VimResized", EVENT_VIMRESIZED},
Expand Down Expand Up @@ -2042,7 +2043,8 @@ apply_autocmds_group(
|| event == EVENT_OPTIONSET
|| event == EVENT_QUICKFIXCMDPOST
|| event == EVENT_DIRCHANGED
|| event == EVENT_MODECHANGED)
|| event == EVENT_MODECHANGED
|| event == EVENT_WINCLOSED)
{
fname = vim_strsave(fname);
autocmd_fname_full = TRUE; // don't expand it later
Expand Down
46 changes: 43 additions & 3 deletions src/testdir/test_autocmd.vim
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ func Test_win_tab_autocmd()

augroup testing
au WinNew * call add(g:record, 'WinNew')
au WinClosed * call add(g:record, 'WinClosed')
au WinEnter * call add(g:record, 'WinEnter')
au WinLeave * call add(g:record, 'WinLeave')
au TabNew * call add(g:record, 'TabNew')
Expand All @@ -286,8 +287,8 @@ func Test_win_tab_autocmd()
call assert_equal([
\ 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter',
\ 'WinLeave', 'WinEnter'
\ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter',
\ 'WinLeave', 'WinClosed', 'WinEnter'
\ ], g:record)

let g:record = []
Expand All @@ -298,7 +299,7 @@ func Test_win_tab_autocmd()
call assert_equal([
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
\ 'TabClosed'
\ 'WinClosed', 'TabClosed'
\ ], g:record)

augroup testing
Expand All @@ -307,6 +308,45 @@ func Test_win_tab_autocmd()
unlet g:record
endfunc

func Test_WinClosed()
" Test that the pattern is matched against the closed window's ID, and both
" <amatch> and <afile> are set to it.
new
let winid = win_getid()
let g:matched = v:false
augroup test-WinClosed
autocmd!
execute 'autocmd WinClosed' winid 'let g:matched = v:true'
autocmd WinClosed * let g:amatch = str2nr(expand('<amatch>'))
autocmd WinClosed * let g:afile = str2nr(expand('<afile>'))
augroup END
close
call assert_true(g:matched)
call assert_equal(winid, g:amatch)
call assert_equal(winid, g:afile)

" Test that WinClosed is non-recursive.
new
new
call assert_equal(3, winnr('$'))
let g:triggered = 0
augroup test-WinClosed
autocmd!
autocmd WinClosed * let g:triggered += 1
autocmd WinClosed * 2 wincmd c
augroup END
close
call assert_equal(1, winnr('$'))
call assert_equal(1, g:triggered)

autocmd! test-WinClosed
augroup! test-WinClosed
unlet g:matched
unlet g:amatch
unlet g:afile
unlet g:triggered
endfunc

func s:AddAnAutocmd()
augroup vimBarTest
au BufReadCmd * echo 'hello'
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3591,
/**/
3590,
/**/
Expand Down
1 change: 1 addition & 0 deletions src/vim.h
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,7 @@ enum auto_event
EVENT_WINENTER, // after entering a window
EVENT_WINLEAVE, // before leaving a window
EVENT_WINNEW, // when entering a new window
EVENT_WINCLOSED, // after closing a window
EVENT_VIMSUSPEND, // before Vim is suspended
EVENT_VIMRESUME, // after Vim is resumed

Expand Down
28 changes: 28 additions & 0 deletions src/window.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ static void win_exchange(long);
static void win_rotate(int, int);
static void win_totop(int size, int flags);
static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
static void trigger_winclosed(win_T *win);
static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp);
static frame_T *win_altframe(win_T *win, tabpage_T *tp);
static tabpage_T *alt_tabpage(void);
Expand Down Expand Up @@ -2566,6 +2567,13 @@ win_close(win_T *win, int free_buf)
if (popup_win_closed(win) && !win_valid(win))
return FAIL;
#endif

// Trigger WinClosed just before starting to free window-related resources.
trigger_winclosed(win);
// autocmd may have freed the window already.
if (!win_valid_any_tab(win))
return OK;

win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, TRUE);

if (only_one_window() && win_valid(win) && win->w_buffer == NULL
Expand Down Expand Up @@ -2710,6 +2718,20 @@ win_close(win_T *win, int free_buf)
return OK;
}

static void
trigger_winclosed(win_T *win)
{
static int recursive = FALSE;
char_u winid[NUMBUFLEN];

if (recursive)
return;
recursive = TRUE;
vim_snprintf((char *)winid, sizeof(winid), "%i", win->w_id);
apply_autocmds(EVENT_WINCLOSED, winid, winid, FALSE, win->w_buffer);
recursive = FALSE;
}

/*
* Close window "win" in tab page "tp", which is not the current tab page.
* This may be the last window in that tab page and result in closing the tab,
Expand All @@ -2731,6 +2753,12 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
&& win->w_buffer->b_locked > 0))
return; // window is already being closed

// Trigger WinClosed just before starting to free window-related resources.
trigger_winclosed(win);
// autocmd may have freed the window already.
if (!win_valid_any_tab(win))
return;

if (win->w_buffer != NULL)
// Close the link to the buffer.
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0,
Expand Down

0 comments on commit 23beefe

Please sign in to comment.