summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <bram@vim.org>2012-06-06 19:02:45 +0200
committerBram Moolenaar <bram@vim.org>2012-06-06 19:02:45 +0200
commit65135be3d079b9779c470e11e940417c44991cb9 (patch)
treed1c78a39ee28222bfc96fd2bc331f2ef1528d7bb
parentf2dc59d8062fa5a2b885587db4dd230f5e99a015 (diff)
downloadvim-65135be3d079b9779c470e11e940417c44991cb9.tar.gz
updated for version 7.3.545v7.3.545v7-3-545
Problem: When closing a window or buffer autocommands may close it too, causing problems for where the autocommand was invoked from. Solution: Add the w_closing and b_closing flags. When set disallow ":q" and ":close" to prevent recursive closing.
-rw-r--r--src/buffer.c36
-rw-r--r--src/ex_docmd.c4
-rw-r--r--src/structs.h12
-rw-r--r--src/version.c2
-rw-r--r--src/window.c45
5 files changed, 82 insertions, 17 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 7ff949c0..00d1f353 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -377,28 +377,35 @@ close_buffer(win, buf, action, abort_if_last)
/* When the buffer is no longer in a window, trigger BufWinLeave */
if (buf->b_nwindows == 1)
{
+ buf->b_closing = TRUE;
apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
FALSE, buf);
- /* Return if autocommands deleted the buffer or made it the only one. */
- if (!buf_valid(buf) || (abort_if_last && one_window()))
+ if (!buf_valid(buf))
{
+ /* Autocommands deleted the buffer. */
+aucmd_abort:
EMSG(_(e_auabort));
return;
}
+ buf->b_closing = FALSE;
+ if (abort_if_last && one_window())
+ /* Autocommands made this the only window. */
+ goto aucmd_abort;
/* When the buffer becomes hidden, but is not unloaded, trigger
* BufHidden */
if (!unload_buf)
{
+ buf->b_closing = TRUE;
apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
FALSE, buf);
- /* Return if autocommands deleted the buffer or made it the only
- * one. */
- if (!buf_valid(buf) || (abort_if_last && one_window()))
- {
- EMSG(_(e_auabort));
- return;
- }
+ if (!buf_valid(buf))
+ /* Autocommands deleted the buffer. */
+ goto aucmd_abort;
+ buf->b_closing = FALSE;
+ if (abort_if_last && one_window())
+ /* Autocommands made this the only window. */
+ goto aucmd_abort;
}
# ifdef FEAT_EVAL
if (aborting()) /* autocmds may abort script processing */
@@ -552,6 +559,7 @@ buf_freeall(buf, flags)
#ifdef FEAT_AUTOCMD
int is_curbuf = (buf == curbuf);
+ buf->b_closing = TRUE;
apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, FALSE, buf);
if (!buf_valid(buf)) /* autocommands may delete the buffer */
return;
@@ -568,6 +576,7 @@ buf_freeall(buf, flags)
if (!buf_valid(buf)) /* autocommands may delete the buffer */
return;
}
+ buf->b_closing = FALSE;
# ifdef FEAT_EVAL
if (aborting()) /* autocmds may abort script processing */
return;
@@ -1150,6 +1159,9 @@ do_buffer(action, start, dir, count, forceit)
* a window with this buffer.
*/
while (buf == curbuf
+# ifdef FEAT_AUTOCMD
+ && !(curwin->w_closing || curwin->w_buffer->b_closing)
+# endif
&& (firstwin != lastwin || first_tabpage->tp_next != NULL))
win_close(curwin, FALSE);
#endif
@@ -4750,7 +4762,11 @@ ex_buffer_all(eap)
#ifdef FEAT_WINDOWS
|| (had_tab > 0 && wp != firstwin)
#endif
- ) && firstwin != lastwin)
+ ) && firstwin != lastwin
+#ifdef FEAT_AUTOCMD
+ && !(wp->w_closing || wp->w_buffer->b_closing)
+#endif
+ )
{
win_close(wp, FALSE);
#ifdef FEAT_AUTOCMD
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 8d9ceb77..6740a51d 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -6459,7 +6459,9 @@ ex_quit(eap)
}
#ifdef FEAT_AUTOCMD
apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
- if (curbuf_locked())
+ /* Refuse to quick when locked or when the buffer in the last window is
+ * being closed (can only happen in autocommands). */
+ if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
return;
#endif
diff --git a/src/structs.h b/src/structs.h
index 921a0493..abcb7045 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1201,6 +1201,10 @@ struct dictvar_S
typedef struct qf_info_S qf_info_T;
#endif
+/*
+ * These are items normally related to a buffer. But when using ":ownsyntax"
+ * a window may have its own instance.
+ */
typedef struct {
#ifdef FEAT_SYN_HL
hashtab_T b_keywtab; /* syntax keywords hash table */
@@ -1290,6 +1294,10 @@ struct file_buffer
int b_nwindows; /* nr of windows open on this buffer */
int b_flags; /* various BF_ flags */
+#ifdef FEAT_AUTOCMD
+ int b_closing; /* buffer is being closed, don't let
+ autocommands close it too. */
+#endif
/*
* b_ffname has the full path of the file (NULL for no name).
@@ -1853,6 +1861,10 @@ struct window_S
win_T *w_prev; /* link to previous window */
win_T *w_next; /* link to next window */
#endif
+#ifdef FEAT_AUTOCMD
+ int w_closing; /* window is being closed, don't let
+ autocommands close it too. */
+#endif
frame_T *w_frame; /* frame containing this window */
diff --git a/src/version.c b/src/version.c
index 8f98f51f..17c2d641 100644
--- a/src/version.c
+++ b/src/version.c
@@ -715,6 +715,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 545,
+/**/
544,
/**/
543,
diff --git a/src/window.c b/src/window.c
index 9f5e39ef..ecf2aa29 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2034,7 +2034,11 @@ close_windows(buf, keep_curwin)
for (wp = firstwin; wp != NULL && lastwin != firstwin; )
{
- if (wp->w_buffer == buf && (!keep_curwin || wp != curwin))
+ if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
+#ifdef FEAT_AUTOCMD
+ && !(wp->w_closing || wp->w_buffer->b_closing)
+#endif
+ )
{
win_close(wp, FALSE);
@@ -2051,7 +2055,11 @@ close_windows(buf, keep_curwin)
nexttp = tp->tp_next;
if (tp != curtab)
for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
- if (wp->w_buffer == buf)
+ if (wp->w_buffer == buf
+#ifdef FEAT_AUTOCMD
+ && !(wp->w_closing || wp->w_buffer->b_closing)
+#endif
+ )
{
win_close_othertab(wp, FALSE, tp);
@@ -2168,6 +2176,8 @@ win_close(win, free_buf)
}
#ifdef FEAT_AUTOCMD
+ if (win->w_closing || win->w_buffer->b_closing)
+ return; /* window is already being closed */
if (win == aucmd_win)
{
EMSG(_("E813: Cannot close autocmd window"));
@@ -2203,17 +2213,26 @@ win_close(win, free_buf)
wp = frame2win(win_altframe(win, NULL));
/*
- * Be careful: If autocommands delete the window, return now.
+ * Be careful: If autocommands delete the window or cause this window
+ * to be the last one left, return now.
*/
if (wp->w_buffer != curbuf)
{
other_buffer = TRUE;
+ win->w_closing = TRUE;
apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
- if (!win_valid(win) || last_window())
+ if (!win_valid(win))
+ return;
+ win->w_closing = FALSE;
+ if (last_window())
return;
}
+ win->w_closing = TRUE;
apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
- if (!win_valid(win) || last_window())
+ if (!win_valid(win))
+ return;
+ win->w_closing = FALSE;
+ if (last_window())
return;
# ifdef FEAT_EVAL
/* autocmds may abort script processing */
@@ -2240,7 +2259,16 @@ win_close(win, free_buf)
* Close the link to the buffer.
*/
if (win->w_buffer != NULL)
- close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
+ {
+#ifdef FEAT_AUTOCMD
+ win->w_closing = TRUE;
+#endif
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
+#ifdef FEAT_AUTOCMD
+ if (win_valid(win))
+ win->w_closing = FALSE;
+#endif
+ }
/* Autocommands may have closed the window already, or closed the only
* other window or moved to another tab page. */
@@ -2346,6 +2374,11 @@ win_close_othertab(win, free_buf, tp)
tabpage_T *ptp = NULL;
int free_tp = FALSE;
+#ifdef FEAT_AUTOCMD
+ if (win->w_closing || win->w_buffer->b_closing)
+ return; /* window is already being closed */
+#endif
+
/* Close the link to the buffer. */
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);