# HG changeset patch # User Christian Brabandt # Date 1501793104 -7200 # Node ID bc0fee081e1e37e750ecbf7dbb7ee4598f4dff2b # Parent a53a58b5452cb58c3c97df71ede6362e4bf5ba85 patch 8.0.0858: can exit while a terminal is still running a job commit https://github.com/vim/vim/commit/eb44a68b42eda207a5bc4def9ea8fc4d38acb650 Author: Bram Moolenaar Date: Thu Aug 3 22:44:55 2017 +0200 patch 8.0.0858: can exit while a terminal is still running a job Problem: Can exit while a terminal is still running a job. Solution: Consider a buffer with a running job like a changed file. diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -1736,7 +1736,7 @@ set_curbuf(buf_T *buf, int action) u_sync(FALSE); close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, unload ? action : (action == DOBUF_GOTO - && !P_HID(prevbuf) + && !buf_hide(prevbuf) && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE); #ifdef FEAT_WINDOWS if (curwin != previouswin && win_valid(previouswin)) @@ -4986,12 +4986,12 @@ do_arg_all( if (i == opened_len && !keep_tabs)/* close this window */ { - if (P_HID(buf) || forceit || buf->b_nwindows > 1 + if (buf_hide(buf) || forceit || buf->b_nwindows > 1 || !bufIsChanged(buf)) { /* If the buffer was changed, and we would like to hide it, * try autowriting. */ - if (!P_HID(buf) && buf->b_nwindows <= 1 + if (!buf_hide(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) { #ifdef FEAT_AUTOCMD @@ -5018,7 +5018,7 @@ do_arg_all( #ifdef FEAT_WINDOWS else { - win_close(wp, !P_HID(buf) && !bufIsChanged(buf)); + win_close(wp, !buf_hide(buf) && !bufIsChanged(buf)); # ifdef FEAT_AUTOCMD /* check if autocommands removed the next window */ if (!win_valid(wpnext)) @@ -5117,7 +5117,7 @@ do_arg_all( } (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, ECMD_ONE, - ((P_HID(curwin->w_buffer) + ((buf_hide(curwin->w_buffer) || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) + ECMD_OLDBUF, curwin); #ifdef FEAT_AUTOCMD @@ -5372,7 +5372,7 @@ ex_buffer_all(exarg_T *eap) */ for (wp = lastwin; open_wins > count; ) { - r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer) + r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) || autowrite(wp->w_buffer, FALSE) == OK); #ifdef FEAT_AUTOCMD if (!win_valid(wp)) @@ -5384,7 +5384,7 @@ ex_buffer_all(exarg_T *eap) #endif if (r) { - win_close(wp, !P_HID(wp->w_buffer)); + win_close(wp, !buf_hide(wp->w_buffer)); --open_wins; wp = lastwin; } diff --git a/src/ex_cmds.c b/src/ex_cmds.c --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -3561,7 +3561,7 @@ getfile( if (other) ++no_wait_return; /* don't wait for autowrite message */ - if (other && !forceit && curbuf->b_nwindows == 1 && !P_HID(curbuf) + if (other && !forceit && curbuf->b_nwindows == 1 && !buf_hide(curbuf) && curbufIsChanged() && autowrite(curbuf, forceit) == FAIL) { #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) @@ -3590,7 +3590,7 @@ getfile( retval = GETFILE_SAME_FILE; /* it's in the same file */ } else if (do_ecmd(fnum, ffname, sfname, NULL, lnum, - (P_HID(curbuf) ? ECMD_HIDE : 0) + (forceit ? ECMD_FORCEIT : 0), + (buf_hide(curbuf) ? ECMD_HIDE : 0) + (forceit ? ECMD_FORCEIT : 0), curwin) == OK) retval = GETFILE_OPEN_OTHER; /* opened another file */ else @@ -8401,7 +8401,7 @@ ex_drop(exarg_T *eap) * Skip the check if the 'hidden' option is set, as in this case the * buffer won't be lost. */ - if (!P_HID(curbuf)) + if (!buf_hide(curbuf)) { # ifdef FEAT_WINDOWS ++emsg_off; diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -2064,7 +2064,7 @@ dialog_changed( int can_abandon(buf_T *buf, int forceit) { - return ( P_HID(buf) + return ( buf_hide(buf) || !bufIsChanged(buf) || buf->b_nwindows > 1 || autowrite(buf, forceit) == OK @@ -2180,7 +2180,14 @@ check_changed_any( msg_col = 0; msg_didout = FALSE; } - if (EMSG2(_("E162: No write since last change for buffer \"%s\""), + if ( +#ifdef FEAT_TERMINAL + term_job_running(buf->b_term) + ? EMSG2(_("E947: Job still running in buffer \"%s\""), + buf->b_fname) + : +#endif + EMSG2(_("E162: No write since last change for buffer \"%s\""), buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { save = no_wait_return; @@ -2734,13 +2741,13 @@ do_argfile(exarg_T *eap, int argn) * the same buffer */ other = TRUE; - if (P_HID(curbuf)) + if (buf_hide(curbuf)) { p = fix_fname(alist_name(&ARGLIST[argn])); other = otherfile(p); vim_free(p); } - if ((!P_HID(curbuf) || !other) + if ((!buf_hide(curbuf) || !other) && check_changed(curbuf, CCGD_AW | (other ? 0 : CCGD_MULTWIN) | (eap->forceit ? CCGD_FORCEIT : 0) @@ -2761,7 +2768,7 @@ do_argfile(exarg_T *eap, int argn) * argument index. */ if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL, eap, ECMD_LAST, - (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) + (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0) + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) curwin->w_arg_idx = old_arg_idx; /* like Vi: set the mark where the cursor is in the file. */ @@ -2782,7 +2789,7 @@ ex_next(exarg_T *eap) * check for changed buffer now, if this fails the argument list is not * redefined. */ - if ( P_HID(curbuf) + if ( buf_hide(curbuf) || eap->cmdidx == CMD_snext || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) @@ -2937,7 +2944,7 @@ ex_listdo(exarg_T *eap) if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo - || P_HID(curbuf) + || buf_hide(curbuf) || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7291,7 +7291,7 @@ ex_quit(exarg_T *eap) */ if (check_more(FALSE, eap->forceit) == OK && only_one_window()) exiting = TRUE; - if ((!P_HID(curbuf) + if ((!buf_hide(curbuf) && check_changed(curbuf, (p_awa ? CCGD_AW : 0) | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) @@ -7318,7 +7318,7 @@ ex_quit(exarg_T *eap) need_mouse_correct = TRUE; # endif /* close window; may free buffer */ - win_close(wp, !P_HID(wp->w_buffer) || eap->forceit); + win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit); #endif } } @@ -7438,7 +7438,7 @@ ex_win_close( buf_T *buf = win->w_buffer; need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); - if (need_hide && !P_HID(buf) && !forceit) + if (need_hide && !buf_hide(buf) && !forceit) { # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || cmdmod.confirm) && p_write) @@ -7465,9 +7465,9 @@ ex_win_close( /* free buffer when not hiding it or when it's a scratch buffer */ if (tp == NULL) - win_close(win, !need_hide && !P_HID(buf)); + win_close(win, !need_hide && !buf_hide(buf)); else - win_close_othertab(win, !need_hide && !P_HID(buf), tp); + win_close_othertab(win, !need_hide && !buf_hide(buf), tp); } /* @@ -7864,7 +7864,7 @@ ex_exit(exarg_T *eap) need_mouse_correct = TRUE; # endif /* Quit current window, may free the buffer. */ - win_close(curwin, !P_HID(curwin->w_buffer)); + win_close(curwin, !buf_hide(curwin->w_buffer)); #endif } } @@ -7960,7 +7960,7 @@ handle_drop( * We don't need to check if the 'hidden' option is set, as in this * case the buffer won't be lost. */ - if (!P_HID(curbuf) && !split) + if (!buf_hide(curbuf) && !split) { ++emsg_off; split = check_changed(curbuf, CCGD_AW); @@ -8747,7 +8747,7 @@ do_exedit( (*eap->arg == NUL && eap->do_ecmd_lnum == 0 && vim_strchr(p_cpo, CPO_GOTO1) != NULL) ? ECMD_ONE : eap->do_ecmd_lnum, - (P_HID(curbuf) ? ECMD_HIDE : 0) + (buf_hide(curbuf) ? ECMD_HIDE : 0) + (eap->forceit ? ECMD_FORCEIT : 0) /* after a split we can use an existing buffer */ + (old_curwin != NULL ? ECMD_OLDBUF : 0) @@ -8761,7 +8761,7 @@ do_exedit( if (old_curwin != NULL) { need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1); - if (!need_hide || P_HID(curbuf)) + if (!need_hide || buf_hide(curbuf)) { # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) cleanup_T cs; @@ -8773,7 +8773,7 @@ do_exedit( # ifdef FEAT_GUI need_mouse_correct = TRUE; # endif - win_close(curwin, !need_hide && !P_HID(curbuf)); + win_close(curwin, !need_hide && !buf_hide(curbuf)); # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -6255,11 +6255,11 @@ nv_gotofile(cmdarg_T *cap) if (ptr != NULL) { /* do autowrite if necessary */ - if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf)) + if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !buf_hide(curbuf)) (void)autowrite(curbuf, FALSE); setpcmark(); if (do_ecmd(0, ptr, NULL, NULL, ECMD_LAST, - P_HID(curbuf) ? ECMD_HIDE : 0, curwin) == OK + buf_hide(curbuf) ? ECMD_HIDE : 0, curwin) == OK && cap->nchar == 'F' && lnum >= 0) { curwin->w_cursor.lnum = lnum; diff --git a/src/option.h b/src/option.h --- a/src/option.h +++ b/src/option.h @@ -558,13 +558,6 @@ EXTERN long p_hh; /* 'helpheight' */ EXTERN char_u *p_hlg; /* 'helplang' */ #endif EXTERN int p_hid; /* 'hidden' */ -/* Use P_HID to check if a buffer is to be hidden when it is no longer - * visible in a window. */ -#ifndef FEAT_QUICKFIX -# define P_HID(dummy) (p_hid || cmdmod.hide) -#else -# define P_HID(buf) (buf_hide(buf)) -#endif EXTERN char_u *p_hl; /* 'highlight' */ EXTERN int p_hls; /* 'hlsearch' */ EXTERN long p_hi; /* 'history' */ diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -36,7 +36,6 @@ * that buffer, attributes come from the scrollback buffer tl_scrollback. * * TODO: - * - don't allow exiting Vim when a terminal is still running a job * - MS-Windows: no redraw for 'updatetime' #1915 * - in bash mouse clicks are inserting characters. * - mouse scroll: when over other window, scroll that window. @@ -284,11 +283,16 @@ term_start(char_u *cmd, jobopt_T *opt) } curbuf->b_fname = curbuf->b_ffname; + set_string_option_direct((char_u *)"buftype", -1, + (char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0); + /* Mark the buffer as not modifiable. It can only be made modifiable after * the job finished. */ curbuf->b_p_ma = FALSE; - set_string_option_direct((char_u *)"buftype", -1, - (char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0); + + /* Set 'bufhidden' to "hide": allow closing the window. */ + set_string_option_direct((char_u *)"bufhidden", -1, + (char_u *)"hide", OPT_FREE|OPT_LOCAL, 0); set_term_and_win_size(term); setup_job_options(opt, term->tl_rows, term->tl_cols); diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -63,7 +63,8 @@ endfunc func Test_terminal_wipe_buffer() let buf = Run_shell_in_terminal() - exe buf . 'bwipe' + call assert_fails(buf . 'bwipe', 'E517') + exe buf . 'bwipe!' call WaitFor('job_status(g:job) == "dead"') call assert_equal('dead', job_status(g:job)) call assert_equal("", bufname(buf)) diff --git a/src/undo.c b/src/undo.c --- a/src/undo.c +++ b/src/undo.c @@ -3522,21 +3522,18 @@ u_save_line(linenr_T lnum) int bufIsChanged(buf_T *buf) { - return -#ifdef FEAT_QUICKFIX - !bt_dontwrite(buf) && +#ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + return TRUE; #endif - (buf->b_changed || file_ff_differs(buf, TRUE)); + return !bt_dontwrite(buf) + && (buf->b_changed || file_ff_differs(buf, TRUE)); } int curbufIsChanged(void) { - return -#ifdef FEAT_QUICKFIX - !bt_dontwrite(curbuf) && -#endif - (curbuf->b_changed || file_ff_differs(curbuf, TRUE)); + return bufIsChanged(curbuf); } #if defined(FEAT_EVAL) || defined(PROTO) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -770,6 +770,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 858, +/**/ 857, /**/ 856, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -3379,7 +3379,8 @@ close_others( #endif continue; } - win_close(wp, !P_HID(wp->w_buffer) && !bufIsChanged(wp->w_buffer)); + win_close(wp, !buf_hide(wp->w_buffer) + && !bufIsChanged(wp->w_buffer)); } }