aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/window.c
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2017-03-20 02:48:28 +0100
committerJustin M. Keyes <justinkz@gmail.com>2017-03-22 18:42:16 +0100
commitb9e1289819183f94afb43330a7e0d953869e2af7 (patch)
tree4b2a5116430921f3f93153822a6461f694a88d65 /src/nvim/window.c
parent06ed7a189b2c1dca88f307538b9739b989776068 (diff)
downloadrneovim-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.c58
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.
*/