To: vim_dev@googlegroups.com Subject: Patch 7.3.449 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.3.449 Problem: Crash when a BufWinLeave autocommand closes the only other window. (Daniel Hunt) Solution: Abort closing a buffer when it becomes the only one. Files: src/buffer.c, src/proto/buffer.pro, src/ex_cmds.c, src/ex_getln.c, src/misc2.c, src/quickfix.c, src/window.c, src/proto/window.pro *** ../vim-7.3.448/src/buffer.c 2012-01-20 20:44:38.000000000 +0100 --- src/buffer.c 2012-02-22 14:50:42.000000000 +0100 *************** *** 64,69 **** --- 64,72 ---- static char *msg_loclist = N_("[Location List]"); static char *msg_qflist = N_("[Quickfix List]"); #endif + #ifdef FEAT_AUTOCMD + static char *e_auabort = N_("E855: Autocommands caused command to abort"); + #endif /* * Open current buffer, that is: open the memfile and read the file into *************** *** 96,102 **** * There MUST be a memfile, otherwise we can't do anything * If we can't create one for the current buffer, take another buffer */ ! close_buffer(NULL, curbuf, 0); for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) if (curbuf->b_ml.ml_mfp != NULL) break; --- 99,105 ---- * There MUST be a memfile, otherwise we can't do anything * If we can't create one for the current buffer, take another buffer */ ! close_buffer(NULL, curbuf, 0, FALSE); for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) if (curbuf->b_ml.ml_mfp != NULL) break; *************** *** 316,327 **** * get a new buffer very soon! * * The 'bufhidden' option can force freeing and deleting. */ void ! close_buffer(win, buf, action) win_T *win; /* if not NULL, set b_last_cursor */ buf_T *buf; int action; { #ifdef FEAT_AUTOCMD int is_curbuf; --- 319,335 ---- * get a new buffer very soon! * * The 'bufhidden' option can force freeing and deleting. + * + * When "abort_if_last" is TRUE then do not close the buffer if autocommands + * cause there to be only one window with this buffer. e.g. when ":quit" is + * supposed to close the window but autocommands close all other windows. */ void ! close_buffer(win, buf, action, abort_if_last) win_T *win; /* if not NULL, set b_last_cursor */ buf_T *buf; int action; + int abort_if_last; { #ifdef FEAT_AUTOCMD int is_curbuf; *************** *** 371,378 **** { apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, FALSE, buf); ! if (!buf_valid(buf)) /* autocommands may delete the buffer */ return; /* When the buffer becomes hidden, but is not unloaded, trigger * BufHidden */ --- 379,390 ---- { 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())) ! { ! EMSG(_(e_auabort)); return; + } /* When the buffer becomes hidden, but is not unloaded, trigger * BufHidden */ *************** *** 380,387 **** { apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, FALSE, buf); ! if (!buf_valid(buf)) /* autocmds may delete the buffer */ return; } # ifdef FEAT_EVAL if (aborting()) /* autocmds may abort script processing */ --- 392,404 ---- { 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; + } } # ifdef FEAT_EVAL if (aborting()) /* autocmds may abort script processing */ *************** *** 775,781 **** * open a new, empty buffer. */ swap_exists_action = SEA_NONE; /* don't want it again */ swap_exists_did_quit = TRUE; ! close_buffer(curwin, curbuf, DOBUF_UNLOAD); if (!buf_valid(old_curbuf) || old_curbuf == curbuf) old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); if (old_curbuf != NULL) --- 792,798 ---- * open a new, empty buffer. */ swap_exists_action = SEA_NONE; /* don't want it again */ swap_exists_did_quit = TRUE; ! close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE); if (!buf_valid(old_curbuf) || old_curbuf == curbuf) old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); if (old_curbuf != NULL) *************** *** 1122,1128 **** * if the buffer still exists. */ if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0) ! close_buffer(NULL, buf, action); return retval; } --- 1139,1145 ---- * if the buffer still exists. */ if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0) ! close_buffer(NULL, buf, action, FALSE); return retval; } *************** *** 1146,1152 **** close_windows(buf, FALSE); #endif if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0) ! close_buffer(NULL, buf, action); return OK; } --- 1163,1169 ---- close_windows(buf, FALSE); #endif if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0) ! close_buffer(NULL, buf, action, FALSE); return OK; } *************** *** 1378,1384 **** close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, unload ? action : (action == DOBUF_GOTO && !P_HID(prevbuf) ! && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0); } } #ifdef FEAT_AUTOCMD --- 1395,1401 ---- close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, unload ? action : (action == DOBUF_GOTO && !P_HID(prevbuf) ! && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE); } } #ifdef FEAT_AUTOCMD *************** *** 2708,2714 **** vim_free(ffname); return FAIL; } ! close_buffer(NULL, obuf, DOBUF_WIPE); /* delete from the list */ } sfname = vim_strsave(sfname); if (ffname == NULL || sfname == NULL) --- 2725,2732 ---- vim_free(ffname); return FAIL; } ! /* delete from the list */ ! close_buffer(NULL, obuf, DOBUF_WIPE, FALSE); } sfname = vim_strsave(sfname); if (ffname == NULL || sfname == NULL) *************** *** 5638,5644 **** if (!aucmd) /* Don't trigger BufDelete autocommands here. */ block_autocmds(); #endif ! close_buffer(NULL, buf, DOBUF_WIPE); #ifdef FEAT_AUTOCMD if (!aucmd) unblock_autocmds(); --- 5656,5662 ---- if (!aucmd) /* Don't trigger BufDelete autocommands here. */ block_autocmds(); #endif ! close_buffer(NULL, buf, DOBUF_WIPE, FALSE); #ifdef FEAT_AUTOCMD if (!aucmd) unblock_autocmds(); *** ../vim-7.3.448/src/proto/buffer.pro 2010-08-15 21:57:28.000000000 +0200 --- src/proto/buffer.pro 2012-02-22 14:04:26.000000000 +0100 *************** *** 1,7 **** /* buffer.c */ int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags)); int buf_valid __ARGS((buf_T *buf)); ! void close_buffer __ARGS((win_T *win, buf_T *buf, int action)); void buf_clear_file __ARGS((buf_T *buf)); void buf_freeall __ARGS((buf_T *buf, int flags)); void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count)); --- 1,7 ---- /* buffer.c */ int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags)); int buf_valid __ARGS((buf_T *buf)); ! void close_buffer __ARGS((win_T *win, buf_T *buf, int action, int abort_if_last)); void buf_clear_file __ARGS((buf_T *buf)); void buf_freeall __ARGS((buf_T *buf, int flags)); void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count)); *** ../vim-7.3.448/src/ex_cmds.c 2011-12-30 15:01:55.000000000 +0100 --- src/ex_cmds.c 2012-02-22 14:00:32.000000000 +0100 *************** *** 3387,3393 **** /* close the link to the current buffer */ u_sync(FALSE); close_buffer(oldwin, curbuf, ! (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD); #ifdef FEAT_AUTOCMD /* Autocommands may open a new window and leave oldwin open --- 3387,3393 ---- /* close the link to the current buffer */ u_sync(FALSE); close_buffer(oldwin, curbuf, ! (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE); #ifdef FEAT_AUTOCMD /* Autocommands may open a new window and leave oldwin open *** ../vim-7.3.448/src/ex_getln.c 2012-02-04 22:44:27.000000000 +0100 --- src/ex_getln.c 2012-02-22 14:01:56.000000000 +0100 *************** *** 6443,6449 **** /* win_close() may have already wiped the buffer when 'bh' is * set to 'wipe' */ if (buf_valid(bp)) ! close_buffer(NULL, bp, DOBUF_WIPE); /* Restore window sizes. */ win_size_restore(&winsizes); --- 6443,6449 ---- /* win_close() may have already wiped the buffer when 'bh' is * set to 'wipe' */ if (buf_valid(bp)) ! close_buffer(NULL, bp, DOBUF_WIPE, FALSE); /* Restore window sizes. */ win_size_restore(&winsizes); *** ../vim-7.3.448/src/misc2.c 2012-02-20 22:18:22.000000000 +0100 --- src/misc2.c 2012-02-22 14:02:12.000000000 +0100 *************** *** 1173,1179 **** for (buf = firstbuf; buf != NULL; ) { nextbuf = buf->b_next; ! close_buffer(NULL, buf, DOBUF_WIPE); if (buf_valid(buf)) buf = nextbuf; /* didn't work, try next one */ else --- 1173,1179 ---- for (buf = firstbuf; buf != NULL; ) { nextbuf = buf->b_next; ! close_buffer(NULL, buf, DOBUF_WIPE, FALSE); if (buf_valid(buf)) buf = nextbuf; /* didn't work, try next one */ else *** ../vim-7.3.448/src/quickfix.c 2012-01-20 13:39:03.000000000 +0100 --- src/quickfix.c 2012-02-22 14:02:20.000000000 +0100 *************** *** 3565,3571 **** buf_T *buf; { if (curbuf != buf) /* safety check */ ! close_buffer(NULL, buf, DOBUF_UNLOAD); } #if defined(FEAT_EVAL) || defined(PROTO) --- 3565,3571 ---- buf_T *buf; { if (curbuf != buf) /* safety check */ ! close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE); } #if defined(FEAT_EVAL) || defined(PROTO) *** ../vim-7.3.448/src/window.c 2012-01-10 22:26:12.000000000 +0100 --- src/window.c 2012-02-22 14:08:13.000000000 +0100 *************** *** 23,29 **** static void win_totop __ARGS((int size, int flags)); static void win_equal_rec __ARGS((win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height)); static int last_window __ARGS((void)); - static int one_window __ARGS((void)); static win_T *win_free_mem __ARGS((win_T *win, int *dirp, tabpage_T *tp)); static frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp)); static tabpage_T *alt_tabpage __ARGS((void)); --- 23,28 ---- *************** *** 2083,2089 **** * Return TRUE if there is only one window other than "aucmd_win" in the * current tab page. */ ! static int one_window() { #ifdef FEAT_AUTOCMD --- 2082,2088 ---- * Return TRUE if there is only one window other than "aucmd_win" in the * current tab page. */ ! int one_window() { #ifdef FEAT_AUTOCMD *************** *** 2109,2115 **** * Close window "win". Only works for the current tab page. * If "free_buf" is TRUE related buffer may be unloaded. * ! * called by :quit, :close, :xit, :wq and findtag() */ void win_close(win, free_buf) --- 2108,2114 ---- * Close window "win". Only works for the current tab page. * If "free_buf" is TRUE related buffer may be unloaded. * ! * Called by :quit, :close, :xit, :wq and findtag(). */ void win_close(win, free_buf) *************** *** 2222,2228 **** * Close the link to the buffer. */ if (win->w_buffer != NULL) ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0); /* Autocommands may have closed the window already, or closed the only * other window or moved to another tab page. */ --- 2221,2227 ---- * Close the link to the buffer. */ if (win->w_buffer != NULL) ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE); /* Autocommands may have closed the window already, or closed the only * other window or moved to another tab page. */ *************** *** 2328,2334 **** int free_tp = FALSE; /* Close the link to the buffer. */ ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0); /* Careful: Autocommands may have closed the tab page or made it the * current tab page. */ --- 2327,2333 ---- int free_tp = FALSE; /* Close the link to the buffer. */ ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE); /* Careful: Autocommands may have closed the tab page or made it the * current tab page. */ *** ../vim-7.3.448/src/proto/window.pro 2010-08-15 21:57:28.000000000 +0200 --- src/proto/window.pro 2012-02-22 14:08:28.000000000 +0100 *************** *** 1,13 **** /* window.c */ void do_window __ARGS((int nchar, long Prenum, int xchar)); int win_split __ARGS((int size, int flags)); ! int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir)); int win_valid __ARGS((win_T *win)); int win_count __ARGS((void)); int make_windows __ARGS((int count, int vertical)); void win_move_after __ARGS((win_T *win1, win_T *win2)); void win_equal __ARGS((win_T *next_curwin, int current, int dir)); void close_windows __ARGS((buf_T *buf, int keep_curwin)); void win_close __ARGS((win_T *win, int free_buf)); void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp)); void win_free_all __ARGS((void)); --- 1,14 ---- /* window.c */ void do_window __ARGS((int nchar, long Prenum, int xchar)); int win_split __ARGS((int size, int flags)); ! int win_split_ins __ARGS((int size, int flags, win_T *new_wp, int dir)); int win_valid __ARGS((win_T *win)); int win_count __ARGS((void)); int make_windows __ARGS((int count, int vertical)); void win_move_after __ARGS((win_T *win1, win_T *win2)); void win_equal __ARGS((win_T *next_curwin, int current, int dir)); void close_windows __ARGS((buf_T *buf, int keep_curwin)); + int one_window __ARGS((void)); void win_close __ARGS((win_T *win, int free_buf)); void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp)); void win_free_all __ARGS((void)); *** ../vim-7.3.448/src/version.c 2012-02-22 13:07:02.000000000 +0100 --- src/version.c 2012-02-22 14:55:21.000000000 +0100 *************** *** 716,717 **** --- 716,719 ---- { /* Add new patch number below this line */ + /**/ + 449, /**/ -- From "know your smileys": :-)-O Smiling doctor with stethoscope /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///