Karsten Hopp a77737
To: vim_dev@googlegroups.com
Karsten Hopp a77737
Subject: Patch 7.3.545
Karsten Hopp a77737
Fcc: outbox
Karsten Hopp a77737
From: Bram Moolenaar <Bram@moolenaar.net>
Karsten Hopp a77737
Mime-Version: 1.0
Karsten Hopp a77737
Content-Type: text/plain; charset=UTF-8
Karsten Hopp a77737
Content-Transfer-Encoding: 8bit
Karsten Hopp a77737
------------
Karsten Hopp a77737
Karsten Hopp a77737
Patch 7.3.545
Karsten Hopp a77737
Problem:    When closing a window or buffer autocommands may close it too,
Karsten Hopp a77737
	    causing problems for where the autocommand was invoked from.
Karsten Hopp a77737
Solution:   Add the w_closing and b_closing flags.  When set disallow ":q" and
Karsten Hopp a77737
	    ":close" to prevent recursive closing.
Karsten Hopp a77737
Files:	    src/structs.h, src/buffer.c, src/ex_docmd.c, src/window.c
Karsten Hopp a77737
Karsten Hopp a77737
Karsten Hopp a77737
*** ../vim-7.3.544/src/structs.h	2012-02-04 21:57:44.000000000 +0100
Karsten Hopp a77737
--- src/structs.h	2012-06-06 16:43:34.000000000 +0200
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 1201,1206 ****
Karsten Hopp a77737
--- 1201,1210 ----
Karsten Hopp a77737
  typedef struct qf_info_S qf_info_T;
Karsten Hopp a77737
  #endif
Karsten Hopp a77737
  
Karsten Hopp a77737
+ /*
Karsten Hopp a77737
+  * These are items normally related to a buffer.  But when using ":ownsyntax"
Karsten Hopp a77737
+  * a window may have its own instance.
Karsten Hopp a77737
+  */
Karsten Hopp a77737
  typedef struct {
Karsten Hopp a77737
  #ifdef FEAT_SYN_HL
Karsten Hopp a77737
      hashtab_T	b_keywtab;		/* syntax keywords hash table */
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 1290,1295 ****
Karsten Hopp a77737
--- 1294,1303 ----
Karsten Hopp a77737
      int		b_nwindows;	/* nr of windows open on this buffer */
Karsten Hopp a77737
  
Karsten Hopp a77737
      int		b_flags;	/* various BF_ flags */
Karsten Hopp a77737
+ #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
+     int		b_closing;	/* buffer is being closed, don't let
Karsten Hopp a77737
+ 				   autocommands close it too. */
Karsten Hopp a77737
+ #endif
Karsten Hopp a77737
  
Karsten Hopp a77737
      /*
Karsten Hopp a77737
       * b_ffname has the full path of the file (NULL for no name).
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 1853,1858 ****
Karsten Hopp a77737
--- 1861,1870 ----
Karsten Hopp a77737
      win_T	*w_prev;	    /* link to previous window */
Karsten Hopp a77737
      win_T	*w_next;	    /* link to next window */
Karsten Hopp a77737
  #endif
Karsten Hopp a77737
+ #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
+     int		w_closing;	    /* window is being closed, don't let
Karsten Hopp a77737
+ 				       autocommands close it too. */
Karsten Hopp a77737
+ #endif
Karsten Hopp a77737
  
Karsten Hopp a77737
      frame_T	*w_frame;	    /* frame containing this window */
Karsten Hopp a77737
  
Karsten Hopp a77737
*** ../vim-7.3.544/src/buffer.c	2012-03-16 14:32:10.000000000 +0100
Karsten Hopp a77737
--- src/buffer.c	2012-06-06 18:57:27.000000000 +0200
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 377,404 ****
Karsten Hopp a77737
      /* When the buffer is no longer in a window, trigger BufWinLeave */
Karsten Hopp a77737
      if (buf->b_nwindows == 1)
Karsten Hopp a77737
      {
Karsten Hopp a77737
  	apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
Karsten Hopp a77737
  								  FALSE, buf);
Karsten Hopp a77737
! 	/* Return if autocommands deleted the buffer or made it the only one. */
Karsten Hopp a77737
! 	if (!buf_valid(buf) || (abort_if_last && one_window()))
Karsten Hopp a77737
  	{
Karsten Hopp a77737
  	    EMSG(_(e_auabort));
Karsten Hopp a77737
  	    return;
Karsten Hopp a77737
  	}
Karsten Hopp a77737
  
Karsten Hopp a77737
  	/* When the buffer becomes hidden, but is not unloaded, trigger
Karsten Hopp a77737
  	 * BufHidden */
Karsten Hopp a77737
  	if (!unload_buf)
Karsten Hopp a77737
  	{
Karsten Hopp a77737
  	    apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
Karsten Hopp a77737
  								  FALSE, buf);
Karsten Hopp a77737
! 	    /* Return if autocommands deleted the buffer or made it the only
Karsten Hopp a77737
! 	     * one. */
Karsten Hopp a77737
! 	    if (!buf_valid(buf) || (abort_if_last && one_window()))
Karsten Hopp a77737
! 	    {
Karsten Hopp a77737
! 		EMSG(_(e_auabort));
Karsten Hopp a77737
! 		return;
Karsten Hopp a77737
! 	    }
Karsten Hopp a77737
  	}
Karsten Hopp a77737
  # ifdef FEAT_EVAL
Karsten Hopp a77737
  	if (aborting())	    /* autocmds may abort script processing */
Karsten Hopp a77737
--- 377,411 ----
Karsten Hopp a77737
      /* When the buffer is no longer in a window, trigger BufWinLeave */
Karsten Hopp a77737
      if (buf->b_nwindows == 1)
Karsten Hopp a77737
      {
Karsten Hopp a77737
+ 	buf->b_closing = TRUE;
Karsten Hopp a77737
  	apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
Karsten Hopp a77737
  								  FALSE, buf);
Karsten Hopp a77737
! 	if (!buf_valid(buf))
Karsten Hopp a77737
  	{
Karsten Hopp a77737
+ 	    /* Autocommands deleted the buffer. */
Karsten Hopp a77737
+ aucmd_abort:
Karsten Hopp a77737
  	    EMSG(_(e_auabort));
Karsten Hopp a77737
  	    return;
Karsten Hopp a77737
  	}
Karsten Hopp a77737
+ 	buf->b_closing = FALSE;
Karsten Hopp a77737
+ 	if (abort_if_last && one_window())
Karsten Hopp a77737
+ 	    /* Autocommands made this the only window. */
Karsten Hopp a77737
+ 	    goto aucmd_abort;
Karsten Hopp a77737
  
Karsten Hopp a77737
  	/* When the buffer becomes hidden, but is not unloaded, trigger
Karsten Hopp a77737
  	 * BufHidden */
Karsten Hopp a77737
  	if (!unload_buf)
Karsten Hopp a77737
  	{
Karsten Hopp a77737
+ 	    buf->b_closing = TRUE;
Karsten Hopp a77737
  	    apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
Karsten Hopp a77737
  								  FALSE, buf);
Karsten Hopp a77737
! 	    if (!buf_valid(buf))
Karsten Hopp a77737
! 		/* Autocommands deleted the buffer. */
Karsten Hopp a77737
! 		goto aucmd_abort;
Karsten Hopp a77737
! 	    buf->b_closing = FALSE;
Karsten Hopp a77737
! 	    if (abort_if_last && one_window())
Karsten Hopp a77737
! 		/* Autocommands made this the only window. */
Karsten Hopp a77737
! 		goto aucmd_abort;
Karsten Hopp a77737
  	}
Karsten Hopp a77737
  # ifdef FEAT_EVAL
Karsten Hopp a77737
  	if (aborting())	    /* autocmds may abort script processing */
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 552,557 ****
Karsten Hopp a77737
--- 559,565 ----
Karsten Hopp a77737
  #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
      int		is_curbuf = (buf == curbuf);
Karsten Hopp a77737
  
Karsten Hopp a77737
+     buf->b_closing = TRUE;
Karsten Hopp a77737
      apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, FALSE, buf);
Karsten Hopp a77737
      if (!buf_valid(buf))	    /* autocommands may delete the buffer */
Karsten Hopp a77737
  	return;
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 568,573 ****
Karsten Hopp a77737
--- 576,582 ----
Karsten Hopp a77737
  	if (!buf_valid(buf))	    /* autocommands may delete the buffer */
Karsten Hopp a77737
  	    return;
Karsten Hopp a77737
      }
Karsten Hopp a77737
+     buf->b_closing = FALSE;
Karsten Hopp a77737
  # ifdef FEAT_EVAL
Karsten Hopp a77737
      if (aborting())	    /* autocmds may abort script processing */
Karsten Hopp a77737
  	return;
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 1150,1155 ****
Karsten Hopp a77737
--- 1159,1167 ----
Karsten Hopp a77737
  	 * a window with this buffer.
Karsten Hopp a77737
  	 */
Karsten Hopp a77737
  	while (buf == curbuf
Karsten Hopp a77737
+ # ifdef FEAT_AUTOCMD
Karsten Hopp a77737
+ 		   && !(curwin->w_closing || curwin->w_buffer->b_closing)
Karsten Hopp a77737
+ # endif
Karsten Hopp a77737
  		   && (firstwin != lastwin || first_tabpage->tp_next != NULL))
Karsten Hopp a77737
  	    win_close(curwin, FALSE);
Karsten Hopp a77737
  #endif
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 4750,4756 ****
Karsten Hopp a77737
  #ifdef FEAT_WINDOWS
Karsten Hopp a77737
  		    || (had_tab > 0 && wp != firstwin)
Karsten Hopp a77737
  #endif
Karsten Hopp a77737
! 		    ) && firstwin != lastwin)
Karsten Hopp a77737
  	    {
Karsten Hopp a77737
  		win_close(wp, FALSE);
Karsten Hopp a77737
  #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
--- 4762,4772 ----
Karsten Hopp a77737
  #ifdef FEAT_WINDOWS
Karsten Hopp a77737
  		    || (had_tab > 0 && wp != firstwin)
Karsten Hopp a77737
  #endif
Karsten Hopp a77737
! 		    ) && firstwin != lastwin
Karsten Hopp a77737
! #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
! 		    && !(wp->w_closing || wp->w_buffer->b_closing)
Karsten Hopp a77737
! #endif
Karsten Hopp a77737
! 		    )
Karsten Hopp a77737
  	    {
Karsten Hopp a77737
  		win_close(wp, FALSE);
Karsten Hopp a77737
  #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
*** ../vim-7.3.544/src/ex_docmd.c	2012-06-06 18:03:01.000000000 +0200
Karsten Hopp a77737
--- src/ex_docmd.c	2012-06-06 18:06:46.000000000 +0200
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 6459,6465 ****
Karsten Hopp a77737
      }
Karsten Hopp a77737
  #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
      apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
Karsten Hopp a77737
!     if (curbuf_locked())
Karsten Hopp a77737
  	return;
Karsten Hopp a77737
  #endif
Karsten Hopp a77737
  
Karsten Hopp a77737
--- 6459,6467 ----
Karsten Hopp a77737
      }
Karsten Hopp a77737
  #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
      apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
Karsten Hopp a77737
!     /* Refuse to quick when locked or when the buffer in the last window is
Karsten Hopp a77737
!      * being closed (can only happen in autocommands). */
Karsten Hopp a77737
!     if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
Karsten Hopp a77737
  	return;
Karsten Hopp a77737
  #endif
Karsten Hopp a77737
  
Karsten Hopp a77737
*** ../vim-7.3.544/src/window.c	2012-05-25 12:38:57.000000000 +0200
Karsten Hopp a77737
--- src/window.c	2012-06-06 18:47:19.000000000 +0200
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 2034,2040 ****
Karsten Hopp a77737
  
Karsten Hopp a77737
      for (wp = firstwin; wp != NULL && lastwin != firstwin; )
Karsten Hopp a77737
      {
Karsten Hopp a77737
! 	if (wp->w_buffer == buf && (!keep_curwin || wp != curwin))
Karsten Hopp a77737
  	{
Karsten Hopp a77737
  	    win_close(wp, FALSE);
Karsten Hopp a77737
  
Karsten Hopp a77737
--- 2034,2044 ----
Karsten Hopp a77737
  
Karsten Hopp a77737
      for (wp = firstwin; wp != NULL && lastwin != firstwin; )
Karsten Hopp a77737
      {
Karsten Hopp a77737
! 	if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
Karsten Hopp a77737
! #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
! 		&& !(wp->w_closing || wp->w_buffer->b_closing)
Karsten Hopp a77737
! #endif
Karsten Hopp a77737
! 		)
Karsten Hopp a77737
  	{
Karsten Hopp a77737
  	    win_close(wp, FALSE);
Karsten Hopp a77737
  
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 2051,2057 ****
Karsten Hopp a77737
  	nexttp = tp->tp_next;
Karsten Hopp a77737
  	if (tp != curtab)
Karsten Hopp a77737
  	    for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
Karsten Hopp a77737
! 		if (wp->w_buffer == buf)
Karsten Hopp a77737
  		{
Karsten Hopp a77737
  		    win_close_othertab(wp, FALSE, tp);
Karsten Hopp a77737
  
Karsten Hopp a77737
--- 2055,2065 ----
Karsten Hopp a77737
  	nexttp = tp->tp_next;
Karsten Hopp a77737
  	if (tp != curtab)
Karsten Hopp a77737
  	    for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
Karsten Hopp a77737
! 		if (wp->w_buffer == buf
Karsten Hopp a77737
! #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
! 		    && !(wp->w_closing || wp->w_buffer->b_closing)
Karsten Hopp a77737
! #endif
Karsten Hopp a77737
! 		    )
Karsten Hopp a77737
  		{
Karsten Hopp a77737
  		    win_close_othertab(wp, FALSE, tp);
Karsten Hopp a77737
  
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 2168,2173 ****
Karsten Hopp a77737
--- 2176,2183 ----
Karsten Hopp a77737
      }
Karsten Hopp a77737
  
Karsten Hopp a77737
  #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
+     if (win->w_closing || win->w_buffer->b_closing)
Karsten Hopp a77737
+ 	return; /* window is already being closed */
Karsten Hopp a77737
      if (win == aucmd_win)
Karsten Hopp a77737
      {
Karsten Hopp a77737
  	EMSG(_("E813: Cannot close autocmd window"));
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 2203,2219 ****
Karsten Hopp a77737
  	wp = frame2win(win_altframe(win, NULL));
Karsten Hopp a77737
  
Karsten Hopp a77737
  	/*
Karsten Hopp a77737
! 	 * Be careful: If autocommands delete the window, return now.
Karsten Hopp a77737
  	 */
Karsten Hopp a77737
  	if (wp->w_buffer != curbuf)
Karsten Hopp a77737
  	{
Karsten Hopp a77737
  	    other_buffer = TRUE;
Karsten Hopp a77737
  	    apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
Karsten Hopp a77737
! 	    if (!win_valid(win) || last_window())
Karsten Hopp a77737
  		return;
Karsten Hopp a77737
  	}
Karsten Hopp a77737
  	apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
Karsten Hopp a77737
! 	if (!win_valid(win) || last_window())
Karsten Hopp a77737
  	    return;
Karsten Hopp a77737
  # ifdef FEAT_EVAL
Karsten Hopp a77737
  	/* autocmds may abort script processing */
Karsten Hopp a77737
--- 2213,2238 ----
Karsten Hopp a77737
  	wp = frame2win(win_altframe(win, NULL));
Karsten Hopp a77737
  
Karsten Hopp a77737
  	/*
Karsten Hopp a77737
! 	 * Be careful: If autocommands delete the window or cause this window
Karsten Hopp a77737
! 	 * to be the last one left, return now.
Karsten Hopp a77737
  	 */
Karsten Hopp a77737
  	if (wp->w_buffer != curbuf)
Karsten Hopp a77737
  	{
Karsten Hopp a77737
  	    other_buffer = TRUE;
Karsten Hopp a77737
+ 	    win->w_closing = TRUE;
Karsten Hopp a77737
  	    apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
Karsten Hopp a77737
! 	    if (!win_valid(win))
Karsten Hopp a77737
! 		return;
Karsten Hopp a77737
! 	    win->w_closing = FALSE;
Karsten Hopp a77737
! 	    if (last_window())
Karsten Hopp a77737
  		return;
Karsten Hopp a77737
  	}
Karsten Hopp a77737
+ 	win->w_closing = TRUE;
Karsten Hopp a77737
  	apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
Karsten Hopp a77737
! 	if (!win_valid(win))
Karsten Hopp a77737
! 	    return;
Karsten Hopp a77737
! 	win->w_closing = FALSE;
Karsten Hopp a77737
! 	if (last_window())
Karsten Hopp a77737
  	    return;
Karsten Hopp a77737
  # ifdef FEAT_EVAL
Karsten Hopp a77737
  	/* autocmds may abort script processing */
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 2240,2246 ****
Karsten Hopp a77737
       * Close the link to the buffer.
Karsten Hopp a77737
       */
Karsten Hopp a77737
      if (win->w_buffer != NULL)
Karsten Hopp a77737
! 	close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
Karsten Hopp a77737
  
Karsten Hopp a77737
      /* Autocommands may have closed the window already, or closed the only
Karsten Hopp a77737
       * other window or moved to another tab page. */
Karsten Hopp a77737
--- 2259,2274 ----
Karsten Hopp a77737
       * Close the link to the buffer.
Karsten Hopp a77737
       */
Karsten Hopp a77737
      if (win->w_buffer != NULL)
Karsten Hopp a77737
!     {
Karsten Hopp a77737
! #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
! 	win->w_closing = TRUE;
Karsten Hopp a77737
! #endif
Karsten Hopp a77737
! 	close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
Karsten Hopp a77737
! #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
! 	if (win_valid(win))
Karsten Hopp a77737
! 	    win->w_closing = FALSE;
Karsten Hopp a77737
! #endif
Karsten Hopp a77737
!     }
Karsten Hopp a77737
  
Karsten Hopp a77737
      /* Autocommands may have closed the window already, or closed the only
Karsten Hopp a77737
       * other window or moved to another tab page. */
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 2346,2351 ****
Karsten Hopp a77737
--- 2374,2384 ----
Karsten Hopp a77737
      tabpage_T   *ptp = NULL;
Karsten Hopp a77737
      int		free_tp = FALSE;
Karsten Hopp a77737
  
Karsten Hopp a77737
+ #ifdef FEAT_AUTOCMD
Karsten Hopp a77737
+     if (win->w_closing || win->w_buffer->b_closing)
Karsten Hopp a77737
+ 	return; /* window is already being closed */
Karsten Hopp a77737
+ #endif
Karsten Hopp a77737
+ 
Karsten Hopp a77737
      /* Close the link to the buffer. */
Karsten Hopp a77737
      close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
Karsten Hopp a77737
  
Karsten Hopp a77737
*** ../vim-7.3.544/src/version.c	2012-06-06 18:03:01.000000000 +0200
Karsten Hopp a77737
--- src/version.c	2012-06-06 18:53:06.000000000 +0200
Karsten Hopp a77737
***************
Karsten Hopp a77737
*** 716,717 ****
Karsten Hopp a77737
--- 716,719 ----
Karsten Hopp a77737
  {   /* Add new patch number below this line */
Karsten Hopp a77737
+ /**/
Karsten Hopp a77737
+     545,
Karsten Hopp a77737
  /**/
Karsten Hopp a77737
Karsten Hopp a77737
-- 
Karsten Hopp a77737
How To Keep A Healthy Level Of Insanity:
Karsten Hopp a77737
4. Put your garbage can on your desk and label it "in".
Karsten Hopp a77737
Karsten Hopp a77737
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
Karsten Hopp a77737
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
Karsten Hopp a77737
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
Karsten Hopp a77737
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///