diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 5ec510d17f..0ed02e168a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5150,6 +5150,8 @@ void tabpage_close(int forceit) 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. while (curwin->w_floating) { @@ -5172,6 +5174,8 @@ void tabpage_close_other(tabpage_T *tp, int forceit) int done = 0; char prev_idx[NUMBUFLEN]; + 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/nvim/window.c b/src/nvim/window.c index 508b92cfaf..99ac0cc4f4 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3102,9 +3102,12 @@ static void do_autocmd_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, bool directly) { static bool recursive = false; + static bool skip = false; tabpage_T *ptp = curtab; // Quickly return when no TabClosedPre autocommands to be executed or @@ -3113,8 +3116,17 @@ static void trigger_tabclosedpre(tabpage_T *tp) 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(); @@ -3187,7 +3199,7 @@ 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); + trigger_tabclosedpre(tp, false); // autocmd may have freed the window already. if (!win_valid_any_tab(win)) { return false; diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index ae734e70ad..db6a992bd5 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -4760,7 +4760,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 @@ -4788,7 +4788,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