To: vim_dev@googlegroups.com Subject: Patch 9.0.0708 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0708 Problem: :confirm does not work properly for a terminal buffer. Solution: Handle :confirm for a terminal buffer differently. (Yee Cheng Chin, closes #11312) Files: runtime/menu.vim, src/buffer.c, src/ex_cmds2.c, src/ex_docmd.c, src/proto/terminal.pro, src/terminal.c, src/testdir/test_terminal.vim *** ../vim-9.0.0707/runtime/menu.vim 2022-03-02 21:25:35.000000000 +0000 --- runtime/menu.vim 2022-10-09 18:42:05.491666766 +0100 *************** *** 129,134 **** --- 129,140 ---- \ else \ confirm close \ endif + tln 10.330 &File.&Close:close + \ :if winheight(2) < 0 && tabpagewinnr(2) == 0 + \ confirm enew + \ else + \ confirm close + \ endif an 10.335 &File.-SEP1- an 10.340 &File.&Save:w :if expand("%") == ""browse confirm welseconfirm wendif an 10.350 &File.Save\ &As\.\.\.:sav :browse confirm saveas *** ../vim-9.0.0707/src/buffer.c 2022-10-01 19:43:48.602494034 +0100 --- src/buffer.c 2022-10-09 18:42:05.491666766 +0100 *************** *** 49,54 **** --- 49,55 ---- static void free_buffer(buf_T *); static void free_buffer_stuff(buf_T *buf, int free_options); static int bt_nofileread(buf_T *buf); + static void no_write_message_buf(buf_T *buf); #ifdef UNIX # define dev_T dev_t *************** *** 1367,1387 **** #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { ! dialog_changed(buf, FALSE); ! if (!bufref_valid(&bufref)) ! // Autocommand deleted buffer, oops! It's not changed ! // now. ! return FAIL; ! // If it's still changed fail silently, the dialog already ! // mentioned why it fails. ! if (bufIsChanged(buf)) ! return FAIL; } else #endif { ! semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), ! buf->b_fnum); return FAIL; } } --- 1368,1397 ---- #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { ! # ifdef FEAT_TERMINAL ! if (term_job_running(buf->b_term)) ! { ! if (term_confirm_stop(buf) == FAIL) ! return FAIL; ! } ! else ! # endif ! { ! dialog_changed(buf, FALSE); ! if (!bufref_valid(&bufref)) ! // Autocommand deleted buffer, oops! It's not changed ! // now. ! return FAIL; ! // If it's still changed fail silently, the dialog already ! // mentioned why it fails. ! if (bufIsChanged(buf)) ! return FAIL; ! } } else #endif { ! no_write_message_buf(buf); return FAIL; } } *************** *** 1552,1566 **** #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { ! bufref_T bufref; ! set_bufref(&bufref, buf); ! dialog_changed(curbuf, FALSE); ! if (!bufref_valid(&bufref)) ! // Autocommand deleted buffer, oops! ! return FAIL; } ! if (bufIsChanged(curbuf)) #endif { no_write_message(); --- 1562,1595 ---- #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { ! # ifdef FEAT_TERMINAL ! if (term_job_running(curbuf->b_term)) ! { ! if (term_confirm_stop(curbuf) == FAIL) ! return FAIL; ! // Manually kill the terminal here because this command will ! // hide it otherwise. ! free_terminal(curbuf); ! } ! else ! # endif ! { ! bufref_T bufref; ! set_bufref(&bufref, buf); ! dialog_changed(curbuf, FALSE); ! if (!bufref_valid(&bufref)) ! // Autocommand deleted buffer, oops! ! return FAIL; ! ! if (bufIsChanged(curbuf)) ! { ! no_write_message(); ! return FAIL; ! } ! } } ! else #endif { no_write_message(); *************** *** 1940,1945 **** --- 1969,1986 ---- } #endif + static void + no_write_message_buf(buf_T *buf UNUSED) + { + #ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + emsg(_(e_job_still_running_add_bang_to_end_the_job)); + else + #endif + semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), + buf->b_fnum); + } + void no_write_message(void) { *************** *** 5751,5758 **** #endif /* ! * Return TRUE if "buf" is a "nowrite", "nofile", "terminal" or "prompt" ! * buffer. */ int bt_dontwrite(buf_T *buf) --- 5792,5799 ---- #endif /* ! * Return TRUE if "buf" is a "nowrite", "nofile", "terminal", "prompt", or ! * "popup" buffer. */ int bt_dontwrite(buf_T *buf) *** ../vim-9.0.0707/src/ex_cmds2.c 2022-08-29 15:06:46.716715543 +0100 --- src/ex_cmds2.c 2022-10-09 18:42:05.491666766 +0100 *************** *** 86,91 **** --- 86,98 ---- #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { + # ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + { + return term_confirm_stop(buf) == FAIL; + } + # endif + buf_T *buf2; int count = 0; *************** *** 198,203 **** --- 205,211 ---- || (cmdmod.cmod_flags & CMOD_BROWSE) #endif ) + && !bt_dontwrite(buf2) && !buf2->b_p_ro) { bufref_T bufref; *** ../vim-9.0.0707/src/ex_docmd.c 2022-10-07 18:51:20.139679475 +0100 --- src/ex_docmd.c 2022-10-09 18:42:05.491666766 +0100 *************** *** 6061,6073 **** #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { ! bufref_T bufref; ! set_bufref(&bufref, buf); ! dialog_changed(buf, FALSE); ! if (bufref_valid(&bufref) && bufIsChanged(buf)) ! return; ! need_hide = FALSE; } else #endif --- 6061,6087 ---- #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { ! # ifdef FEAT_TERMINAL ! if (term_job_running(buf->b_term)) ! { ! if (term_confirm_stop(buf) == FAIL) ! return; ! // Manually kill the terminal here because this command will ! // hide it otherwise. ! free_terminal(buf); ! need_hide = FALSE; ! } ! else ! # endif ! { ! bufref_T bufref; ! set_bufref(&bufref, buf); ! dialog_changed(buf, FALSE); ! if (bufref_valid(&bufref) && bufIsChanged(buf)) ! return; ! need_hide = FALSE; ! } } else #endif *** ../vim-9.0.0707/src/proto/terminal.pro 2022-06-27 23:15:25.000000000 +0100 --- src/proto/terminal.pro 2022-10-09 18:42:05.491666766 +0100 *************** *** 10,15 **** --- 10,16 ---- int term_job_running(term_T *term); int term_job_running_not_none(term_T *term); int term_none_open(term_T *term); + int term_confirm_stop(buf_T *buf); int term_try_stop_job(buf_T *buf); int term_check_timers(int next_due_arg, proftime_T *now); int term_in_normal_mode(void); *** ../vim-9.0.0707/src/terminal.c 2022-10-04 16:23:39.018042176 +0100 --- src/terminal.c 2022-10-09 18:42:05.495666761 +0100 *************** *** 1651,1656 **** --- 1651,1675 ---- && term->tl_job->jv_channel->ch_keep_open; } + // + // Used to confirm whether we would like to kill a terminal. + // Return OK when the user confirms to kill it. + // Return FAIL if the user selects otherwise. + // + int + term_confirm_stop(buf_T *buf) + { + char_u buff[DIALOG_MSG_SIZE]; + int ret; + + dialog_msg(buff, _("Kill job in \"%s\"?"), buf_get_fname(buf)); + ret = vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1); + if (ret == VIM_YES) + return OK; + else + return FAIL; + } + /* * Used when exiting: kill the job in "buf" if so desired. * Return OK when the job finished. *************** *** 1666,1679 **** if ((how == NULL || *how == NUL) && (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))) { ! char_u buff[DIALOG_MSG_SIZE]; ! int ret; ! ! dialog_msg(buff, _("Kill job in \"%s\"?"), buf_get_fname(buf)); ! ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); ! if (ret == VIM_YES) how = "kill"; ! else if (ret == VIM_CANCEL) return FAIL; } #endif --- 1685,1693 ---- if ((how == NULL || *how == NUL) && (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))) { ! if (term_confirm_stop(buf) == OK) how = "kill"; ! else return FAIL; } #endif *** ../vim-9.0.0707/src/testdir/test_terminal.vim 2022-09-22 12:57:02.288750572 +0100 --- src/testdir/test_terminal.vim 2022-10-09 18:42:05.495666761 +0100 *************** *** 98,104 **** func Test_terminal_wipe_buffer() let buf = Run_shell_in_terminal({}) ! call assert_fails(buf . 'bwipe', 'E89:') exe buf . 'bwipe!' call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) call assert_equal("", bufname(buf)) --- 98,104 ---- func Test_terminal_wipe_buffer() let buf = Run_shell_in_terminal({}) ! call assert_fails(buf . 'bwipe', 'E948:') exe buf . 'bwipe!' call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) call assert_equal("", bufname(buf)) *************** *** 106,111 **** --- 106,231 ---- unlet g:job endfunc + " Test that using ':confirm bwipe' on terminal works + func Test_terminal_confirm_wipe_buffer() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf = Run_shell_in_terminal({}) + call assert_fails(buf . 'bwipe', 'E948:') + call feedkeys('n', 'L') + call assert_fails('confirm ' .. buf .. 'bwipe', 'E517:') + call assert_equal(buf, bufnr()) + call assert_equal(1, &modified) + call feedkeys('y', 'L') + exe 'confirm ' .. buf .. 'bwipe' + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf)) + + unlet g:job + endfunc + + " Test that using :b! will hide the terminal + func Test_terminal_goto_buffer() + let buf_mod = bufnr() + let buf_term = Run_shell_in_terminal({}) + call assert_equal(buf_term, bufnr()) + call assert_fails(buf_mod . 'b', 'E948:') + exe buf_mod . 'b!' + call assert_equal(buf_mod, bufnr()) + call assert_equal('run', job_status(g:job)) + call assert_notequal('', bufname(buf_term)) + exec buf_mod .. 'bwipe!' + exec buf_term .. 'bwipe!' + + unlet g:job + endfunc + + " Test that using ':confirm :b' will kill terminal + func Test_terminal_confirm_goto_buffer() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf_mod = bufnr() + let buf_term = Run_shell_in_terminal({}) + call feedkeys('n', 'L') + exe 'confirm ' .. buf_mod .. 'b' + call assert_equal(buf_term, bufnr()) + call feedkeys('y', 'L') + exec 'confirm ' .. buf_mod .. 'b' + call assert_equal(buf_mod, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf_term)) + exec buf_mod .. 'bwipe!' + + unlet g:job + endfunc + + " Test that using :close! will hide the terminal + func Test_terminal_close_win() + let buf = Run_shell_in_terminal({}) + call assert_equal(buf, bufnr()) + call assert_fails('close', 'E948:') + close! + call assert_notequal(buf, bufnr()) + call assert_equal('run', job_status(g:job)) + call assert_notequal('', bufname(buf)) + exec buf .. 'bwipe!' + + unlet g:job + endfunc + + " Test that using ':confirm close' will kill terminal + func Test_terminal_confirm_close_win() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf = Run_shell_in_terminal({}) + call feedkeys('n', 'L') + confirm close + call assert_equal(buf, bufnr()) + call feedkeys('y', 'L') + confirm close + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf)) + + unlet g:job + endfunc + + " Test that using :quit! will kill the terminal + func Test_terminal_quit() + let buf = Run_shell_in_terminal({}) + call assert_equal(buf, bufnr()) + call assert_fails('quit', 'E948:') + quit! + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + exec buf .. 'bwipe!' + + unlet g:job + endfunc + + " Test that using ':confirm quit' will kill terminal + func Test_terminal_confirm_quit() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf = Run_shell_in_terminal({}) + call feedkeys('n', 'L') + confirm quit + call assert_equal(buf, bufnr()) + call feedkeys('y', 'L') + confirm quit + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + + unlet g:job + endfunc + + " Test :q or :next + func Test_terminal_split_quit() let buf = Run_shell_in_terminal({}) split *************** *** 707,713 **** func Test_terminal_list_args() let buf = term_start([&shell, &shellcmdflag, 'echo "123"']) ! call assert_fails(buf . 'bwipe', 'E89:') exe buf . 'bwipe!' call assert_equal("", bufname(buf)) endfunction --- 827,833 ---- func Test_terminal_list_args() let buf = term_start([&shell, &shellcmdflag, 'echo "123"']) ! call assert_fails(buf . 'bwipe', 'E948:') exe buf . 'bwipe!' call assert_equal("", bufname(buf)) endfunction *************** *** 1235,1241 **** " make Vim exit, it will prompt to kill the shell call term_sendkeys(buf, "\:confirm qall\") ! call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))}) call term_sendkeys(buf, "y") call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) --- 1355,1361 ---- " make Vim exit, it will prompt to kill the shell call term_sendkeys(buf, "\:confirm qall\") ! call WaitForAssert({-> assert_match('\[Y\]es, (N)o:', term_getline(buf, 20))}) call term_sendkeys(buf, "y") call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) *** ../vim-9.0.0707/src/version.c 2022-10-09 17:19:04.445451418 +0100 --- src/version.c 2022-10-09 18:49:46.120290363 +0100 *************** *** 701,702 **** --- 701,704 ---- { /* Add new patch number below this line */ + /**/ + 708, /**/ -- I still remember when I gave up Smoking, Drinking and Sex. It was the most *horrifying* hour of my life! /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///