]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
updated for version 7.3.545 v7.3.545
authorBram Moolenaar <Bram@vim.org>
Wed, 6 Jun 2012 17:02:45 +0000 (19:02 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 6 Jun 2012 17:02:45 +0000 (19:02 +0200)
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.

src/buffer.c
src/ex_docmd.c
src/structs.h
src/version.c
src/window.c

index 7ff949c021c97b82e6c2643f2be85f3fdbad4f3a..00d1f3535106a838bc6e91f232108c32b64b4f23 100644 (file)
@@ -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
index 8d9ceb77b584021214442ddcb5240b7edd22e4d3..6740a51da43b004000d9909898a26fb8f7d1db9f 100644 (file)
@@ -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
 
index 921a04935e43c98e21a3f177eb5922d3ca31ad24..abcb7045d6c987c713171919b7ce9453c6f44096 100644 (file)
@@ -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 */
 
index 8f98f51feb4c4f0ef3bc901f6a17125260274fcc..17c2d6417bb15c261c427a0209f59240d034e74c 100644 (file)
@@ -714,6 +714,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    545,
 /**/
     544,
 /**/
index 9f5e39efcdc5758ac86581a1753ac262121a360f..ecf2aa29ab8f53c0926ef4c22efff12cb6b6cb18 100644 (file)
@@ -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);