To: vim_dev@googlegroups.com Subject: Patch 8.0.0858 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0858 Problem: Can exit while a terminal is still running a job. Solution: Consider a buffer with a running job like a changed file. Files: src/undo.c, src/terminal.c, src/option.h, src/buffer.c, src/ex_cmds.c, src/ex_cmds2.c, src/ex_docmd.c, src/normal.c, src/window.c, src/testdir/test_terminal.vim *** ../vim-8.0.0857/src/undo.c 2017-07-28 22:29:31.591928613 +0200 --- src/undo.c 2017-08-03 22:18:51.829975863 +0200 *************** *** 3522,3542 **** int bufIsChanged(buf_T *buf) { ! return ! #ifdef FEAT_QUICKFIX ! !bt_dontwrite(buf) && #endif ! (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)); } #if defined(FEAT_EVAL) || defined(PROTO) --- 3522,3539 ---- int bufIsChanged(buf_T *buf) { ! #ifdef FEAT_TERMINAL ! if (term_job_running(buf->b_term)) ! return TRUE; #endif ! return !bt_dontwrite(buf) ! && (buf->b_changed || file_ff_differs(buf, TRUE)); } int curbufIsChanged(void) { ! return bufIsChanged(curbuf); } #if defined(FEAT_EVAL) || defined(PROTO) *** ../vim-8.0.0857/src/terminal.c 2017-08-03 20:59:25.939943837 +0200 --- src/terminal.c 2017-08-03 22:24:37.607498206 +0200 *************** *** 36,42 **** * 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. --- 36,41 ---- *************** *** 284,294 **** } curbuf->b_fname = curbuf->b_ffname; /* 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_term_and_win_size(term); setup_job_options(opt, term->tl_rows, term->tl_cols); --- 283,298 ---- } 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 '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); *** ../vim-8.0.0857/src/option.h 2017-07-23 22:56:56.196681386 +0200 --- src/option.h 2017-08-03 22:25:10.323263742 +0200 *************** *** 558,570 **** 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' */ --- 558,563 ---- *** ../vim-8.0.0857/src/buffer.c 2017-08-01 21:44:27.082445161 +0200 --- src/buffer.c 2017-08-03 22:25:58.878915745 +0200 *************** *** 1736,1742 **** u_sync(FALSE); close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, unload ? action : (action == DOBUF_GOTO ! && !P_HID(prevbuf) && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE); #ifdef FEAT_WINDOWS if (curwin != previouswin && win_valid(previouswin)) --- 1736,1742 ---- u_sync(FALSE); close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, unload ? action : (action == DOBUF_GOTO ! && !buf_hide(prevbuf) && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE); #ifdef FEAT_WINDOWS if (curwin != previouswin && win_valid(previouswin)) *************** *** 4986,4997 **** if (i == opened_len && !keep_tabs)/* close this window */ { ! if (P_HID(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 && bufIsChanged(buf)) { #ifdef FEAT_AUTOCMD --- 4986,4997 ---- if (i == opened_len && !keep_tabs)/* close this window */ { ! 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 (!buf_hide(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) { #ifdef FEAT_AUTOCMD *************** *** 5018,5024 **** #ifdef FEAT_WINDOWS else { ! win_close(wp, !P_HID(buf) && !bufIsChanged(buf)); # ifdef FEAT_AUTOCMD /* check if autocommands removed the next window */ if (!win_valid(wpnext)) --- 5018,5024 ---- #ifdef FEAT_WINDOWS else { ! win_close(wp, !buf_hide(buf) && !bufIsChanged(buf)); # ifdef FEAT_AUTOCMD /* check if autocommands removed the next window */ if (!win_valid(wpnext)) *************** *** 5117,5123 **** } (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, ECMD_ONE, ! ((P_HID(curwin->w_buffer) || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) + ECMD_OLDBUF, curwin); #ifdef FEAT_AUTOCMD --- 5117,5123 ---- } (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, ECMD_ONE, ! ((buf_hide(curwin->w_buffer) || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) + ECMD_OLDBUF, curwin); #ifdef FEAT_AUTOCMD *************** *** 5372,5378 **** */ for (wp = lastwin; open_wins > count; ) { ! r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer) || autowrite(wp->w_buffer, FALSE) == OK); #ifdef FEAT_AUTOCMD if (!win_valid(wp)) --- 5372,5378 ---- */ for (wp = lastwin; open_wins > count; ) { ! r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) || autowrite(wp->w_buffer, FALSE) == OK); #ifdef FEAT_AUTOCMD if (!win_valid(wp)) *************** *** 5384,5390 **** #endif if (r) { ! win_close(wp, !P_HID(wp->w_buffer)); --open_wins; wp = lastwin; } --- 5384,5390 ---- #endif if (r) { ! win_close(wp, !buf_hide(wp->w_buffer)); --open_wins; wp = lastwin; } *** ../vim-8.0.0857/src/ex_cmds.c 2017-07-27 22:03:45.550703059 +0200 --- src/ex_cmds.c 2017-08-03 22:26:32.974671372 +0200 *************** *** 3561,3567 **** if (other) ++no_wait_return; /* don't wait for autowrite message */ ! if (other && !forceit && curbuf->b_nwindows == 1 && !P_HID(curbuf) && curbufIsChanged() && autowrite(curbuf, forceit) == FAIL) { #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) --- 3561,3567 ---- if (other) ++no_wait_return; /* don't wait for autowrite message */ ! 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,3596 **** 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), curwin) == OK) retval = GETFILE_OPEN_OTHER; /* opened another file */ else --- 3590,3596 ---- retval = GETFILE_SAME_FILE; /* it's in the same file */ } else if (do_ecmd(fnum, ffname, sfname, NULL, lnum, ! (buf_hide(curbuf) ? ECMD_HIDE : 0) + (forceit ? ECMD_FORCEIT : 0), curwin) == OK) retval = GETFILE_OPEN_OTHER; /* opened another file */ else *************** *** 8401,8407 **** * Skip the check if the 'hidden' option is set, as in this case the * buffer won't be lost. */ ! if (!P_HID(curbuf)) { # ifdef FEAT_WINDOWS ++emsg_off; --- 8401,8407 ---- * Skip the check if the 'hidden' option is set, as in this case the * buffer won't be lost. */ ! if (!buf_hide(curbuf)) { # ifdef FEAT_WINDOWS ++emsg_off; *** ../vim-8.0.0857/src/ex_cmds2.c 2017-08-03 14:29:09.895896191 +0200 --- src/ex_cmds2.c 2017-08-03 22:37:46.329843865 +0200 *************** *** 2064,2070 **** int can_abandon(buf_T *buf, int forceit) { ! return ( P_HID(buf) || !bufIsChanged(buf) || buf->b_nwindows > 1 || autowrite(buf, forceit) == OK --- 2064,2070 ---- int can_abandon(buf_T *buf, int forceit) { ! return ( buf_hide(buf) || !bufIsChanged(buf) || buf->b_nwindows > 1 || autowrite(buf, forceit) == OK *************** *** 2180,2186 **** msg_col = 0; msg_didout = FALSE; } ! if (EMSG2(_("E162: No write since last change for buffer \"%s\""), buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { save = no_wait_return; --- 2180,2193 ---- msg_col = 0; msg_didout = FALSE; } ! 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,2746 **** * the same buffer */ other = TRUE; ! if (P_HID(curbuf)) { p = fix_fname(alist_name(&ARGLIST[argn])); other = otherfile(p); vim_free(p); } ! if ((!P_HID(curbuf) || !other) && check_changed(curbuf, CCGD_AW | (other ? 0 : CCGD_MULTWIN) | (eap->forceit ? CCGD_FORCEIT : 0) --- 2741,2753 ---- * the same buffer */ other = TRUE; ! if (buf_hide(curbuf)) { p = fix_fname(alist_name(&ARGLIST[argn])); other = otherfile(p); vim_free(p); } ! if ((!buf_hide(curbuf) || !other) && check_changed(curbuf, CCGD_AW | (other ? 0 : CCGD_MULTWIN) | (eap->forceit ? CCGD_FORCEIT : 0) *************** *** 2761,2767 **** * 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) + (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. */ --- 2768,2774 ---- * argument index. */ if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL, eap, ECMD_LAST, ! (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,2788 **** * check for changed buffer now, if this fails the argument list is not * redefined. */ ! if ( P_HID(curbuf) || eap->cmdidx == CMD_snext || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) --- 2789,2795 ---- * check for changed buffer now, if this fails the argument list is not * redefined. */ ! if ( buf_hide(curbuf) || eap->cmdidx == CMD_snext || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) *************** *** 2937,2943 **** if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo ! || P_HID(curbuf) || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) --- 2944,2950 ---- if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo ! || buf_hide(curbuf) || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) *** ../vim-8.0.0857/src/ex_docmd.c 2017-07-27 22:56:56.251890982 +0200 --- src/ex_docmd.c 2017-08-03 22:27:21.266325242 +0200 *************** *** 7291,7297 **** */ if (check_more(FALSE, eap->forceit) == OK && only_one_window()) exiting = TRUE; ! if ((!P_HID(curbuf) && check_changed(curbuf, (p_awa ? CCGD_AW : 0) | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) --- 7291,7297 ---- */ if (check_more(FALSE, eap->forceit) == OK && only_one_window()) exiting = TRUE; ! if ((!buf_hide(curbuf) && check_changed(curbuf, (p_awa ? CCGD_AW : 0) | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) *************** *** 7318,7324 **** need_mouse_correct = TRUE; # endif /* close window; may free buffer */ ! win_close(wp, !P_HID(wp->w_buffer) || eap->forceit); #endif } } --- 7318,7324 ---- need_mouse_correct = TRUE; # endif /* close window; may free buffer */ ! win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit); #endif } } *************** *** 7438,7444 **** buf_T *buf = win->w_buffer; need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); ! if (need_hide && !P_HID(buf) && !forceit) { # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || cmdmod.confirm) && p_write) --- 7438,7444 ---- buf_T *buf = win->w_buffer; need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); ! if (need_hide && !buf_hide(buf) && !forceit) { # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || cmdmod.confirm) && p_write) *************** *** 7465,7473 **** /* free buffer when not hiding it or when it's a scratch buffer */ if (tp == NULL) ! win_close(win, !need_hide && !P_HID(buf)); else ! win_close_othertab(win, !need_hide && !P_HID(buf), tp); } /* --- 7465,7473 ---- /* free buffer when not hiding it or when it's a scratch buffer */ if (tp == NULL) ! win_close(win, !need_hide && !buf_hide(buf)); else ! win_close_othertab(win, !need_hide && !buf_hide(buf), tp); } /* *************** *** 7864,7870 **** need_mouse_correct = TRUE; # endif /* Quit current window, may free the buffer. */ ! win_close(curwin, !P_HID(curwin->w_buffer)); #endif } } --- 7864,7870 ---- need_mouse_correct = TRUE; # endif /* Quit current window, may free the buffer. */ ! win_close(curwin, !buf_hide(curwin->w_buffer)); #endif } } *************** *** 7960,7966 **** * 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) { ++emsg_off; split = check_changed(curbuf, CCGD_AW); --- 7960,7966 ---- * We don't need to check if the 'hidden' option is set, as in this * case the buffer won't be lost. */ ! if (!buf_hide(curbuf) && !split) { ++emsg_off; split = check_changed(curbuf, CCGD_AW); *************** *** 8747,8753 **** (*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) + (eap->forceit ? ECMD_FORCEIT : 0) /* after a split we can use an existing buffer */ + (old_curwin != NULL ? ECMD_OLDBUF : 0) --- 8747,8753 ---- (*eap->arg == NUL && eap->do_ecmd_lnum == 0 && vim_strchr(p_cpo, CPO_GOTO1) != NULL) ? ECMD_ONE : eap->do_ecmd_lnum, ! (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,8767 **** if (old_curwin != NULL) { need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1); ! if (!need_hide || P_HID(curbuf)) { # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) cleanup_T cs; --- 8761,8767 ---- if (old_curwin != NULL) { need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1); ! if (!need_hide || buf_hide(curbuf)) { # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) cleanup_T cs; *************** *** 8773,8779 **** # ifdef FEAT_GUI need_mouse_correct = TRUE; # endif ! win_close(curwin, !need_hide && !P_HID(curbuf)); # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not --- 8773,8779 ---- # ifdef FEAT_GUI need_mouse_correct = TRUE; # endif ! win_close(curwin, !need_hide && !buf_hide(curbuf)); # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not *** ../vim-8.0.0857/src/normal.c 2017-07-31 22:56:19.964702432 +0200 --- src/normal.c 2017-08-03 22:27:42.334174234 +0200 *************** *** 6255,6265 **** if (ptr != NULL) { /* do autowrite if necessary */ ! if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf)) (void)autowrite(curbuf, FALSE); setpcmark(); if (do_ecmd(0, ptr, NULL, NULL, ECMD_LAST, ! P_HID(curbuf) ? ECMD_HIDE : 0, curwin) == OK && cap->nchar == 'F' && lnum >= 0) { curwin->w_cursor.lnum = lnum; --- 6255,6265 ---- if (ptr != NULL) { /* do autowrite if necessary */ ! if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !buf_hide(curbuf)) (void)autowrite(curbuf, FALSE); setpcmark(); if (do_ecmd(0, ptr, NULL, NULL, ECMD_LAST, ! buf_hide(curbuf) ? ECMD_HIDE : 0, curwin) == OK && cap->nchar == 'F' && lnum >= 0) { curwin->w_cursor.lnum = lnum; *** ../vim-8.0.0857/src/window.c 2017-07-27 22:03:45.550703059 +0200 --- src/window.c 2017-08-03 22:27:51.978105108 +0200 *************** *** 3379,3385 **** #endif continue; } ! win_close(wp, !P_HID(wp->w_buffer) && !bufIsChanged(wp->w_buffer)); } } --- 3379,3386 ---- #endif continue; } ! win_close(wp, !buf_hide(wp->w_buffer) ! && !bufIsChanged(wp->w_buffer)); } } *** ../vim-8.0.0857/src/testdir/test_terminal.vim 2017-08-03 21:08:01.216288078 +0200 --- src/testdir/test_terminal.vim 2017-08-03 22:42:37.215757639 +0200 *************** *** 63,69 **** func Test_terminal_wipe_buffer() let buf = Run_shell_in_terminal() ! exe buf . 'bwipe' call WaitFor('job_status(g:job) == "dead"') call assert_equal('dead', job_status(g:job)) call assert_equal("", bufname(buf)) --- 63,70 ---- func Test_terminal_wipe_buffer() let buf = Run_shell_in_terminal() ! 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)) *** ../vim-8.0.0857/src/version.c 2017-08-03 21:08:01.216288078 +0200 --- src/version.c 2017-08-03 22:17:59.846348280 +0200 *************** *** 771,772 **** --- 771,774 ---- { /* Add new patch number below this line */ + /**/ + 858, /**/ -- Trees moving back and forth is what makes the wind blow. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///