summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authornaohiro ono <obcat@icloud.com>2021-11-13 12:38:49 +0000
committerBram Moolenaar <Bram@vim.org>2021-11-13 12:38:49 +0000
commit23beefed73aadb243fb67cf944e3d60fe8c038bb (patch)
tree8d03d8a6bc3126588a637252bd1a23e53baeaabf /src
parenta0fca17251bf491db7b8d302ce22dee844597e82 (diff)
patch 8.2.3591: no event is triggered when closing a windowv8.2.3591
Problem: No event is triggered when closing a window. Solution: Add the WinClosed event. (Naohiro Ono, closes #9110)
Diffstat (limited to 'src')
-rw-r--r--src/autocmd.c4
-rw-r--r--src/testdir/test_autocmd.vim46
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
-rw-r--r--src/window.c28
5 files changed, 77 insertions, 4 deletions
diff --git a/src/autocmd.c b/src/autocmd.c
index 1704cd4e3a..14cd4af592 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -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},
@@ -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
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 8161183dc8..9eb718f9da 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -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')
@@ -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 = []
@@ -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
@@ -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'
diff --git a/src/version.c b/src/version.c
index e294d8eb51..ca022bf8b3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3591,
+/**/
3590,
/**/
3589,
diff --git a/src/vim.h b/src/vim.h
index 22451c7e47..f86d68d04f 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -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
diff --git a/src/window.c b/src/window.c
index 5de6ed7f53..226d6c1a40 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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);
@@ -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
@@ -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,
@@ -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,