comparison src/buffer.c @ 3365:9ccdc4a69d8f v7.3.449

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.
author Bram Moolenaar <bram@vim.org>
date Wed, 22 Feb 2012 14:58:37 +0100
parents 55cebc7e5de0
children 07fd030f89be
comparison
equal deleted inserted replaced
3364:e8d5db3a6d4f 3365:9ccdc4a69d8f
62 62
63 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 63 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
64 static char *msg_loclist = N_("[Location List]"); 64 static char *msg_loclist = N_("[Location List]");
65 static char *msg_qflist = N_("[Quickfix List]"); 65 static char *msg_qflist = N_("[Quickfix List]");
66 #endif 66 #endif
67 #ifdef FEAT_AUTOCMD
68 static char *e_auabort = N_("E855: Autocommands caused command to abort");
69 #endif
67 70
68 /* 71 /*
69 * Open current buffer, that is: open the memfile and read the file into 72 * Open current buffer, that is: open the memfile and read the file into
70 * memory. 73 * memory.
71 * Return FAIL for failure, OK otherwise. 74 * Return FAIL for failure, OK otherwise.
94 { 97 {
95 /* 98 /*
96 * There MUST be a memfile, otherwise we can't do anything 99 * There MUST be a memfile, otherwise we can't do anything
97 * If we can't create one for the current buffer, take another buffer 100 * If we can't create one for the current buffer, take another buffer
98 */ 101 */
99 close_buffer(NULL, curbuf, 0); 102 close_buffer(NULL, curbuf, 0, FALSE);
100 for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) 103 for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
101 if (curbuf->b_ml.ml_mfp != NULL) 104 if (curbuf->b_ml.ml_mfp != NULL)
102 break; 105 break;
103 /* 106 /*
104 * if there is no memfile at all, exit 107 * if there is no memfile at all, exit
314 * DOBUF_WIPE buffer is unloaded and really deleted 317 * DOBUF_WIPE buffer is unloaded and really deleted
315 * When doing all but the first one on the current buffer, the caller should 318 * When doing all but the first one on the current buffer, the caller should
316 * get a new buffer very soon! 319 * get a new buffer very soon!
317 * 320 *
318 * The 'bufhidden' option can force freeing and deleting. 321 * The 'bufhidden' option can force freeing and deleting.
322 *
323 * When "abort_if_last" is TRUE then do not close the buffer if autocommands
324 * cause there to be only one window with this buffer. e.g. when ":quit" is
325 * supposed to close the window but autocommands close all other windows.
319 */ 326 */
320 void 327 void
321 close_buffer(win, buf, action) 328 close_buffer(win, buf, action, abort_if_last)
322 win_T *win; /* if not NULL, set b_last_cursor */ 329 win_T *win; /* if not NULL, set b_last_cursor */
323 buf_T *buf; 330 buf_T *buf;
324 int action; 331 int action;
332 int abort_if_last;
325 { 333 {
326 #ifdef FEAT_AUTOCMD 334 #ifdef FEAT_AUTOCMD
327 int is_curbuf; 335 int is_curbuf;
328 int nwindows; 336 int nwindows;
329 #endif 337 #endif
369 /* When the buffer is no longer in a window, trigger BufWinLeave */ 377 /* When the buffer is no longer in a window, trigger BufWinLeave */
370 if (buf->b_nwindows == 1) 378 if (buf->b_nwindows == 1)
371 { 379 {
372 apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, 380 apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
373 FALSE, buf); 381 FALSE, buf);
374 if (!buf_valid(buf)) /* autocommands may delete the buffer */ 382 /* Return if autocommands deleted the buffer or made it the only one. */
383 if (!buf_valid(buf) || (abort_if_last && one_window()))
384 {
385 EMSG(_(e_auabort));
375 return; 386 return;
387 }
376 388
377 /* When the buffer becomes hidden, but is not unloaded, trigger 389 /* When the buffer becomes hidden, but is not unloaded, trigger
378 * BufHidden */ 390 * BufHidden */
379 if (!unload_buf) 391 if (!unload_buf)
380 { 392 {
381 apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, 393 apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
382 FALSE, buf); 394 FALSE, buf);
383 if (!buf_valid(buf)) /* autocmds may delete the buffer */ 395 /* Return if autocommands deleted the buffer or made it the only
396 * one. */
397 if (!buf_valid(buf) || (abort_if_last && one_window()))
398 {
399 EMSG(_(e_auabort));
384 return; 400 return;
401 }
385 } 402 }
386 # ifdef FEAT_EVAL 403 # ifdef FEAT_EVAL
387 if (aborting()) /* autocmds may abort script processing */ 404 if (aborting()) /* autocmds may abort script processing */
388 return; 405 return;
389 # endif 406 # endif
773 /* User selected Quit at ATTENTION prompt. Go back to previous 790 /* User selected Quit at ATTENTION prompt. Go back to previous
774 * buffer. If that buffer is gone or the same as the current one, 791 * buffer. If that buffer is gone or the same as the current one,
775 * open a new, empty buffer. */ 792 * open a new, empty buffer. */
776 swap_exists_action = SEA_NONE; /* don't want it again */ 793 swap_exists_action = SEA_NONE; /* don't want it again */
777 swap_exists_did_quit = TRUE; 794 swap_exists_did_quit = TRUE;
778 close_buffer(curwin, curbuf, DOBUF_UNLOAD); 795 close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
779 if (!buf_valid(old_curbuf) || old_curbuf == curbuf) 796 if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
780 old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); 797 old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
781 if (old_curbuf != NULL) 798 if (old_curbuf != NULL)
782 enter_buffer(old_curbuf); 799 enter_buffer(old_curbuf);
783 /* If "old_curbuf" is NULL we are in big trouble here... */ 800 /* If "old_curbuf" is NULL we are in big trouble here... */
1120 * do_ecmd() may create a new buffer, then we have to delete 1137 * do_ecmd() may create a new buffer, then we have to delete
1121 * the old one. But do_ecmd() may have done that already, check 1138 * the old one. But do_ecmd() may have done that already, check
1122 * if the buffer still exists. 1139 * if the buffer still exists.
1123 */ 1140 */
1124 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0) 1141 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
1125 close_buffer(NULL, buf, action); 1142 close_buffer(NULL, buf, action, FALSE);
1126 return retval; 1143 return retval;
1127 } 1144 }
1128 1145
1129 #ifdef FEAT_WINDOWS 1146 #ifdef FEAT_WINDOWS
1130 /* 1147 /*
1144 { 1161 {
1145 #ifdef FEAT_WINDOWS 1162 #ifdef FEAT_WINDOWS
1146 close_windows(buf, FALSE); 1163 close_windows(buf, FALSE);
1147 #endif 1164 #endif
1148 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0) 1165 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
1149 close_buffer(NULL, buf, action); 1166 close_buffer(NULL, buf, action, FALSE);
1150 return OK; 1167 return OK;
1151 } 1168 }
1152 1169
1153 /* 1170 /*
1154 * Deleting the current buffer: Need to find another buffer to go to. 1171 * Deleting the current buffer: Need to find another buffer to go to.
1376 if (prevbuf == curbuf) 1393 if (prevbuf == curbuf)
1377 u_sync(FALSE); 1394 u_sync(FALSE);
1378 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, 1395 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
1379 unload ? action : (action == DOBUF_GOTO 1396 unload ? action : (action == DOBUF_GOTO
1380 && !P_HID(prevbuf) 1397 && !P_HID(prevbuf)
1381 && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0); 1398 && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
1382 } 1399 }
1383 } 1400 }
1384 #ifdef FEAT_AUTOCMD 1401 #ifdef FEAT_AUTOCMD
1385 /* An autocommand may have deleted "buf", already entered it (e.g., when 1402 /* An autocommand may have deleted "buf", already entered it (e.g., when
1386 * it did ":bunload") or aborted the script processing! */ 1403 * it did ":bunload") or aborted the script processing! */
2706 if (message) 2723 if (message)
2707 EMSG(_("E95: Buffer with this name already exists")); 2724 EMSG(_("E95: Buffer with this name already exists"));
2708 vim_free(ffname); 2725 vim_free(ffname);
2709 return FAIL; 2726 return FAIL;
2710 } 2727 }
2711 close_buffer(NULL, obuf, DOBUF_WIPE); /* delete from the list */ 2728 /* delete from the list */
2729 close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
2712 } 2730 }
2713 sfname = vim_strsave(sfname); 2731 sfname = vim_strsave(sfname);
2714 if (ffname == NULL || sfname == NULL) 2732 if (ffname == NULL || sfname == NULL)
2715 { 2733 {
2716 vim_free(sfname); 2734 vim_free(sfname);
5636 5654
5637 #ifdef FEAT_AUTOCMD 5655 #ifdef FEAT_AUTOCMD
5638 if (!aucmd) /* Don't trigger BufDelete autocommands here. */ 5656 if (!aucmd) /* Don't trigger BufDelete autocommands here. */
5639 block_autocmds(); 5657 block_autocmds();
5640 #endif 5658 #endif
5641 close_buffer(NULL, buf, DOBUF_WIPE); 5659 close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
5642 #ifdef FEAT_AUTOCMD 5660 #ifdef FEAT_AUTOCMD
5643 if (!aucmd) 5661 if (!aucmd)
5644 unblock_autocmds(); 5662 unblock_autocmds();
5645 #endif 5663 #endif
5646 } 5664 }