Mercurial > vim
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 } |