diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2017-03-20 02:48:28 +0100 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2017-03-22 18:42:16 +0100 |
commit | b9e1289819183f94afb43330a7e0d953869e2af7 (patch) | |
tree | 4b2a5116430921f3f93153822a6461f694a88d65 /src/nvim/window.c | |
parent | 06ed7a189b2c1dca88f307538b9739b989776068 (diff) | |
download | rneovim-b9e1289819183f94afb43330a7e0d953869e2af7.tar.gz rneovim-b9e1289819183f94afb43330a7e0d953869e2af7.tar.bz2 rneovim-b9e1289819183f94afb43330a7e0d953869e2af7.zip |
vim-patch:8.0.0486
Problem: Crash and endless loop when closing windows in a SessionLoadPost
autocommand.
Solution: Check for valid tabpage. (partly neovim/neovim#6308)
https://github.com/vim/vim/commit/8c752bd6c4af54c0b7bac35a39acc2bf16015f85
Closes #6308
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r-- | src/nvim/window.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c index 6c9d3554f1..eda3cd7810 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -1714,14 +1714,10 @@ static void win_equal_rec( } } -/* - * close all windows for buffer 'buf' - */ -void -close_windows ( - buf_T *buf, - int keep_curwin /* don't close "curwin" */ -) +/// Closes all windows for buffer `buf`. +/// +/// @param keep_curwin don't close `curwin` +void close_windows(buf_T *buf, int keep_curwin) { tabpage_T *tp, *nexttp; int h = tabline_height(); @@ -1731,9 +1727,11 @@ close_windows ( for (win_T *wp = firstwin; wp != NULL && lastwin != firstwin; ) { if (wp->w_buffer == buf && (!keep_curwin || wp != curwin) - && !(wp->w_closing || wp->w_buffer->b_closing) - ) { - win_close(wp, FALSE); + && !(wp->w_closing || wp->w_buffer->b_closing)) { + if (win_close(wp, false) == FAIL) { + // If closing the window fails give up, to avoid looping forever. + break; + } /* Start all over, autocommands may change the window layout. */ wp = firstwin; @@ -3134,6 +3132,44 @@ bool valid_tabpage(tabpage_T *tpc) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT return false; } +/// Returns true when `tpc` is valid and at least one window is valid. +int valid_tabpage_win(tabpage_T *tpc) +{ + FOR_ALL_TABS(tp) { + if (tp == tpc) { + FOR_ALL_WINDOWS_IN_TAB(wp, tp) { + if (win_valid_any_tab(wp)) { + return true; + } + } + return false; + } + } + // shouldn't happen + return false; +} + +/// Close tabpage `tab`, assuming it has no windows in it. +/// There must be another tabpage or this will crash. +void close_tabpage(tabpage_T *tab) +{ + tabpage_T *ptp; + + if (tab == first_tabpage) { + first_tabpage = tab->tp_next; + ptp = first_tabpage; + } else { + for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab; + ptp = ptp->tp_next) { + // do nothing + } + ptp->tp_next = tab->tp_next; + } + + goto_tabpage_tp(ptp, false, false); + free_tabpage(tab); +} + /* * Find tab page "n" (first one is 1). Returns NULL when not found. */ |