# HG changeset patch # User Christian Brabandt # Date 1472913006 -7200 # Node ID 7fc6103c66518dccc4414dc88d029983451cbc0c # Parent a7e347d09237497bba1fc896c6ad66304d0616ae commit https://github.com/vim/vim/commit/5a49789a9b1f6447aeafbbbdd5b235dd10c471d5 Author: Bram Moolenaar Date: Sat Sep 3 16:29:04 2016 +0200 patch 7.4.2312 Problem: Crash when autocommand moves to another tab. (Dominique Pelle) Solution: When navigating to another window halfway the :edit command go back to the right window. diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -666,7 +666,8 @@ buf_clear_file(buf_T *buf) /* * buf_freeall() - free all things allocated for a buffer that are related to - * the file. flags: + * the file. Careful: get here with "curwin" NULL when exiting. + * flags: * BFA_DEL buffer is going to be deleted * BFA_WIPE buffer is going to be wiped out * BFA_KEEP_UNDO do not free undo information @@ -677,7 +678,13 @@ buf_freeall(buf_T *buf, int flags) #ifdef FEAT_AUTOCMD int is_curbuf = (buf == curbuf); bufref_T bufref; - +# ifdef FEAT_WINDOWS + int is_curwin = (curwin!= NULL && curwin->w_buffer == buf); + win_T *the_curwin = curwin; + tabpage_T *the_curtab = curtab; +# endif + + /* Make sure the buffer isn't closed by autocommands. */ buf->b_closing = TRUE; set_bufref(&bufref, buf); if (buf->b_ml.ml_mfp != NULL) @@ -705,6 +712,19 @@ buf_freeall(buf_T *buf, int flags) return; } buf->b_closing = FALSE; + +# ifdef FEAT_WINDOWS + /* If the buffer was in curwin and the window has changed, go back to that + * window, if it still exists. This avoids that ":edit x" triggering a + * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */ + if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) + { + block_autocmds(); + goto_tabpage_win(the_curtab, the_curwin); + unblock_autocmds(); + } +# endif + # ifdef FEAT_EVAL if (aborting()) /* autocmds may abort script processing */ return; diff --git a/src/ex_cmds.c b/src/ex_cmds.c --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -3935,25 +3935,28 @@ do_ecmd( auto_buf = TRUE; else { + win_T *the_curwin = curwin; + + /* Set the w_closing flag to avoid that autocommands close the + * window. */ + the_curwin->w_closing = TRUE; + if (curbuf == old_curbuf.br_buf) #endif buf_copy_options(buf, BCO_ENTER); - /* close the link to the current buffer */ + /* Close the link to the current buffer. This will set + * curwin->w_buffer to NULL. */ 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 - * which leads to crashes since the above call sets - * oldwin->w_buffer to NULL. */ - if (curwin != oldwin && oldwin != aucmd_win - && win_valid(oldwin) && oldwin->w_buffer == NULL) - win_close(oldwin, FALSE); + the_curwin->w_closing = FALSE; # ifdef FEAT_EVAL - if (aborting()) /* autocmds may abort script processing */ + /* autocmds may abort script processing */ + if (aborting() && curwin->w_buffer != NULL) { vim_free(new_name); goto theend; diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2475,12 +2475,7 @@ do_one_cmd( && !IS_USER_CMDIDX(ea.cmdidx)) { /* Command not allowed when editing the command line. */ -#ifdef FEAT_CMDWIN - if (cmdwin_type != 0) - errormsg = (char_u *)_(e_cmdwin); - else -#endif - errormsg = (char_u *)_(e_secure); + errormsg = get_text_locked_msg(); goto doend; } #ifdef FEAT_AUTOCMD diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -2133,12 +2133,17 @@ text_locked(void) void text_locked_msg(void) { + EMSG(_(get_text_locked_msg())); +} + + char_u * +get_text_locked_msg(void) +{ #ifdef FEAT_CMDWIN if (cmdwin_type != 0) - EMSG(_(e_cmdwin)); - else -#endif - EMSG(_(e_secure)); + return e_cmdwin; +#endif + return e_secure; } #if defined(FEAT_AUTOCMD) || defined(PROTO) diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro --- a/src/proto/ex_getln.pro +++ b/src/proto/ex_getln.pro @@ -3,6 +3,7 @@ char_u *getcmdline(int firstc, long coun char_u *getcmdline_prompt(int firstc, char_u *prompt, int attr, int xp_context, char_u *xp_arg); int text_locked(void); void text_locked_msg(void); +char_u *get_text_locked_msg(void); int curbuf_locked(void); int allbuf_locked(void); char_u *getexline(int c, void *cookie, int indent); diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim --- a/src/testdir/test_tabpage.vim +++ b/src/testdir/test_tabpage.vim @@ -218,7 +218,7 @@ function Test_tabpage_with_tab_modifier( bw! endfunction -func Test_tabnext_on_buf_unload() +func Test_tabnext_on_buf_unload1() " This once caused a crash new tabedit @@ -227,7 +227,19 @@ func Test_tabnext_on_buf_unload() q while tabpagenr('$') > 1 - quit + bwipe! + endwhile +endfunc + +func Test_tabnext_on_buf_unload2() + " This once caused a crash + tabedit + autocmd BufUnload tabnext + file x + edit y + + while tabpagenr('$') > 1 + bwipe! endwhile endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -764,6 +764,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2312, +/**/ 2311, /**/ 2310, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -3912,12 +3912,7 @@ goto_tabpage(int n) if (text_locked()) { /* Not allowed when editing the command line. */ -#ifdef FEAT_CMDWIN - if (cmdwin_type != 0) - EMSG(_(e_cmdwin)); - else -#endif - EMSG(_(e_secure)); + text_locked_msg(); return; }