Commit: patch 9.1.1211: TabClosedPre is triggered just before the tab is being freed

2 views
Skip to first unread message

Christian Brabandt

unread,
Mar 16, 2025, 3:30:11 PM3/16/25
to vim...@googlegroups.com
patch 9.1.1211: TabClosedPre is triggered just before the tab is being freed

Commit: https://github.com/vim/vim/commit/bcf66e014141982192e2743829bceef60ce77727
Author: Jim Zhou <jimzh...@gmail.com>
Date: Sun Mar 16 20:24:57 2025 +0100

patch 9.1.1211: TabClosedPre is triggered just before the tab is being freed

Problem: TabClosedPre is triggered just before the tab is being freed,
which limited its functionality.
Solution: Trigger it a bit earlier and also on :tabclose and :tabonly
(Jim Zhou)

closes: #16890

Signed-off-by: Jim Zhou <jimzh...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 443883490..80ec8a1a6 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -6536,6 +6536,8 @@ tabpage_close(int forceit)
if (window_layout_locked(CMD_tabclose))
return;

+ trigger_tabclosedpre(curtab, TRUE);
+
// First close all the windows but the current one. If that worked then
// close the last window in this tab, that will close it.
if (!ONE_WINDOW)
@@ -6559,6 +6561,8 @@ tabpage_close_other(tabpage_T *tp, int forceit)
int done = 0;
win_T *wp;

+ trigger_tabclosedpre(tp, TRUE);
+
// Limit to 1000 windows, autocommands may add a window while we close
// one. OK, so I'm paranoid...
while (++done < 1000)
diff --git a/src/proto/window.pro b/src/proto/window.pro
index 9a2661d96..f1e129d6e 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -102,4 +102,5 @@ int get_tab_number(tabpage_T *tp);
char *check_colorcolumn(char_u *cc, win_T *wp);
int get_last_winid(void);
int win_locked(win_T *wp);
+void trigger_tabclosedpre(tabpage_T *tp, int directly);
/* vim: set ft=c : */
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 138b852f0..2519e60a1 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -5109,7 +5109,7 @@ func Test_autocmd_tabclosedpre()
call ClearAutomcdAndCreateTabs()
au TabClosedPre * tabmove 0
tabclose
- call assert_equal('1Z2A3>B', GetTabs())
+ call assert_equal('1>Z2A3B', GetTabs())
call ClearAutomcdAndCreateTabs()
au TabClosedPre * tabmove 0
tabclose 1
@@ -5137,7 +5137,33 @@ func Test_autocmd_tabclosedpre()
au TabClosedPre * new X | new Y | new Z
call assert_fails('tabclose 1', 'E242')

+ " Test directly closing the tab page with ':tabclose'
+ au!
+ tabonly
+ bw!
+ e Z
+ au TabClosedPre * mksession!
+ tabnew A
+ sp
+ tabclose
+ source Session.vim
+ call assert_equal('1Z2>AA', GetTabs())
+
+ " Test directly closing the tab page with ':tabonly'
+ " Z is closed before A. Hence A overwrites the session.
+ au!
+ tabonly
+ bw!
+ e Z
+ au TabClosedPre * mksession!
+ tabnew A
+ tabnew B
+ tabonly
+ source Session.vim
+ call assert_equal('1>A2B', GetTabs())
+
" Clean up
+ call delete('Session.vim')
au!
only
tabonly
diff --git a/src/version.c b/src/version.c
index d293eba6a..812941804 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1211,
/**/
1210,
/**/
diff --git a/src/window.c b/src/window.c
index cce7f4c79..55168d53f 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2978,10 +2978,15 @@ trigger_winclosed(win_T *win)
recursive = FALSE;
}

- static void
-trigger_tabclosedpre(tabpage_T *tp)
+/*
+ * directly is TRUE if the window is closed by ':tabclose' or ':tabonly'.
+ * This allows saving the session before closing multi-window tab.
+ */
+ void
+trigger_tabclosedpre(tabpage_T *tp, int directly)
{
static int recursive = FALSE;
+ static int skip = FALSE;
tabpage_T *ptp = curtab;

// Quickly return when no TabClosedPre autocommands to be executed or
@@ -2989,8 +2994,19 @@ trigger_tabclosedpre(tabpage_T *tp)
if (!has_tabclosedpre() || recursive)
return;

+ // Skip if the event have been triggered by ':tabclose' recently
+ if (skip)
+ {
+ skip = FALSE;
+ return;
+ }
+
if (valid_tabpage(tp))
+ {
goto_tabpage_tp(tp, FALSE, FALSE);
+ if (directly)
+ skip = TRUE;
+ }
recursive = TRUE;
window_layout_lock();
apply_autocmds(EVENT_TABCLOSEDPRE, NULL, NULL, FALSE, NULL);
@@ -3382,7 +3398,7 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)

if (tp->tp_firstwin == tp->tp_lastwin)
{
- trigger_tabclosedpre(tp);
+ trigger_tabclosedpre(tp, FALSE);
// autocmd may have freed the window already.
if (!win_valid_any_tab(win))
return;
Reply all
Reply to author
Forward
0 new messages