aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/ex_docmd.c6
-rw-r--r--src/nvim/testdir/test_autocmd.vim20
-rw-r--r--src/nvim/window.c21
-rw-r--r--test/functional/editor/tabpage_spec.lua42
-rw-r--r--test/functional/terminal/buffer_spec.lua6
5 files changed, 77 insertions, 18 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index b01a262f84..085948f7b1 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -4696,7 +4696,6 @@ void tabpage_close(int forceit)
void tabpage_close_other(tabpage_T *tp, int forceit)
{
int done = 0;
- int h = tabline_height();
char prev_idx[NUMBUFLEN];
// Limit to 1000 windows, autocommands may add a window while we close
@@ -4712,11 +4711,6 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
break;
}
}
-
- redraw_tabline = true;
- if (h != tabline_height()) {
- win_new_screen_rows();
- }
}
/// ":only".
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 1be2d11034..d766256d4b 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -447,6 +447,26 @@ func Test_WinClosed_throws_with_tabs()
augroup! test-WinClosed
endfunc
+" This used to trigger WinClosed twice for the same window, and the window's
+" buffer was NULL in the second autocommand.
+func Test_WinClosed_switch_tab()
+ edit Xa
+ split Xb
+ split Xc
+ tab split
+ new
+ augroup test-WinClosed
+ autocmd WinClosed * tabprev | bwipe!
+ augroup END
+ close
+ " Check that the tabline has been fully removed
+ call assert_equal([1, 1], win_screenpos(0))
+
+ autocmd! test-WinClosed
+ augroup! test-WinClosed
+ %bwipe!
+endfunc
+
func s:AddAnAutocmd()
augroup vimBarTest
au BufReadCmd * echo 'hello'
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 236663dfea..22c1b77570 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -2439,7 +2439,6 @@ void curwin_init(void)
void close_windows(buf_T *buf, bool keep_curwin)
{
tabpage_T *tp, *nexttp;
- int h = tabline_height();
RedrawingDisabled++;
@@ -2480,11 +2479,6 @@ void close_windows(buf_T *buf, bool keep_curwin)
}
RedrawingDisabled--;
-
- redraw_tabline = true;
- if (h != tabline_height()) {
- win_new_screen_rows();
- }
}
/// Check that the specified window is the last one.
@@ -2575,7 +2569,6 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
// Don't trigger autocommands yet, they may use wrong values, so do
// that below.
goto_tabpage_tp(alt_tabpage(), false, true);
- redraw_tabline = true;
// save index for tabclosed event
char_u prev_idx[NUMBUFLEN];
@@ -2584,12 +2577,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
// Safety check: Autocommands may have closed the window when jumping
// to the other tab page.
if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win) {
- int h = tabline_height();
-
win_close_othertab(win, free_buf, prev_curtab);
- if (h != tabline_height()) {
- win_new_screen_rows();
- }
}
entering_window(curwin);
@@ -2793,7 +2781,10 @@ int win_close(win_T *win, bool free_buf, bool force)
if (curtab != prev_curtab && win_valid_any_tab(win)
&& win->w_buffer == NULL) {
// Need to close the window anyway, since the buffer is NULL.
+ // Don't trigger autocmds with a NULL buffer.
+ block_autocmds();
win_close_othertab(win, false, prev_curtab);
+ unblock_autocmds();
return FAIL;
}
@@ -2990,6 +2981,8 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
vim_snprintf(prev_idx, NUMBUFLEN, "%i", tabpage_index(tp));
}
+ int h = tabline_height();
+
if (tp == first_tabpage) {
first_tabpage = tp->tp_next;
} else {
@@ -3004,6 +2997,10 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
ptp->tp_next = tp->tp_next;
}
free_tp = true;
+ redraw_tabline = true;
+ if (h != tabline_height()) {
+ win_new_screen_rows();
+ }
if (has_event(EVENT_TABCLOSED)) {
apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, win->w_buffer);
diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua
index 849a02c28b..01779a9a92 100644
--- a/test/functional/editor/tabpage_spec.lua
+++ b/test/functional/editor/tabpage_spec.lua
@@ -9,6 +9,9 @@ local feed = helpers.feed
local eval = helpers.eval
local exec = helpers.exec
local funcs = helpers.funcs
+local meths = helpers.meths
+local curwin = helpers.curwin
+local assert_alive = helpers.assert_alive
describe('tabpage', function()
before_each(clear)
@@ -54,6 +57,45 @@ describe('tabpage', function()
neq(999, eval('g:win_closed'))
end)
+ it('no segfault with strange WinClosed autocommand #20290', function()
+ pcall(exec, [[
+ set nohidden
+ edit Xa
+ split Xb
+ tab split
+ new
+ autocmd WinClosed * tabprev | bwipe!
+ close
+ ]])
+ assert_alive()
+ end)
+
+ it('nvim_win_close and nvim_win_hide update tabline #20285', function()
+ eq(1, #meths.list_tabpages())
+ eq({1, 1}, funcs.win_screenpos(0))
+ local win1 = curwin().id
+
+ command('tabnew')
+ eq(2, #meths.list_tabpages())
+ eq({2, 1}, funcs.win_screenpos(0))
+ local win2 = curwin().id
+
+ meths.win_close(win1, true)
+ eq(win2, curwin().id)
+ eq(1, #meths.list_tabpages())
+ eq({1, 1}, funcs.win_screenpos(0))
+
+ command('tabnew')
+ eq(2, #meths.list_tabpages())
+ eq({2, 1}, funcs.win_screenpos(0))
+ local win3 = curwin().id
+
+ meths.win_close(win2, true)
+ eq(win3, curwin().id)
+ eq(1, #meths.list_tabpages())
+ eq({1, 1}, funcs.win_screenpos(0))
+ end)
+
it('switching tabpage after setting laststatus=3 #19591', function()
local screen = Screen.new(40, 8)
screen:set_default_attr_ids({
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 23430a620b..9d10f43ec6 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -4,6 +4,7 @@ local assert_alive = helpers.assert_alive
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
local poke_eventloop = helpers.poke_eventloop
local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.source
+local pcall_err = helpers.pcall_err
local eq, neq = helpers.eq, helpers.neq
local meths = helpers.meths
local retry = helpers.retry
@@ -339,6 +340,11 @@ describe(':terminal buffer', function()
]]}
eq('t', funcs.mode(1))
end)
+
+ it('writing to an existing file with :w fails #13549', function()
+ eq('Vim(write):E13: File exists (add ! to override)',
+ pcall_err(command, 'write test/functional/fixtures/tty-test.c'))
+ end)
end)
describe('No heap-buffer-overflow when using', function()