1 To: vim_dev@googlegroups.com
4 From: Bram Moolenaar <Bram@moolenaar.net>
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
11 Problem: Crash when a BufWinLeave autocommand closes the only other window.
13 Solution: Abort closing a buffer when it becomes the only one.
14 Files: src/buffer.c, src/proto/buffer.pro, src/ex_cmds.c, src/ex_getln.c,
15 src/misc2.c, src/quickfix.c, src/window.c, src/proto/window.pro
18 *** ../vim-7.3.448/src/buffer.c 2012-01-20 20:44:38.000000000 +0100
19 --- src/buffer.c 2012-02-22 14:50:42.000000000 +0100
23 static char *msg_loclist = N_("[Location List]");
24 static char *msg_qflist = N_("[Quickfix List]");
27 + static char *e_auabort = N_("E855: Autocommands caused command to abort");
31 * Open current buffer, that is: open the memfile and read the file into
34 * There MUST be a memfile, otherwise we can't do anything
35 * If we can't create one for the current buffer, take another buffer
37 ! close_buffer(NULL, curbuf, 0);
38 for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
39 if (curbuf->b_ml.ml_mfp != NULL)
42 * There MUST be a memfile, otherwise we can't do anything
43 * If we can't create one for the current buffer, take another buffer
45 ! close_buffer(NULL, curbuf, 0, FALSE);
46 for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
47 if (curbuf->b_ml.ml_mfp != NULL)
51 * get a new buffer very soon!
53 * The 'bufhidden' option can force freeing and deleting.
56 ! close_buffer(win, buf, action)
57 win_T *win; /* if not NULL, set b_last_cursor */
64 * get a new buffer very soon!
66 * The 'bufhidden' option can force freeing and deleting.
68 + * When "abort_if_last" is TRUE then do not close the buffer if autocommands
69 + * cause there to be only one window with this buffer. e.g. when ":quit" is
70 + * supposed to close the window but autocommands close all other windows.
73 ! close_buffer(win, buf, action, abort_if_last)
74 win_T *win; /* if not NULL, set b_last_cursor */
84 apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
86 ! if (!buf_valid(buf)) /* autocommands may delete the buffer */
89 /* When the buffer becomes hidden, but is not unloaded, trigger
93 apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
95 ! /* Return if autocommands deleted the buffer or made it the only one. */
96 ! if (!buf_valid(buf) || (abort_if_last && one_window()))
102 /* When the buffer becomes hidden, but is not unloaded, trigger
107 apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
109 ! if (!buf_valid(buf)) /* autocmds may delete the buffer */
113 if (aborting()) /* autocmds may abort script processing */
116 apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
118 ! /* Return if autocommands deleted the buffer or made it the only
120 ! if (!buf_valid(buf) || (abort_if_last && one_window()))
122 ! EMSG(_(e_auabort));
127 if (aborting()) /* autocmds may abort script processing */
130 * open a new, empty buffer. */
131 swap_exists_action = SEA_NONE; /* don't want it again */
132 swap_exists_did_quit = TRUE;
133 ! close_buffer(curwin, curbuf, DOBUF_UNLOAD);
134 if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
135 old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
136 if (old_curbuf != NULL)
138 * open a new, empty buffer. */
139 swap_exists_action = SEA_NONE; /* don't want it again */
140 swap_exists_did_quit = TRUE;
141 ! close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
142 if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
143 old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
144 if (old_curbuf != NULL)
147 * if the buffer still exists.
149 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
150 ! close_buffer(NULL, buf, action);
155 * if the buffer still exists.
157 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
158 ! close_buffer(NULL, buf, action, FALSE);
164 close_windows(buf, FALSE);
166 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
167 ! close_buffer(NULL, buf, action);
172 close_windows(buf, FALSE);
174 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
175 ! close_buffer(NULL, buf, action, FALSE);
181 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
182 unload ? action : (action == DOBUF_GOTO
184 ! && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0);
189 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
190 unload ? action : (action == DOBUF_GOTO
192 ! && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
201 ! close_buffer(NULL, obuf, DOBUF_WIPE); /* delete from the list */
203 sfname = vim_strsave(sfname);
204 if (ffname == NULL || sfname == NULL)
209 ! /* delete from the list */
210 ! close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
212 sfname = vim_strsave(sfname);
213 if (ffname == NULL || sfname == NULL)
216 if (!aucmd) /* Don't trigger BufDelete autocommands here. */
219 ! close_buffer(NULL, buf, DOBUF_WIPE);
224 if (!aucmd) /* Don't trigger BufDelete autocommands here. */
227 ! close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
231 *** ../vim-7.3.448/src/proto/buffer.pro 2010-08-15 21:57:28.000000000 +0200
232 --- src/proto/buffer.pro 2012-02-22 14:04:26.000000000 +0100
236 int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags));
237 int buf_valid __ARGS((buf_T *buf));
238 ! void close_buffer __ARGS((win_T *win, buf_T *buf, int action));
239 void buf_clear_file __ARGS((buf_T *buf));
240 void buf_freeall __ARGS((buf_T *buf, int flags));
241 void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count));
244 int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags));
245 int buf_valid __ARGS((buf_T *buf));
246 ! void close_buffer __ARGS((win_T *win, buf_T *buf, int action, int abort_if_last));
247 void buf_clear_file __ARGS((buf_T *buf));
248 void buf_freeall __ARGS((buf_T *buf, int flags));
249 void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count));
250 *** ../vim-7.3.448/src/ex_cmds.c 2011-12-30 15:01:55.000000000 +0100
251 --- src/ex_cmds.c 2012-02-22 14:00:32.000000000 +0100
254 /* close the link to the current buffer */
256 close_buffer(oldwin, curbuf,
257 ! (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD);
260 /* Autocommands may open a new window and leave oldwin open
262 /* close the link to the current buffer */
264 close_buffer(oldwin, curbuf,
265 ! (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE);
268 /* Autocommands may open a new window and leave oldwin open
269 *** ../vim-7.3.448/src/ex_getln.c 2012-02-04 22:44:27.000000000 +0100
270 --- src/ex_getln.c 2012-02-22 14:01:56.000000000 +0100
273 /* win_close() may have already wiped the buffer when 'bh' is
276 ! close_buffer(NULL, bp, DOBUF_WIPE);
278 /* Restore window sizes. */
279 win_size_restore(&winsizes);
281 /* win_close() may have already wiped the buffer when 'bh' is
284 ! close_buffer(NULL, bp, DOBUF_WIPE, FALSE);
286 /* Restore window sizes. */
287 win_size_restore(&winsizes);
288 *** ../vim-7.3.448/src/misc2.c 2012-02-20 22:18:22.000000000 +0100
289 --- src/misc2.c 2012-02-22 14:02:12.000000000 +0100
292 for (buf = firstbuf; buf != NULL; )
294 nextbuf = buf->b_next;
295 ! close_buffer(NULL, buf, DOBUF_WIPE);
297 buf = nextbuf; /* didn't work, try next one */
300 for (buf = firstbuf; buf != NULL; )
302 nextbuf = buf->b_next;
303 ! close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
305 buf = nextbuf; /* didn't work, try next one */
307 *** ../vim-7.3.448/src/quickfix.c 2012-01-20 13:39:03.000000000 +0100
308 --- src/quickfix.c 2012-02-22 14:02:20.000000000 +0100
313 if (curbuf != buf) /* safety check */
314 ! close_buffer(NULL, buf, DOBUF_UNLOAD);
317 #if defined(FEAT_EVAL) || defined(PROTO)
321 if (curbuf != buf) /* safety check */
322 ! close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE);
325 #if defined(FEAT_EVAL) || defined(PROTO)
326 *** ../vim-7.3.448/src/window.c 2012-01-10 22:26:12.000000000 +0100
327 --- src/window.c 2012-02-22 14:08:13.000000000 +0100
330 static void win_totop __ARGS((int size, int flags));
331 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));
332 static int last_window __ARGS((void));
333 - static int one_window __ARGS((void));
334 static win_T *win_free_mem __ARGS((win_T *win, int *dirp, tabpage_T *tp));
335 static frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp));
336 static tabpage_T *alt_tabpage __ARGS((void));
340 * Return TRUE if there is only one window other than "aucmd_win" in the
348 * Return TRUE if there is only one window other than "aucmd_win" in the
357 * Close window "win". Only works for the current tab page.
358 * If "free_buf" is TRUE related buffer may be unloaded.
360 ! * called by :quit, :close, :xit, :wq and findtag()
363 win_close(win, free_buf)
365 * Close window "win". Only works for the current tab page.
366 * If "free_buf" is TRUE related buffer may be unloaded.
368 ! * Called by :quit, :close, :xit, :wq and findtag().
371 win_close(win, free_buf)
374 * Close the link to the buffer.
376 if (win->w_buffer != NULL)
377 ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0);
379 /* Autocommands may have closed the window already, or closed the only
380 * other window or moved to another tab page. */
382 * Close the link to the buffer.
384 if (win->w_buffer != NULL)
385 ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
387 /* Autocommands may have closed the window already, or closed the only
388 * other window or moved to another tab page. */
393 /* Close the link to the buffer. */
394 ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0);
396 /* Careful: Autocommands may have closed the tab page or made it the
397 * current tab page. */
401 /* Close the link to the buffer. */
402 ! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
404 /* Careful: Autocommands may have closed the tab page or made it the
405 * current tab page. */
406 *** ../vim-7.3.448/src/proto/window.pro 2010-08-15 21:57:28.000000000 +0200
407 --- src/proto/window.pro 2012-02-22 14:08:28.000000000 +0100
411 void do_window __ARGS((int nchar, long Prenum, int xchar));
412 int win_split __ARGS((int size, int flags));
413 ! int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir));
414 int win_valid __ARGS((win_T *win));
415 int win_count __ARGS((void));
416 int make_windows __ARGS((int count, int vertical));
417 void win_move_after __ARGS((win_T *win1, win_T *win2));
418 void win_equal __ARGS((win_T *next_curwin, int current, int dir));
419 void close_windows __ARGS((buf_T *buf, int keep_curwin));
420 void win_close __ARGS((win_T *win, int free_buf));
421 void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp));
422 void win_free_all __ARGS((void));
425 void do_window __ARGS((int nchar, long Prenum, int xchar));
426 int win_split __ARGS((int size, int flags));
427 ! int win_split_ins __ARGS((int size, int flags, win_T *new_wp, int dir));
428 int win_valid __ARGS((win_T *win));
429 int win_count __ARGS((void));
430 int make_windows __ARGS((int count, int vertical));
431 void win_move_after __ARGS((win_T *win1, win_T *win2));
432 void win_equal __ARGS((win_T *next_curwin, int current, int dir));
433 void close_windows __ARGS((buf_T *buf, int keep_curwin));
434 + int one_window __ARGS((void));
435 void win_close __ARGS((win_T *win, int free_buf));
436 void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp));
437 void win_free_all __ARGS((void));
438 *** ../vim-7.3.448/src/version.c 2012-02-22 13:07:02.000000000 +0100
439 --- src/version.c 2012-02-22 14:55:21.000000000 +0100
443 { /* Add new patch number below this line */
449 From "know your smileys":
450 :-)-O Smiling doctor with stethoscope
452 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
453 /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
454 \\\ an exciting new programming language -- http://www.Zimbu.org ///
455 \\\ help me help AIDS victims -- http://ICCF-Holland.org ///