mirror of
https://github.com/neovim/neovim.git
synced 2026-04-23 15:55:36 +00:00
Merge pull request #37464 from zeertzjq/vim-9.1.1202
vim-patch:9.1.{1202,1211,1325,2093,2097}: TabClosedPre
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`,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -841,9 +841,10 @@ struct tabpage_S {
|
||||
win_T *tp_firstwin; ///< first window in this Tab page
|
||||
win_T *tp_lastwin; ///< last window in this Tab page
|
||||
int64_t tp_old_Rows_avail; ///< ROWS_AVAIL when Tab page was left
|
||||
int64_t tp_old_Columns; ///< Columns when Tab page was left, -1 when
|
||||
///< calling win_new_screen_cols() postponed
|
||||
int64_t tp_old_Columns; ///< Columns when Tab page was left, -1 when
|
||||
///< calling win_new_screen_cols() postponed
|
||||
OptInt tp_ch_used; ///< value of 'cmdheight' when frame size was set
|
||||
bool tp_did_tabclosedpre; ///< whether TabClosedPre was triggered
|
||||
|
||||
diff_T *tp_first_diff;
|
||||
buf_T *(tp_diffbuf[DB_COUNT]);
|
||||
|
||||
@@ -5150,6 +5150,10 @@ void tabpage_close(int forceit)
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_tabclosedpre(curtab);
|
||||
curtab->tp_did_tabclosedpre = true;
|
||||
tabpage_T *const save_curtab = curtab;
|
||||
|
||||
// First close all the windows but the current one. If that worked then
|
||||
// close the last window in this tab, that will close it.
|
||||
while (curwin->w_floating) {
|
||||
@@ -5161,6 +5165,11 @@ void tabpage_close(int forceit)
|
||||
if (ONE_WINDOW) {
|
||||
ex_win_close(forceit, curwin, NULL);
|
||||
}
|
||||
if (curtab == save_curtab) {
|
||||
// When closing the tab page failed, reset tp_did_tabclosedpre so that
|
||||
// TabClosedPre behaves consistently on next :close vs :tabclose.
|
||||
curtab->tp_did_tabclosedpre = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Close tab page "tp", which is not the current tab page.
|
||||
@@ -5172,6 +5181,13 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
|
||||
int done = 0;
|
||||
char prev_idx[NUMBUFLEN];
|
||||
|
||||
if (window_layout_locked(CMD_SIZE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_tabclosedpre(tp);
|
||||
tp->tp_did_tabclosedpre = true;
|
||||
|
||||
// Limit to 1000 windows, autocommands may add a window while we close
|
||||
// one. OK, so I'm paranoid...
|
||||
while (++done < 1000) {
|
||||
@@ -5179,11 +5195,21 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
|
||||
win_T *wp = tp->tp_lastwin;
|
||||
ex_win_close(forceit, wp, tp);
|
||||
|
||||
// Autocommands may delete the tab page under our fingers and we may
|
||||
// fail to close a window with a modified buffer.
|
||||
if (!valid_tabpage(tp) || tp->tp_lastwin == wp) {
|
||||
// Autocommands may delete the tab page under our fingers.
|
||||
if (!valid_tabpage(tp)) {
|
||||
break;
|
||||
}
|
||||
// We may fail to close a window with a modified buffer.
|
||||
if (tp->tp_lastwin == wp) {
|
||||
done = 1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done >= 1000) {
|
||||
// When closing the tab page failed, reset tp_did_tabclosedpre so that
|
||||
// TabClosedPre behaves consistently on next :close vs :tabclose.
|
||||
tp->tp_did_tabclosedpre = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,8 @@ bool frames_locked(void)
|
||||
|
||||
/// When the window layout cannot be changed give an error and return true.
|
||||
/// "cmd" indicates the action being performed and is used to pick the relevant
|
||||
/// error message.
|
||||
/// error message. When closing window(s) and the command isn't easy to know,
|
||||
/// passing CMD_SIZE will also work.
|
||||
bool window_layout_locked(cmdidx_T cmd)
|
||||
{
|
||||
if (split_disallowed > 0 || close_disallowed > 0) {
|
||||
@@ -2569,6 +2570,9 @@ void close_windows(buf_T *buf, bool keep_curwin)
|
||||
for (win_T *wp = lastwin; wp != NULL && (is_aucmd_win(lastwin) || !one_window(wp, NULL));) {
|
||||
if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
|
||||
&& !(win_locked(wp) || wp->w_buffer->b_locked > 0)) {
|
||||
if (window_layout_locked(CMD_SIZE)) {
|
||||
goto theend; // Only give one error message.
|
||||
}
|
||||
if (win_close(wp, false, false) == FAIL) {
|
||||
// If closing the window fails give up, to avoid looping forever.
|
||||
break;
|
||||
@@ -2591,6 +2595,9 @@ void close_windows(buf_T *buf, bool keep_curwin)
|
||||
for (win_T *wp = tp->tp_lastwin; wp != NULL; wp = wp->w_prev) {
|
||||
if (wp->w_buffer == buf
|
||||
&& !(win_locked(wp) || wp->w_buffer->b_locked > 0)) {
|
||||
if (window_layout_locked(CMD_SIZE)) {
|
||||
goto theend; // Only give one error message.
|
||||
}
|
||||
if (!win_close_othertab(wp, false, tp, false)) {
|
||||
// If closing the window fails give up, to avoid looping forever.
|
||||
break;
|
||||
@@ -2605,6 +2612,7 @@ void close_windows(buf_T *buf, bool keep_curwin)
|
||||
}
|
||||
}
|
||||
|
||||
theend:
|
||||
RedrawingDisabled--;
|
||||
}
|
||||
|
||||
@@ -3102,6 +3110,35 @@ static void do_autocmd_winclosed(win_T *win)
|
||||
recursive = false;
|
||||
}
|
||||
|
||||
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 tabpage first
|
||||
goto_tabpage_tp(ptp, false, false);
|
||||
} else {
|
||||
// fall back to the first tabpage
|
||||
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!
|
||||
@@ -3115,6 +3152,11 @@ bool win_close_othertab(win_T *win, int free_buf, tabpage_T *tp, bool force)
|
||||
assert(tp != curtab);
|
||||
bool did_decrement = false;
|
||||
|
||||
// Commands that may call win_close_othertab() already check this, but
|
||||
// check here again just in case.
|
||||
if (window_layout_locked(CMD_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
// Get here with win->w_buffer == NULL when win_close() detects the tab page
|
||||
// changed.
|
||||
if (win_locked(win)
|
||||
@@ -3157,6 +3199,14 @@ bool win_close_othertab(win_T *win, int free_buf, tabpage_T *tp, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
if (tp->tp_firstwin == tp->tp_lastwin && !tp->tp_did_tabclosedpre) {
|
||||
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);
|
||||
|
||||
|
||||
@@ -640,7 +640,7 @@ endfunc
|
||||
func Test_clear_arglist_in_all()
|
||||
n 0 00 000 0000 00000 000000
|
||||
au WinNew 0 n 0
|
||||
call assert_fails("all", "E1156")
|
||||
call assert_fails("all", "E1156:")
|
||||
au! *
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -3817,10 +3817,10 @@ func Test_autocmd_normal_mess()
|
||||
au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc
|
||||
augroup END
|
||||
" Nvim has removed :open
|
||||
" call assert_fails('o4', 'E1159')
|
||||
call assert_fails('e4', 'E1159')
|
||||
" call assert_fails('o4', 'E1159:')
|
||||
call assert_fails('e4', 'E1159:')
|
||||
silent! H
|
||||
call assert_fails('e xx', 'E1159')
|
||||
call assert_fails('e xx', 'E1159:')
|
||||
normal G
|
||||
|
||||
augroup aucmd_normal_test
|
||||
@@ -4566,6 +4566,7 @@ func Test_OptionSet_cmdheight()
|
||||
call Ntest_setmouse(&lines - 2, 1)
|
||||
call feedkeys("\<LeftDrag>", 'xt')
|
||||
call assert_equal(2, &l:ch)
|
||||
call feedkeys("\<LeftRelease>", 'xt')
|
||||
|
||||
tabnew | resize +1
|
||||
call assert_equal(1, &l:ch)
|
||||
@@ -4636,6 +4637,337 @@ 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)
|
||||
|
||||
" Test failing to close tab page
|
||||
let g:tabpagenr_pre = []
|
||||
let g:tabpagenr_post = []
|
||||
let t:testvar = 1
|
||||
call setline(1, 'foo')
|
||||
setlocal bufhidden=wipe
|
||||
tabnew
|
||||
let t:testvar = 2
|
||||
tabnew
|
||||
let t:testvar = 3
|
||||
call setline(1, 'bar')
|
||||
setlocal bufhidden=wipe
|
||||
tabnew
|
||||
let t:testvar = 4
|
||||
call setline(1, 'baz')
|
||||
setlocal bufhidden=wipe
|
||||
new
|
||||
call assert_fails('tabclose', 'E445:')
|
||||
call assert_equal([4], g:tabpagenr_pre)
|
||||
call assert_equal([], g:tabpagenr_post)
|
||||
" :tabclose! after failed :tabclose should trigger TabClosedPre again.
|
||||
tabclose!
|
||||
call assert_equal([4, 4], g:tabpagenr_pre)
|
||||
call assert_equal([3], g:tabpagenr_post)
|
||||
call assert_fails('tabclose', 'E37:')
|
||||
call assert_equal([4, 4, 3], g:tabpagenr_pre)
|
||||
call assert_equal([3], g:tabpagenr_post)
|
||||
" The same for :close! if the tab page only has one window.
|
||||
close!
|
||||
call assert_equal([4, 4, 3, 3], g:tabpagenr_pre)
|
||||
call assert_equal([3, 2], g:tabpagenr_post)
|
||||
" Also test with :close! after failed :tabonly.
|
||||
call assert_fails('tabonly', 'E37:')
|
||||
call assert_equal([4, 4, 3, 3, 1], g:tabpagenr_pre)
|
||||
call assert_equal([3, 2], g:tabpagenr_post)
|
||||
tabprevious | close!
|
||||
call assert_equal([4, 4, 3, 3, 1, 1], g:tabpagenr_pre)
|
||||
call assert_equal([3, 2, 2], g:tabpagenr_post)
|
||||
%bwipe!
|
||||
|
||||
" Test closing another tab page in BufWinLeave
|
||||
let g:tabpagenr_pre = []
|
||||
let g:tabpagenr_post = []
|
||||
split
|
||||
let t:testvar = 1
|
||||
tabnew
|
||||
let t:testvar = 2
|
||||
tabnew Xsomebuf
|
||||
let t:testvar = 3
|
||||
new
|
||||
autocmd BufWinLeave Xsomebuf ++once ++nested tabclose 1
|
||||
tabclose
|
||||
" TabClosedPre should not be triggered for tab page 3 twice.
|
||||
call assert_equal([3, 1], g:tabpagenr_pre)
|
||||
" When tab page 1 was closed, tab page 3 was still the current tab page.
|
||||
call assert_equal([3, 2], g:tabpagenr_post)
|
||||
%bwipe!
|
||||
|
||||
func ClearAutocmdAndCreateTabs()
|
||||
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 ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabclose
|
||||
call assert_fails('tabclose', 'E1312:')
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabclose
|
||||
call assert_fails('tabclose 2', 'E1312:')
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabclose 1
|
||||
call assert_fails('tabclose', 'E1312:')
|
||||
|
||||
" Close other (all) tabs in TabClosedPre autocmd
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabonly
|
||||
call assert_fails('tabclose', 'E1312:')
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabonly
|
||||
call assert_fails('tabclose 2', 'E1312:')
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabclose 4
|
||||
call assert_fails('tabclose 2', 'E1312:')
|
||||
|
||||
" Open new tabs in TabClosedPre autocmd
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabnew D
|
||||
call assert_fails('tabclose', 'E1312:')
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabnew D
|
||||
call assert_fails('tabclose 1', 'E1312:')
|
||||
|
||||
" Moving the tab page in TabClosedPre autocmd
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabmove 0
|
||||
tabclose
|
||||
call assert_equal('1>Z2A3B', GetTabs())
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
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 ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * tabnext | e Y
|
||||
tabclose
|
||||
call assert_equal('1Y2A3>B', GetTabs())
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
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 ClearAutocmdAndCreateTabs()
|
||||
au TabClosedPre * split | e X| vsplit | e Y | split | e Z
|
||||
call assert_fails('tabclose', 'E242:')
|
||||
call ClearAutocmdAndCreateTabs()
|
||||
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
|
||||
bw!
|
||||
delfunc ClearAutocmdAndCreateTabs
|
||||
delfunc GetTabs
|
||||
endfunc
|
||||
|
||||
" This used to cause heap-use-after-free.
|
||||
func Run_test_TabClosedPre_wipe_buffer(split_cmds)
|
||||
file Xa
|
||||
exe a:split_cmds
|
||||
autocmd TabClosedPre * ++once tabnext | bwipe! Xa
|
||||
" Closing window inside TabClosedPre is not allowed.
|
||||
call assert_fails('tabonly', 'E1312:')
|
||||
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_TabClosedPre_wipe_buffer()
|
||||
" Test with Xa only in other tab pages.
|
||||
call Run_test_TabClosedPre_wipe_buffer('split | tab split | tabnew Xb')
|
||||
" Test with Xa in both current and other tab pages.
|
||||
call Run_test_TabClosedPre_wipe_buffer('split | tab split | new Xb')
|
||||
endfunc
|
||||
|
||||
func Test_TabClosedPre_mouse()
|
||||
func MyTabline()
|
||||
let cnt = tabpagenr('$')
|
||||
return range(1, cnt)->mapnew({_, n -> $'%{n}X|Close{n}|%X'})->join('')
|
||||
endfunc
|
||||
|
||||
let save_mouse = &mouse
|
||||
if has('gui')
|
||||
set guioptions-=e
|
||||
endif
|
||||
set mouse=a tabline=%!MyTabline()
|
||||
|
||||
func OpenTwoTabPages()
|
||||
%bwipe!
|
||||
file Xa | split | split
|
||||
let g:Xa_bufnr = bufnr()
|
||||
tabnew Xb | split
|
||||
let g:Xb_bufnr = bufnr()
|
||||
redraw!
|
||||
call assert_match('^|Close1||Close2| *$', Screenline(1))
|
||||
call assert_equal(2, tabpagenr('$'))
|
||||
endfunc
|
||||
|
||||
autocmd! TabClosedPre
|
||||
call OpenTwoTabPages()
|
||||
let g:autocmd_bufnrs = []
|
||||
autocmd TabClosedPre * let g:autocmd_bufnrs += [tabpagebuflist()]
|
||||
call Ntest_setmouse(1, 2)
|
||||
call feedkeys("\<LeftMouse>\<LeftRelease>", 'tx')
|
||||
call assert_equal(1, tabpagenr('$'))
|
||||
call assert_equal([[g:Xa_bufnr]->repeat(3)], g:autocmd_bufnrs)
|
||||
call assert_equal([g:Xb_bufnr]->repeat(2), tabpagebuflist())
|
||||
|
||||
call OpenTwoTabPages()
|
||||
let g:autocmd_bufnrs = []
|
||||
autocmd TabClosedPre * call feedkeys("\<LeftRelease>\<LeftMouse>", 'tx')
|
||||
call Ntest_setmouse(1, 2)
|
||||
" Closing tab page inside TabClosedPre is not allowed.
|
||||
call assert_fails('call feedkeys("\<LeftMouse>", "tx")', 'E1312:')
|
||||
call feedkeys("\<LeftRelease>", 'tx')
|
||||
|
||||
autocmd! TabClosedPre
|
||||
call OpenTwoTabPages()
|
||||
let g:autocmd_bufnrs = []
|
||||
autocmd TabClosedPre * let g:autocmd_bufnrs += [tabpagebuflist()]
|
||||
call Ntest_setmouse(1, 10)
|
||||
call feedkeys("\<LeftMouse>\<LeftRelease>", 'tx')
|
||||
call assert_equal(1, tabpagenr('$'))
|
||||
call assert_equal([[g:Xb_bufnr]->repeat(2)], g:autocmd_bufnrs)
|
||||
call assert_equal([g:Xa_bufnr]->repeat(3), tabpagebuflist())
|
||||
|
||||
call OpenTwoTabPages()
|
||||
let g:autocmd_bufnrs = []
|
||||
autocmd TabClosedPre * call feedkeys("\<LeftRelease>\<LeftMouse>", 'tx')
|
||||
call Ntest_setmouse(1, 10)
|
||||
" Closing tab page inside TabClosedPre is not allowed.
|
||||
call assert_fails('call feedkeys("\<LeftMouse>", "tx")', 'E1312:')
|
||||
call feedkeys("\<LeftRelease>", 'tx')
|
||||
|
||||
autocmd! TabClosedPre
|
||||
%bwipe!
|
||||
unlet g:Xa_bufnr g:Xb_bufnr g:autocmd_bufnrs
|
||||
let &mouse = save_mouse
|
||||
set tabline& guioptions&
|
||||
delfunc MyTabline
|
||||
delfunc OpenTwoTabPages
|
||||
endfunc
|
||||
|
||||
func Test_eventignorewin_non_current()
|
||||
defer CleanUpTestAuGroup()
|
||||
let s:triggered = ''
|
||||
|
||||
@@ -229,13 +229,13 @@ func Test_blob_compare()
|
||||
VAR b1 = 0z0011
|
||||
echo b1 == 9
|
||||
END
|
||||
call CheckLegacyAndVim9Failure(lines, ['E977:', 'E1072', 'E1072'])
|
||||
call CheckLegacyAndVim9Failure(lines, ['E977:', 'E1072:', 'E1072:'])
|
||||
|
||||
let lines =<< trim END
|
||||
VAR b1 = 0z0011
|
||||
echo b1 != 9
|
||||
END
|
||||
call CheckLegacyAndVim9Failure(lines, ['E977:', 'E1072', 'E1072'])
|
||||
call CheckLegacyAndVim9Failure(lines, ['E977:', 'E1072:', 'E1072:'])
|
||||
|
||||
let lines =<< trim END
|
||||
VAR b1 = 0z0011
|
||||
|
||||
@@ -2123,7 +2123,7 @@ endfunc
|
||||
func Test_read_invalid()
|
||||
" set encoding=latin1
|
||||
" This was not properly checking for going past the end.
|
||||
call assert_fails('r`=', 'E484')
|
||||
call assert_fails('r`=', 'E484:')
|
||||
set encoding=utf-8
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -213,10 +213,10 @@ func Test_method_with_prefix()
|
||||
call CheckLegacyAndVim9Success(lines)
|
||||
|
||||
call assert_equal([0, 1, 2], --3->range())
|
||||
call CheckDefAndScriptFailure(['eval --3->range()'], 'E15')
|
||||
call CheckDefAndScriptFailure(['eval --3->range()'], 'E15:')
|
||||
|
||||
call assert_equal(1, !+-+0)
|
||||
call CheckDefAndScriptFailure(['eval !+-+0'], 'E15')
|
||||
call CheckDefAndScriptFailure(['eval !+-+0'], 'E15:')
|
||||
endfunc
|
||||
|
||||
func Test_option_value()
|
||||
@@ -836,7 +836,7 @@ endfunc
|
||||
" Test for errors in expression evaluation
|
||||
func Test_expr_eval_error()
|
||||
call CheckLegacyAndVim9Failure(["VAR i = 'abc' .. []"], ['E730:', 'E1105:', 'E730:'])
|
||||
call CheckLegacyAndVim9Failure(["VAR l = [] + 10"], ['E745:', 'E1051:', 'E745'])
|
||||
call CheckLegacyAndVim9Failure(["VAR l = [] + 10"], ['E745:', 'E1051:', 'E745:'])
|
||||
call CheckLegacyAndVim9Failure(["VAR v = 10 + []"], ['E745:', 'E1051:', 'E745:'])
|
||||
call CheckLegacyAndVim9Failure(["VAR v = 10 / []"], ['E745:', 'E1036:', 'E745:'])
|
||||
call CheckLegacyAndVim9Failure(["VAR v = -{}"], ['E728:', 'E1012:', 'E728:'])
|
||||
|
||||
@@ -1366,7 +1366,7 @@ func Test_listdict_index()
|
||||
call CheckLegacyAndVim9Failure(['VAR d = {"k": 10}', 'echo d[1 : 2]'], 'E719:')
|
||||
|
||||
call assert_fails("let v = [4, 6][{-> 1}]", 'E729:')
|
||||
call CheckDefAndScriptFailure(['var v = [4, 6][() => 1]'], ['E1012', 'E703:'])
|
||||
call CheckDefAndScriptFailure(['var v = [4, 6][() => 1]'], ['E1012:', 'E703:'])
|
||||
|
||||
call CheckLegacyAndVim9Failure(['VAR v = range(5)[2 : []]'], ['E730:', 'E1012:', 'E730:'])
|
||||
|
||||
|
||||
@@ -1356,7 +1356,7 @@ func Test_cq_zero_exmode()
|
||||
let logfile = 'Xcq_log.txt'
|
||||
let out = system(GetVimCommand() .. ' --clean --log ' .. logfile .. ' -es -X -c "argdelete foobar" -c"7cq"')
|
||||
call assert_equal(8, v:shell_error)
|
||||
let log = filter(readfile(logfile), {idx, val -> val =~ "E480"})
|
||||
let log = filter(readfile(logfile), {idx, val -> val =~ "E480:"})
|
||||
call assert_match('E480: No match: foobar', log[0])
|
||||
call delete(logfile)
|
||||
|
||||
@@ -1367,7 +1367,7 @@ func Test_cq_zero_exmode()
|
||||
else
|
||||
call assert_equal(256, v:shell_error)
|
||||
endif
|
||||
let log = filter(readfile(logfile), {idx, val -> val =~ "E480"})
|
||||
let log = filter(readfile(logfile), {idx, val -> val =~ "E480:"})
|
||||
call assert_match('E480: No match: foobar', log[0])
|
||||
call delete('Xcq_log.txt')
|
||||
endfunc
|
||||
|
||||
@@ -1850,7 +1850,7 @@ func T75_R()
|
||||
Xpath 'f'
|
||||
finally
|
||||
Xpath 'g'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
|
||||
Xpath 'h'
|
||||
endif
|
||||
break " discard error for $VIMNOERRTHROW
|
||||
@@ -1877,7 +1877,7 @@ func Test_builtin_func_error()
|
||||
Xpath 'k'
|
||||
finally
|
||||
Xpath 'l'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
|
||||
Xpath 'm'
|
||||
endif
|
||||
break " discard error for $VIMNOERRTHROW
|
||||
@@ -1896,7 +1896,7 @@ func Test_builtin_func_error()
|
||||
Xpath 'o'
|
||||
finally
|
||||
Xpath 'p'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
|
||||
Xpath 'q'
|
||||
endif
|
||||
break " discard error for $VIMNOERRTHROW
|
||||
@@ -1915,7 +1915,7 @@ func Test_builtin_func_error()
|
||||
Xpath 's'
|
||||
finally
|
||||
Xpath 't'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
|
||||
Xpath 'u'
|
||||
endif
|
||||
break " discard error for $VIMNOERRTHROW
|
||||
@@ -1938,7 +1938,7 @@ func Test_builtin_func_error()
|
||||
Xpath 'x'
|
||||
finally
|
||||
Xpath 'y'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
|
||||
Xpath 'z'
|
||||
endif
|
||||
break " discard error for $VIMNOERRTHROW
|
||||
@@ -1958,7 +1958,7 @@ func Test_builtin_func_error()
|
||||
Xpath 'B'
|
||||
finally
|
||||
Xpath 'C'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
|
||||
if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
|
||||
Xpath 'D'
|
||||
endif
|
||||
call assert_equal('a', x)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
source check.vim
|
||||
source screendump.vim
|
||||
source vim9.vim
|
||||
|
||||
" Test for <mods> in user defined commands
|
||||
function Test_cmdmods()
|
||||
@@ -307,13 +308,26 @@ func Test_CmdErrors()
|
||||
call assert_fails('com! -complete=custom DoCmd :', 'E467:')
|
||||
call assert_fails('com! -complete=customlist DoCmd :', 'E467:')
|
||||
" call assert_fails('com! -complete=behave,CustomComplete DoCmd :', 'E468:')
|
||||
call assert_fails('com! -complete=file DoCmd :', 'E1208:')
|
||||
call assert_fails('com! -nargs=0 -complete=file DoCmd :', 'E1208:')
|
||||
call assert_fails('com! -nargs=x DoCmd :', 'E176:')
|
||||
call assert_fails('com! -count=1 -count=2 DoCmd :', 'E177:')
|
||||
call assert_fails('com! -count=x DoCmd :', 'E178:')
|
||||
call assert_fails('com! -range=x DoCmd :', 'E178:')
|
||||
|
||||
call assert_fails('com! -complete=file DoCmd :', 'E1208:')
|
||||
call assert_fails('com! -nargs=0 -complete=file DoCmd :', 'E1208:')
|
||||
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
com! -complete=file DoCmd :
|
||||
END
|
||||
call CheckScriptFailure(lines, 'E1208:', 2)
|
||||
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
com! -nargs=0 -complete=file DoCmd :
|
||||
END
|
||||
call CheckScriptFailure(lines, 'E1208:', 2)
|
||||
|
||||
com! -nargs=0 DoCmd :
|
||||
call assert_fails('DoCmd x', 'E488:')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user