changeset 11957:bc0fee081e1e

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 <Bram@vim.org> 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.
author Christian Brabandt <cb@256bit.org>
date Thu, 03 Aug 2017 22:45:04 +0200
parents a53a58b5452c
children 052270a67371
files src/buffer.c src/ex_cmds.c src/ex_cmds2.c src/ex_docmd.c src/normal.c src/option.h src/terminal.c src/testdir/test_terminal.vim src/undo.c src/version.c src/window.c
diffstat 11 files changed, 55 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- 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;
 	}
--- 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;
--- 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))
--- 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
--- 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;
--- 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' */
--- 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);
--- 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))
--- 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)
--- 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,
--- 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));
 	}
     }