mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 04:42:03 +00:00
vim-patch:9.1.1202: Missing TabClosedPre autocommand
Problem: Missing TabClosedPre autocommand
(zoumi)
Solution: Add the TabClosedPre autcommand (Jim Zhou).
fixes: vim/vim#16518
closes: vim/vim#16855
5606ca5349
Co-authored-by: Jim Zhou <jimzhouzzy@gmail.com>
This commit is contained in:
@@ -1041,6 +1041,13 @@ Syntax When the 'syntax' option has been set. The
|
||||
this option was set. <amatch> expands to the
|
||||
new value of 'syntax'.
|
||||
See |:syn-on|.
|
||||
*TabClosed*
|
||||
TabClosed After closing a tab page. <afile> expands to
|
||||
the tab page number.
|
||||
*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 WinEnter.
|
||||
@@ -1055,9 +1062,6 @@ TabNew When creating a new tab page. |tab-page|
|
||||
*TabNewEntered*
|
||||
TabNewEntered After entering a new tab page. |tab-page|
|
||||
After BufEnter.
|
||||
*TabClosed*
|
||||
TabClosed After closing a tab page. <afile> expands to
|
||||
the tab page number.
|
||||
*TermOpen*
|
||||
TermOpen When a |terminal| job is starting. Can be
|
||||
used to configure the terminal buffer. To get
|
||||
|
||||
@@ -233,6 +233,7 @@ EVENTS
|
||||
• Creating or updating a progress message with |nvim_echo()| triggers a |Progress| event.
|
||||
• |MarkSet| is triggered after a |mark| is set by the user (currently doesn't
|
||||
support implicit marks like |'[| or |'<|, …).
|
||||
• |TabClosedPre| is triggered before closing a |tabpage|.
|
||||
• New `terminator` parameter for |TermRequest| event.
|
||||
|
||||
HIGHLIGHTS
|
||||
|
||||
@@ -2561,6 +2561,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
|SwapExists|,
|
||||
|Syntax|,
|
||||
|TabClosed|,
|
||||
|TabClosedPre|,
|
||||
|TabEnter|,
|
||||
|TabLeave|,
|
||||
|TabNew|,
|
||||
|
||||
1
runtime/lua/vim/_meta/api_keysets.lua
generated
1
runtime/lua/vim/_meta/api_keysets.lua
generated
@@ -189,6 +189,7 @@ error('Cannot require a meta file')
|
||||
--- |'SwapExists'
|
||||
--- |'Syntax'
|
||||
--- |'TabClosed'
|
||||
--- |'TabClosedPre'
|
||||
--- |'TabEnter'
|
||||
--- |'TabLeave'
|
||||
--- |'TabNew'
|
||||
|
||||
1
runtime/lua/vim/_meta/options.lua
generated
1
runtime/lua/vim/_meta/options.lua
generated
@@ -2239,6 +2239,7 @@ vim.go.ei = vim.go.eventignore
|
||||
--- `SwapExists`,
|
||||
--- `Syntax`,
|
||||
--- `TabClosed`,
|
||||
--- `TabClosedPre`,
|
||||
--- `TabEnter`,
|
||||
--- `TabLeave`,
|
||||
--- `TabNew`,
|
||||
|
||||
@@ -1890,7 +1890,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 "\<linebreaks=" nextgroup=vimNumber
|
||||
syn keyword vimSyncLinecont contained linecont skipwhite nextgroup=vimSynRegPat
|
||||
syn match vimSyncLines contained "\<lines=" nextgroup=vimNumber
|
||||
|
||||
@@ -109,7 +109,8 @@ return {
|
||||
StdinReadPre = false, -- before reading from stdin
|
||||
SwapExists = false, -- found existing swap file
|
||||
Syntax = false, -- syntax selected
|
||||
TabClosed = false, -- a tab has closed
|
||||
TabClosed = false, -- after closing a tab page
|
||||
TabClosedPre = false, -- before closing a tab page
|
||||
TabEnter = false, -- after entering a tab page
|
||||
TabLeave = false, -- before leaving a tab page
|
||||
TabNew = false, -- when creating a new tab
|
||||
|
||||
@@ -3102,6 +3102,35 @@ static void do_autocmd_winclosed(win_T *win)
|
||||
recursive = false;
|
||||
}
|
||||
|
||||
static void trigger_tabclosedpre(tabpage_T *tp)
|
||||
{
|
||||
static bool recursive = false;
|
||||
tabpage_T *ptp = curtab;
|
||||
|
||||
// Quickly return when no TabClosedPre autocommands to be executed or
|
||||
// already executing
|
||||
if (!has_event(EVENT_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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
// thus "tp" may become invalid!
|
||||
@@ -3157,6 +3186,14 @@ bool win_close_othertab(win_T *win, int free_buf, tabpage_T *tp, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
if (tp->tp_firstwin == tp->tp_lastwin) {
|
||||
trigger_tabclosedpre(tp);
|
||||
// autocmd may have freed the window already.
|
||||
if (!win_valid_any_tab(win)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bufref_T bufref;
|
||||
set_bufref(&bufref, win->w_buffer);
|
||||
|
||||
|
||||
@@ -4636,6 +4636,165 @@ func Test_WinScrolled_Resized_eiw()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" Test that TabClosedPre and TabClosed are triggered when closing a tab.
|
||||
func Test_autocmd_tabclosedpre()
|
||||
augroup testing
|
||||
au TabClosedPre * call add(g:tabpagenr_pre, t:testvar)
|
||||
au TabClosed * call add(g:tabpagenr_post, t:testvar)
|
||||
augroup END
|
||||
|
||||
" Test 'tabclose' triggering
|
||||
let g:tabpagenr_pre = []
|
||||
let g:tabpagenr_post = []
|
||||
let t:testvar = 1
|
||||
tabnew
|
||||
let t:testvar = 2
|
||||
tabnew
|
||||
let t:testvar = 3
|
||||
tabnew
|
||||
let t:testvar = 4
|
||||
tabnext
|
||||
tabclose
|
||||
tabclose
|
||||
tabclose
|
||||
call assert_equal([1, 2, 3], g:tabpagenr_pre)
|
||||
call assert_equal([2, 3, 4], g:tabpagenr_post)
|
||||
|
||||
" Test 'tabclose {count}' triggering
|
||||
let g:tabpagenr_pre = []
|
||||
let g:tabpagenr_post = []
|
||||
let t:testvar = 1
|
||||
tabnew
|
||||
let t:testvar = 2
|
||||
tabnew
|
||||
let t:testvar = 3
|
||||
tabclose 2
|
||||
tabclose 2
|
||||
call assert_equal([2, 3], g:tabpagenr_pre)
|
||||
call assert_equal([3, 1], g:tabpagenr_post)
|
||||
|
||||
" Test 'tabonly' triggering
|
||||
let g:tabpagenr_pre = []
|
||||
let g:tabpagenr_post = []
|
||||
let t:testvar = 1
|
||||
tabnew
|
||||
let t:testvar = 2
|
||||
tabonly
|
||||
call assert_equal([1], g:tabpagenr_pre)
|
||||
call assert_equal([2], g:tabpagenr_post)
|
||||
|
||||
" Test 'q' and 'close' triggering (closing the last window in a tab)
|
||||
let g:tabpagenr_pre = []
|
||||
let g:tabpagenr_post = []
|
||||
split
|
||||
let t:testvar = 1
|
||||
tabnew
|
||||
let t:testvar = 2
|
||||
split
|
||||
vsplit
|
||||
tabnew
|
||||
let t:testvar = 3
|
||||
tabnext
|
||||
only
|
||||
quit
|
||||
quit
|
||||
close
|
||||
close
|
||||
call assert_equal([1, 2], g:tabpagenr_pre)
|
||||
call assert_equal([2, 3], g:tabpagenr_post)
|
||||
|
||||
func ClearAutomcdAndCreateTabs()
|
||||
au! TabClosedPre
|
||||
bw!
|
||||
e Z
|
||||
tabonly
|
||||
tabnew A
|
||||
tabnew B
|
||||
tabnew C
|
||||
endfunc
|
||||
|
||||
func GetTabs()
|
||||
redir => tabsout
|
||||
tabs
|
||||
redir END
|
||||
let tabsout = substitute(tabsout, '\n', '', 'g')
|
||||
let tabsout = substitute(tabsout, 'Tab page ', '', 'g')
|
||||
let tabsout = substitute(tabsout, '#', '', 'g') " Nvim: remove '#'
|
||||
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
|
||||
|
||||
func Test_eventignorewin_non_current()
|
||||
defer CleanUpTestAuGroup()
|
||||
let s:triggered = ''
|
||||
|
||||
Reference in New Issue
Block a user