]> granicus.if.org Git - vim/commitdiff
patch 9.0.0708: :confirm does not work properly for a terminal buffer v9.0.0708
authorYee Cheng Chin <ychin.git@gmail.com>
Sun, 9 Oct 2022 17:53:32 +0000 (18:53 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 9 Oct 2022 17:53:32 +0000 (18:53 +0100)
Problem:    :confirm does not work properly for a terminal buffer.
Solution:   Handle :confirm for a terminal buffer differently.  (Yee Cheng
            Chin, closes #11312)

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
src/version.c

index 9ba2d3b3fadcc6cfd595096d3015bb8e442d5ab9..d449a75102b171533c1e4377198c950b07336848 100644 (file)
@@ -129,6 +129,12 @@ an <silent> 10.330 &File.&Close<Tab>:close
        \ else <Bar>
        \   confirm close <Bar>
        \ endif<CR>
+tln <silent> 10.330 &File.&Close<Tab>:close
+       \ <C-W>:if winheight(2) < 0 && tabpagewinnr(2) == 0 <Bar>
+       \   confirm enew <Bar>
+       \ else <Bar>
+       \   confirm close <Bar>
+       \ endif<CR>
 an 10.335 &File.-SEP1-                         <Nop>
 an <silent> 10.340 &File.&Save<Tab>:w          :if expand("%") == ""<Bar>browse confirm w<Bar>else<Bar>confirm w<Bar>endif<CR>
 an 10.350 &File.Save\ &As\.\.\.<Tab>:sav       :browse confirm saveas<CR>
index f74348d69229510f37f65fae5dcfef14ce99b1a0..97b41e0a89c510d32ffabcb1bb71f654e6e06923 100644 (file)
@@ -49,6 +49,7 @@ static int    append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file);
 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,21 +1368,30 @@ do_buffer_ext(
 #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;
+# 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
            {
-               semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override),
-                                                                buf->b_fnum);
+               no_write_message_buf(buf);
                return FAIL;
            }
        }
@@ -1552,15 +1562,34 @@ do_buffer_ext(
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
        if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
        {
-           bufref_T bufref;
+# 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;
+               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;
+               }
+           }
        }
-       if (bufIsChanged(curbuf))
+       else
 #endif
        {
            no_write_message();
@@ -1940,6 +1969,18 @@ do_autochdir(void)
 }
 #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,8 +5792,8 @@ bt_nofile(buf_T *buf)
 #endif
 
 /*
- * Return TRUE if "buf" is a "nowrite", "nofile", "terminal" or "prompt"
- * buffer.
+ * Return TRUE if "buf" is a "nowrite", "nofile", "terminal", "prompt", or
+ * "popup" buffer.
  */
     int
 bt_dontwrite(buf_T *buf)
index 3db15922facb07732bf5532b81462abdb48fc858..c13d354bc1c32121d405921c7661e74226ad812b 100644 (file)
@@ -86,6 +86,13 @@ check_changed(buf_T *buf, int flags)
 #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,6 +205,7 @@ dialog_changed(
                        || (cmdmod.cmod_flags & CMOD_BROWSE)
 #endif
                        )
+                   && !bt_dontwrite(buf2)
                    && !buf2->b_p_ro)
            {
                bufref_T bufref;
index 8ca5ede46bb5e2f0e53058ed2cd04a94ac038c2c..f5b39804653e4b8c3a1f57a43bb887329b2e6157 100644 (file)
@@ -6061,13 +6061,27 @@ ex_win_close(
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
        if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
        {
-           bufref_T bufref;
+# 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;
+               set_bufref(&bufref, buf);
+               dialog_changed(buf, FALSE);
+               if (bufref_valid(&bufref) && bufIsChanged(buf))
+                   return;
+               need_hide = FALSE;
+           }
        }
        else
 #endif
index 9de563115d7ec03fe51d035e6e0e11cf88c5db3d..7a7c507a89cf52edf7eb8bdbe52a00d9075ff5a7 100644 (file)
@@ -10,6 +10,7 @@ void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
 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);
index f5687df6125d518e998eca7f16a7ea1844847b90..46ed325a52feff58a4588ed3586f400e88bca52c 100644 (file)
@@ -1651,6 +1651,25 @@ term_none_open(term_T *term)
        && 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,14 +1685,9 @@ term_try_stop_job(buf_T *buf)
     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)
+       if (term_confirm_stop(buf) == OK)
            how = "kill";
-       else if (ret == VIM_CANCEL)
+       else
            return FAIL;
     }
 #endif
index e6548079a9dda43ccd2624c59425d2e0e50acc92..80f5db61d7ac0bf0cabae1f3fdba100d18db8496 100644 (file)
@@ -98,7 +98,7 @@ endfunc
 
 func Test_terminal_wipe_buffer()
   let buf = Run_shell_in_terminal({})
-  call assert_fails(buf . 'bwipe', 'E89:')
+  call assert_fails(buf . 'bwipe', 'E948:')
   exe buf . 'bwipe!'
   call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
   call assert_equal("", bufname(buf))
@@ -106,6 +106,126 @@ func Test_terminal_wipe_buffer()
   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,7 +827,7 @@ endfunc
 
 func Test_terminal_list_args()
   let buf = term_start([&shell, &shellcmdflag, 'echo "123"'])
-  call assert_fails(buf . 'bwipe', 'E89:')
+  call assert_fails(buf . 'bwipe', 'E948:')
   exe buf . 'bwipe!'
   call assert_equal("", bufname(buf))
 endfunction
@@ -1235,7 +1355,7 @@ func Test_terminal_qall_prompt()
 
   " make Vim exit, it will prompt to kill the shell
   call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>")
-  call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))})
+  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))})
 
index f006710d9bcae9c1a28b63c4a46f39699dce8399..7bd02861aae97c26562a6a820b7319614795b7c3 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    708,
 /**/
     707,
 /**/