From 5606ca5349982fe53cc6a2ec6345aa66f0613d40 Mon Sep 17 00:00:00 2001 From: Jim Zhou Date: Thu, 13 Mar 2025 21:58:25 +0100 Subject: [PATCH] patch 9.1.1202: Missing TabClosedPre autocommand Problem: Missing TabClosedPre autocommand (zoumi) Solution: Add the TabClosedPre autcommand (Jim Zhou). fixes: #16518 closes: #16855 Signed-off-by: Jim Zhou Signed-off-by: Christian Brabandt --- runtime/doc/autocmd.txt | 5 ++ runtime/doc/tags | 1 + runtime/doc/version9.txt | 3 +- runtime/syntax/vim.vim | 6 +- src/autocmd.c | 9 ++ src/proto/autocmd.pro | 1 + src/testdir/test_autocmd.vim | 158 +++++++++++++++++++++++++++++++++++ src/version.c | 2 + src/vim.h | 1 + src/window.c | 35 ++++++++ 10 files changed, 217 insertions(+), 4 deletions(-) diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 8532fc9562..372d1acbc3 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -387,6 +387,7 @@ Name triggered by ~ |TabNew| after creating a new tab page |WinClosed| after closing a window |TabClosed| after closing a tab page +|TabClosedPre| before closing a tab page |WinEnter| after entering another window |WinLeave| before leaving a window |TabEnter| after entering another tab page @@ -1232,6 +1233,10 @@ Syntax When the 'syntax' option has been set. The See |:syn-on|. *TabClosed* TabClosed After closing a tab page. + *TabClosedPre* +TabClosedPre Before closing a tab page. The window layout + is locked, thus opening and closing of windows + is prohibited. *TabEnter* TabEnter Just after entering a tab page. |tab-page| After triggering the WinEnter and before diff --git a/runtime/doc/tags b/runtime/doc/tags index a91b4af0b1..3bd49d90d6 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -5759,6 +5759,7 @@ TSQL ft_sql.txt /*TSQL* TTpro-telnet syntax.txt /*TTpro-telnet* Tab intro.txt /*Tab* TabClosed autocmd.txt /*TabClosed* +TabClosedPre autocmd.txt /*TabClosedPre* TabEnter autocmd.txt /*TabEnter* TabLeave autocmd.txt /*TabLeave* TabNew autocmd.txt /*TabNew* diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index f12bcd4c35..6d41e342fb 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2025 Mar 06 +*version9.txt* For Vim version 9.1. Last change: 2025 Mar 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41687,6 +41687,7 @@ Autocommands: ~ |CursorMovedC| after the cursor was moved in the command-line |KeyInputPre| before processing any key event in any mode |SessionWritePost| after writing the session file |:mksession| +|TabClosedPre| before closing a |tabpage|. |TermResponseAll| after the terminal response to |t_RV| and others is received |WinNewPre| before creating a new window diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index f537e03979..d469134db1 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -2,7 +2,7 @@ " Language: Vim script " Maintainer: Hirohito Higashi " Doug Kearns -" Last Change: 2025 Mar 10 +" Last Change: 2025 Mar 13 " Former Maintainer: Charles E. Campbell " DO NOT CHANGE DIRECTLY. @@ -116,7 +116,7 @@ syn keyword vimErrSetting contained invakm invaltkeymap invanti invantialias inv syn case ignore " GEN_SYN_VIM: vimAutoEvent, START_STR='syn keyword vimAutoEvent contained', END_STR='' syn keyword vimAutoEvent contained BufAdd BufCreate BufDelete BufEnter BufFilePost BufFilePre BufHidden BufLeave BufNew BufNewFile BufRead BufReadCmd BufReadPost BufReadPre BufUnload BufWinEnter BufWinLeave BufWipeout BufWrite BufWriteCmd BufWritePost BufWritePre CmdlineChanged CmdlineEnter CmdlineLeave CmdUndefined CmdwinEnter CmdwinLeave ColorScheme ColorSchemePre CompleteChanged CompleteDone CompleteDonePre CursorHold CursorHoldI CursorMoved CursorMovedC CursorMovedI DiffUpdated DirChanged DirChangedPre EncodingChanged ExitPre FileAppendCmd FileAppendPost FileAppendPre FileChangedRO FileChangedShell FileChangedShellPost FileEncoding FileReadCmd FileReadPost FileReadPre FileType FileWriteCmd FileWritePost FileWritePre FilterReadPost FilterReadPre FilterWritePost -syn keyword vimAutoEvent contained FilterWritePre FocusGained FocusLost FuncUndefined GUIEnter GUIFailed InsertChange InsertCharPre InsertEnter InsertLeave InsertLeavePre KeyInputPre MenuPopup ModeChanged OptionSet QuickFixCmdPost QuickFixCmdPre QuitPre RemoteReply SafeState SafeStateAgain SessionLoadPost SessionWritePost ShellCmdPost ShellFilterPost SigUSR1 SourceCmd SourcePost SourcePre SpellFileMissing StdinReadPost StdinReadPre SwapExists Syntax TabClosed TabEnter TabLeave TabNew TermChanged TerminalOpen TerminalWinOpen TermResponse TermResponseAll TextChanged TextChangedI TextChangedP TextChangedT TextYankPost User VimEnter VimLeave VimLeavePre VimResized VimResume VimSuspend WinClosed WinEnter WinLeave WinNew WinNewPre WinResized WinScrolled +syn keyword vimAutoEvent contained FilterWritePre FocusGained FocusLost FuncUndefined GUIEnter GUIFailed InsertChange InsertCharPre InsertEnter InsertLeave InsertLeavePre KeyInputPre MenuPopup ModeChanged OptionSet QuickFixCmdPost QuickFixCmdPre QuitPre RemoteReply SafeState SafeStateAgain SessionLoadPost SessionWritePost ShellCmdPost ShellFilterPost SigUSR1 SourceCmd SourcePost SourcePre SpellFileMissing StdinReadPost StdinReadPre SwapExists Syntax TabClosed TabClosedPre TabEnter TabLeave TabNew TermChanged TerminalOpen TerminalWinOpen TermResponse TermResponseAll TextChanged TextChangedI TextChangedP TextChangedT TextYankPost User VimEnter VimLeave VimLeavePre VimResized VimResume VimSuspend WinClosed WinEnter WinLeave WinNew WinNewPre WinResized WinScrolled " Highlight commonly used Groupnames {{{2 syn keyword vimGroup contained Comment Constant String Character Number Boolean Float Identifier Function Statement Conditional Repeat Label Operator Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug Underlined Ignore Error Todo @@ -1153,7 +1153,7 @@ syn keyword vimSyncCcomment contained ccomment skipwhite nextgroup=vimGroupName syn keyword vimSyncClear contained clear skipwhite nextgroup=vimSyncGroupName syn keyword vimSyncFromstart contained fromstart syn keyword vimSyncMatch contained match skipwhite nextgroup=vimSyncGroupName -syn keyword vimSyncRegion contained region skipwhite nextgroup=vimSynRegion +syn keyword vimSyncRegion contained region skipwhite nextgroup=vimSynReg syn match vimSyncLinebreak contained "\ tabsout + tabs + redir END + let tabsout = substitute(tabsout, '\n', '', 'g') + let tabsout = substitute(tabsout, 'Tab page ', '', 'g') + let tabsout = substitute(tabsout, ' ', '', 'g') + return tabsout + endfunc + + call CleanUpTestAuGroup() + + " Close tab in TabClosedPre autocmd + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabclose + call assert_fails('tabclose', 'E1312') + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabclose + call assert_fails('tabclose 2', 'E1312') + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabclose 1 + call assert_fails('tabclose', 'E1312') + + " Close other (all) tabs in TabClosedPre autocmd + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabonly + call assert_fails('tabclose', 'E1312') + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabonly + call assert_fails('tabclose 2', 'E1312') + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabclose 4 + call assert_fails('tabclose 2', 'E1312') + + " Open new tabs in TabClosedPre autocmd + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabnew D + call assert_fails('tabclose', 'E1312') + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabnew D + call assert_fails('tabclose 1', 'E1312') + + " Moving the tab page in TabClosedPre autocmd + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabmove 0 + tabclose + call assert_equal('1Z2A3>B', GetTabs()) + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabmove 0 + tabclose 1 + call assert_equal('1A2B3>C', GetTabs()) + tabonly + call assert_equal('1>C', GetTabs()) + + " Switching tab page in TabClosedPre autocmd + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabnext | e Y + tabclose + call assert_equal('1Y2A3>B', GetTabs()) + call ClearAutomcdAndCreateTabs() + au TabClosedPre * tabnext | e Y + tabclose 1 + call assert_equal('1Y2B3>C', GetTabs()) + tabonly + call assert_equal('1>Y', GetTabs()) + + " Create new windows in TabClosedPre autocmd + call ClearAutomcdAndCreateTabs() + au TabClosedPre * split | e X| vsplit | e Y | split | e Z + call assert_fails('tabclose', 'E242') + call ClearAutomcdAndCreateTabs() + au TabClosedPre * new X | new Y | new Z + call assert_fails('tabclose 1', 'E242') + + " Clean up + au! + only + tabonly + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index b9fcedc01d..c129404aa3 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 */ +/**/ + 1202, /**/ 1201, /**/ diff --git a/src/vim.h b/src/vim.h index 212b7e774f..85fad6ce41 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1435,6 +1435,7 @@ enum auto_event EVENT_SWAPEXISTS, // found existing swap file EVENT_SYNTAX, // syntax selected EVENT_TABCLOSED, // after closing a tab page + EVENT_TABCLOSEDPRE, // before closing a tab page EVENT_TABENTER, // after entering a tab page EVENT_TABLEAVE, // before leaving a tab page EVENT_TABNEW, // when entering a new tab page diff --git a/src/window.c b/src/window.c index cc76f79516..cce7f4c797 100644 --- a/src/window.c +++ b/src/window.c @@ -2978,6 +2978,33 @@ trigger_winclosed(win_T *win) recursive = FALSE; } + static void +trigger_tabclosedpre(tabpage_T *tp) +{ + static int recursive = FALSE; + tabpage_T *ptp = curtab; + + // Quickly return when no TabClosedPre autocommands to be executed or + // already executing + if (!has_tabclosedpre() || recursive) + return; + + if (valid_tabpage(tp)) + goto_tabpage_tp(tp, FALSE, FALSE); + recursive = TRUE; + window_layout_lock(); + apply_autocmds(EVENT_TABCLOSEDPRE, NULL, NULL, FALSE, NULL); + window_layout_unlock(); + recursive = FALSE; + // tabpage may have been modified or deleted by autocmds + if (valid_tabpage(ptp)) + // try to recover the tappage first + goto_tabpage_tp(ptp, FALSE, FALSE); + else + // fall back to the first tappage + goto_tabpage_tp(first_tabpage, FALSE, FALSE); +} + /* * Make a snapshot of all the window scroll positions and sizes of the current * tab page. @@ -3353,6 +3380,14 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) return; } + if (tp->tp_firstwin == tp->tp_lastwin) + { + trigger_tabclosedpre(tp); + // 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, -- 2.39.5