summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYee Cheng Chin <ychin.git@gmail.com>2022-10-09 18:53:32 +0100
committerBram Moolenaar <Bram@vim.org>2022-10-09 18:53:32 +0100
commit15b314ffbb93f934b72cb71aa8f881caea026256 (patch)
treecffce54dd07078c4d6407e7e06a2823f945e6ef6
parent118c235112854f34182d968613d7fe98be3b290b (diff)
downloadvim-git-9.0.0708.tar.gz
patch 9.0.0708: :confirm does not work properly for a terminal bufferv9.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)
-rw-r--r--runtime/menu.vim6
-rw-r--r--src/buffer.c81
-rw-r--r--src/ex_cmds2.c8
-rw-r--r--src/ex_docmd.c26
-rw-r--r--src/proto/terminal.pro1
-rw-r--r--src/terminal.c28
-rw-r--r--src/testdir/test_terminal.vim126
-rw-r--r--src/version.c2
8 files changed, 242 insertions, 36 deletions
diff --git a/runtime/menu.vim b/runtime/menu.vim
index 9ba2d3b3f..d449a7510 100644
--- a/runtime/menu.vim
+++ b/runtime/menu.vim
@@ -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>
diff --git a/src/buffer.c b/src/buffer.c
index f74348d69..97b41e0a8 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -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)
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 3db15922f..c13d354bc 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -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;
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 8ca5ede46..f5b398046 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -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
diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro
index 9de563115..7a7c507a8 100644
--- a/src/proto/terminal.pro
+++ b/src/proto/terminal.pro
@@ -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);
diff --git a/src/terminal.c b/src/terminal.c
index f5687df61..46ed325a5 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -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
diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim
index e6548079a..80f5db61d 100644
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -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))})
diff --git a/src/version.c b/src/version.c
index f006710d9..7bd02861a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 708,
+/**/
707,
/**/
706,