]> granicus.if.org Git - vim/commitdiff
patch 8.2.3591: no event is triggered when closing a window v8.2.3591
authornaohiro ono <obcat@icloud.com>
Sat, 13 Nov 2021 12:38:49 +0000 (12:38 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 13 Nov 2021 12:38:49 +0000 (12:38 +0000)
Problem:    No event is triggered when closing a window.
Solution:   Add the WinClosed event. (Naohiro Ono, closes #9110)

runtime/doc/autocmd.txt
src/autocmd.c
src/testdir/test_autocmd.vim
src/version.c
src/vim.h
src/window.c

index 6a4edf9039ce862c906abae4c02e3d8077e2dd7d..fdac7daad270b360a28f7f60dfec5c95b4accb21 100644 (file)
@@ -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
@@ -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.
index 1704cd4e3a5c98f7f43abe454a61d04b009716ce..14cd4af592c1cb5b3c6a011ebed2981f55cc9da5 100644 (file)
@@ -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
index 8161183dc8447e718d2d344789686e777e5bd2ed..9eb718f9da4c6de08a925432b3702b9690a4f597 100644 (file)
@@ -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'
index e294d8eb51b9e2c1e3afb62fa96c73369360e16e..ca022bf8b35405bcfc2fb806afc7f2befe6d22b0 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3591,
 /**/
     3590,
 /**/
index 22451c7e479c6cf15ca67afd5135e5580fcf16a3..f86d68d04f8f3aabb58852ce79b05ccc70273f05 100644 (file)
--- 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
 
index 5de6ed7f53d5693ae37b64d13f1a650839fde744..226d6c1a405c34bfb121ca157b709093e101eba9 100644 (file)
@@ -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,