0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

updated for version 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.
This commit is contained in:
Bram Moolenaar 2012-02-22 14:58:37 +01:00
parent fb7df7be2f
commit 42ec656524
9 changed files with 41 additions and 21 deletions

View File

@ -64,6 +64,9 @@ static void buf_delete_signs __ARGS((buf_T *buf));
static char *msg_loclist = N_("[Location List]"); static char *msg_loclist = N_("[Location List]");
static char *msg_qflist = N_("[Quickfix List]"); static char *msg_qflist = N_("[Quickfix List]");
#endif #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 * Open current buffer, that is: open the memfile and read the file into
@ -96,7 +99,7 @@ open_buffer(read_stdin, eap, flags)
* There MUST be a memfile, otherwise we can't do anything * There MUST be a memfile, otherwise we can't do anything
* If we can't create one for the current buffer, take another buffer * If we can't create one for the current buffer, take another buffer
*/ */
close_buffer(NULL, curbuf, 0); close_buffer(NULL, curbuf, 0, FALSE);
for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
if (curbuf->b_ml.ml_mfp != NULL) if (curbuf->b_ml.ml_mfp != NULL)
break; break;
@ -316,12 +319,17 @@ buf_valid(buf)
* get a new buffer very soon! * get a new buffer very soon!
* *
* The 'bufhidden' option can force freeing and deleting. * 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 void
close_buffer(win, buf, action) close_buffer(win, buf, action, abort_if_last)
win_T *win; /* if not NULL, set b_last_cursor */ win_T *win; /* if not NULL, set b_last_cursor */
buf_T *buf; buf_T *buf;
int action; int action;
int abort_if_last;
{ {
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
int is_curbuf; int is_curbuf;
@ -371,8 +379,12 @@ close_buffer(win, buf, action)
{ {
apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
FALSE, buf); FALSE, buf);
if (!buf_valid(buf)) /* autocommands may delete the buffer */ /* 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; return;
}
/* When the buffer becomes hidden, but is not unloaded, trigger /* When the buffer becomes hidden, but is not unloaded, trigger
* BufHidden */ * BufHidden */
@ -380,9 +392,14 @@ close_buffer(win, buf, action)
{ {
apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
FALSE, buf); FALSE, buf);
if (!buf_valid(buf)) /* autocmds may delete the buffer */ /* 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; return;
} }
}
# ifdef FEAT_EVAL # ifdef FEAT_EVAL
if (aborting()) /* autocmds may abort script processing */ if (aborting()) /* autocmds may abort script processing */
return; return;
@ -775,7 +792,7 @@ handle_swap_exists(old_curbuf)
* open a new, empty buffer. */ * open a new, empty buffer. */
swap_exists_action = SEA_NONE; /* don't want it again */ swap_exists_action = SEA_NONE; /* don't want it again */
swap_exists_did_quit = TRUE; swap_exists_did_quit = TRUE;
close_buffer(curwin, curbuf, DOBUF_UNLOAD); close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
if (!buf_valid(old_curbuf) || old_curbuf == curbuf) if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
if (old_curbuf != NULL) if (old_curbuf != NULL)
@ -1122,7 +1139,7 @@ do_buffer(action, start, dir, count, forceit)
* if the buffer still exists. * if the buffer still exists.
*/ */
if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0) if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
close_buffer(NULL, buf, action); close_buffer(NULL, buf, action, FALSE);
return retval; return retval;
} }
@ -1146,7 +1163,7 @@ do_buffer(action, start, dir, count, forceit)
close_windows(buf, FALSE); close_windows(buf, FALSE);
#endif #endif
if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0) if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
close_buffer(NULL, buf, action); close_buffer(NULL, buf, action, FALSE);
return OK; return OK;
} }
@ -1378,7 +1395,7 @@ set_curbuf(buf, action)
close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
unload ? action : (action == DOBUF_GOTO unload ? action : (action == DOBUF_GOTO
&& !P_HID(prevbuf) && !P_HID(prevbuf)
&& !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0); && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
} }
} }
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
@ -2708,7 +2725,8 @@ setfname(buf, ffname, sfname, message)
vim_free(ffname); vim_free(ffname);
return FAIL; return FAIL;
} }
close_buffer(NULL, obuf, DOBUF_WIPE); /* delete from the list */ /* delete from the list */
close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
} }
sfname = vim_strsave(sfname); sfname = vim_strsave(sfname);
if (ffname == NULL || sfname == NULL) if (ffname == NULL || sfname == NULL)
@ -5638,7 +5656,7 @@ wipe_buffer(buf, aucmd)
if (!aucmd) /* Don't trigger BufDelete autocommands here. */ if (!aucmd) /* Don't trigger BufDelete autocommands here. */
block_autocmds(); block_autocmds();
#endif #endif
close_buffer(NULL, buf, DOBUF_WIPE); close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
if (!aucmd) if (!aucmd)
unblock_autocmds(); unblock_autocmds();

View File

@ -3387,7 +3387,7 @@ do_ecmd(fnum, ffname, sfname, eap, newlnum, flags, oldwin)
/* close the link to the current buffer */ /* close the link to the current buffer */
u_sync(FALSE); u_sync(FALSE);
close_buffer(oldwin, curbuf, close_buffer(oldwin, curbuf,
(flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD); (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE);
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
/* Autocommands may open a new window and leave oldwin open /* Autocommands may open a new window and leave oldwin open

View File

@ -6443,7 +6443,7 @@ ex_window()
/* win_close() may have already wiped the buffer when 'bh' is /* win_close() may have already wiped the buffer when 'bh' is
* set to 'wipe' */ * set to 'wipe' */
if (buf_valid(bp)) if (buf_valid(bp))
close_buffer(NULL, bp, DOBUF_WIPE); close_buffer(NULL, bp, DOBUF_WIPE, FALSE);
/* Restore window sizes. */ /* Restore window sizes. */
win_size_restore(&winsizes); win_size_restore(&winsizes);

View File

@ -1173,7 +1173,7 @@ free_all_mem()
for (buf = firstbuf; buf != NULL; ) for (buf = firstbuf; buf != NULL; )
{ {
nextbuf = buf->b_next; nextbuf = buf->b_next;
close_buffer(NULL, buf, DOBUF_WIPE); close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
if (buf_valid(buf)) if (buf_valid(buf))
buf = nextbuf; /* didn't work, try next one */ buf = nextbuf; /* didn't work, try next one */
else else

View File

@ -1,7 +1,7 @@
/* buffer.c */ /* buffer.c */
int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags)); int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags));
int buf_valid __ARGS((buf_T *buf)); int buf_valid __ARGS((buf_T *buf));
void close_buffer __ARGS((win_T *win, buf_T *buf, int action)); 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_clear_file __ARGS((buf_T *buf));
void buf_freeall __ARGS((buf_T *buf, int flags)); void buf_freeall __ARGS((buf_T *buf, int flags));
void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count)); void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count));

View File

@ -1,13 +1,14 @@
/* window.c */ /* window.c */
void do_window __ARGS((int nchar, long Prenum, int xchar)); void do_window __ARGS((int nchar, long Prenum, int xchar));
int win_split __ARGS((int size, int flags)); int win_split __ARGS((int size, int flags));
int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir)); int win_split_ins __ARGS((int size, int flags, win_T *new_wp, int dir));
int win_valid __ARGS((win_T *win)); int win_valid __ARGS((win_T *win));
int win_count __ARGS((void)); int win_count __ARGS((void));
int make_windows __ARGS((int count, int vertical)); int make_windows __ARGS((int count, int vertical));
void win_move_after __ARGS((win_T *win1, win_T *win2)); void win_move_after __ARGS((win_T *win1, win_T *win2));
void win_equal __ARGS((win_T *next_curwin, int current, int dir)); void win_equal __ARGS((win_T *next_curwin, int current, int dir));
void close_windows __ARGS((buf_T *buf, int keep_curwin)); 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 __ARGS((win_T *win, int free_buf));
void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp)); void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp));
void win_free_all __ARGS((void)); void win_free_all __ARGS((void));

View File

@ -3565,7 +3565,7 @@ unload_dummy_buffer(buf)
buf_T *buf; buf_T *buf;
{ {
if (curbuf != buf) /* safety check */ if (curbuf != buf) /* safety check */
close_buffer(NULL, buf, DOBUF_UNLOAD); close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE);
} }
#if defined(FEAT_EVAL) || defined(PROTO) #if defined(FEAT_EVAL) || defined(PROTO)

View File

@ -714,6 +714,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
449,
/**/ /**/
448, 448,
/**/ /**/

View File

@ -23,7 +23,6 @@ static void win_rotate __ARGS((int, int));
static void win_totop __ARGS((int size, int flags)); 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 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 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 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 frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp));
static tabpage_T *alt_tabpage __ARGS((void)); static tabpage_T *alt_tabpage __ARGS((void));
@ -2083,7 +2082,7 @@ last_window()
* Return TRUE if there is only one window other than "aucmd_win" in the * Return TRUE if there is only one window other than "aucmd_win" in the
* current tab page. * current tab page.
*/ */
static int int
one_window() one_window()
{ {
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
@ -2109,7 +2108,7 @@ one_window()
* Close window "win". Only works for the current tab page. * Close window "win". Only works for the current tab page.
* If "free_buf" is TRUE related buffer may be unloaded. * If "free_buf" is TRUE related buffer may be unloaded.
* *
* called by :quit, :close, :xit, :wq and findtag() * Called by :quit, :close, :xit, :wq and findtag().
*/ */
void void
win_close(win, free_buf) win_close(win, free_buf)
@ -2222,7 +2221,7 @@ win_close(win, free_buf)
* Close the link to the buffer. * Close the link to the buffer.
*/ */
if (win->w_buffer != NULL) if (win->w_buffer != NULL)
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0); close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
/* Autocommands may have closed the window already, or closed the only /* Autocommands may have closed the window already, or closed the only
* other window or moved to another tab page. */ * other window or moved to another tab page. */
@ -2328,7 +2327,7 @@ win_close_othertab(win, free_buf, tp)
int free_tp = FALSE; int free_tp = FALSE;
/* Close the link to the buffer. */ /* Close the link to the buffer. */
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0); close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
/* Careful: Autocommands may have closed the tab page or made it the /* Careful: Autocommands may have closed the tab page or made it the
* current tab page. */ * current tab page. */