1
0
forked from aniani/vim

patch 8.2.3591: no event is triggered when closing a window

Problem:    No event is triggered when closing a window.
Solution:   Add the WinClosed event. (Naohiro Ono, closes #9110)
This commit is contained in:
naohiro ono 2021-11-13 12:38:49 +00:00 committed by Bram Moolenaar
parent a0fca17251
commit 23beefed73
6 changed files with 84 additions and 4 deletions

View File

@ -348,6 +348,7 @@ Name triggered by ~
|WinNew| after creating a new window |WinNew| after creating a new window
|TabNew| after creating a new tab page |TabNew| after creating a new tab page
|WinClosed| after closing a window
|TabClosed| after closing a tab page |TabClosed| after closing a tab page
|WinEnter| after entering another window |WinEnter| after entering another window
|WinLeave| before leaving a window |WinLeave| before leaving a window
@ -1280,6 +1281,12 @@ VimResume When the Vim instance is resumed after being
VimSuspend When the Vim instance is suspended. Only when VimSuspend When the Vim instance is suspended. Only when
CTRL-Z was typed inside Vim, not when the CTRL-Z was typed inside Vim, not when the
SIGSTOP or SIGTSTP signal was sent to Vim. 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*
WinEnter After entering another window. Not done for WinEnter After entering another window. Not done for
the first window, when Vim has just started. the first window, when Vim has just started.

View File

@ -186,6 +186,7 @@ static struct event_name
{"VimLeave", EVENT_VIMLEAVE}, {"VimLeave", EVENT_VIMLEAVE},
{"VimLeavePre", EVENT_VIMLEAVEPRE}, {"VimLeavePre", EVENT_VIMLEAVEPRE},
{"WinNew", EVENT_WINNEW}, {"WinNew", EVENT_WINNEW},
{"WinClosed", EVENT_WINCLOSED},
{"WinEnter", EVENT_WINENTER}, {"WinEnter", EVENT_WINENTER},
{"WinLeave", EVENT_WINLEAVE}, {"WinLeave", EVENT_WINLEAVE},
{"VimResized", EVENT_VIMRESIZED}, {"VimResized", EVENT_VIMRESIZED},
@ -2042,7 +2043,8 @@ apply_autocmds_group(
|| event == EVENT_OPTIONSET || event == EVENT_OPTIONSET
|| event == EVENT_QUICKFIXCMDPOST || event == EVENT_QUICKFIXCMDPOST
|| event == EVENT_DIRCHANGED || event == EVENT_DIRCHANGED
|| event == EVENT_MODECHANGED) || event == EVENT_MODECHANGED
|| event == EVENT_WINCLOSED)
{ {
fname = vim_strsave(fname); fname = vim_strsave(fname);
autocmd_fname_full = TRUE; // don't expand it later autocmd_fname_full = TRUE; // don't expand it later

View File

@ -270,6 +270,7 @@ func Test_win_tab_autocmd()
augroup testing augroup testing
au WinNew * call add(g:record, 'WinNew') au WinNew * call add(g:record, 'WinNew')
au WinClosed * call add(g:record, 'WinClosed')
au WinEnter * call add(g:record, 'WinEnter') au WinEnter * call add(g:record, 'WinEnter')
au WinLeave * call add(g:record, 'WinLeave') au WinLeave * call add(g:record, 'WinLeave')
au TabNew * call add(g:record, 'TabNew') au TabNew * call add(g:record, 'TabNew')
@ -286,8 +287,8 @@ func Test_win_tab_autocmd()
call assert_equal([ call assert_equal([
\ 'WinLeave', 'WinNew', 'WinEnter', \ 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter',
\ 'WinLeave', 'WinEnter' \ 'WinLeave', 'WinClosed', 'WinEnter'
\ ], g:record) \ ], g:record)
let g:record = [] let g:record = []
@ -298,7 +299,7 @@ func Test_win_tab_autocmd()
call assert_equal([ call assert_equal([
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
\ 'TabClosed' \ 'WinClosed', 'TabClosed'
\ ], g:record) \ ], g:record)
augroup testing augroup testing
@ -307,6 +308,45 @@ func Test_win_tab_autocmd()
unlet g:record unlet g:record
endfunc 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() func s:AddAnAutocmd()
augroup vimBarTest augroup vimBarTest
au BufReadCmd * echo 'hello' au BufReadCmd * echo 'hello'

View File

@ -757,6 +757,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
3591,
/**/ /**/
3590, 3590,
/**/ /**/

View File

@ -1379,6 +1379,7 @@ enum auto_event
EVENT_WINENTER, // after entering a window EVENT_WINENTER, // after entering a window
EVENT_WINLEAVE, // before leaving a window EVENT_WINLEAVE, // before leaving a window
EVENT_WINNEW, // when entering a new window EVENT_WINNEW, // when entering a new window
EVENT_WINCLOSED, // after closing a window
EVENT_VIMSUSPEND, // before Vim is suspended EVENT_VIMSUSPEND, // before Vim is suspended
EVENT_VIMRESUME, // after Vim is resumed EVENT_VIMRESUME, // after Vim is resumed

View File

@ -19,6 +19,7 @@ static void win_exchange(long);
static void win_rotate(int, int); static void win_rotate(int, int);
static void win_totop(int size, int flags); 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 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 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 frame_T *win_altframe(win_T *win, tabpage_T *tp);
static tabpage_T *alt_tabpage(void); static tabpage_T *alt_tabpage(void);
@ -2566,6 +2567,13 @@ win_close(win_T *win, int free_buf)
if (popup_win_closed(win) && !win_valid(win)) if (popup_win_closed(win) && !win_valid(win))
return FAIL; return FAIL;
#endif #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); win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, TRUE);
if (only_one_window() && win_valid(win) && win->w_buffer == NULL if (only_one_window() && win_valid(win) && win->w_buffer == NULL
@ -2710,6 +2718,20 @@ win_close(win_T *win, int free_buf)
return OK; 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. * 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, * This may be the last window in that tab page and result in closing the tab,
@ -2731,6 +2753,12 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
&& win->w_buffer->b_locked > 0)) && win->w_buffer->b_locked > 0))
return; // window is already being closed 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) if (win->w_buffer != NULL)
// Close the link to the buffer. // Close the link to the buffer.
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0,