forked from aniani/vim
patch 8.0.0896: cannot close a terminal window when the job ends
Problem: Cannot automaticlaly close a terminal window when the job ends. Solution: Add the ++close argument to :term. Add the term_finish option to term_start(). (Yasuhiro Matsumoto, closes #1950) Also add ++open.
This commit is contained in:
@@ -8054,9 +8054,14 @@ term_start({cmd}, {options}) *term_start()*
|
|||||||
connected to the terminal. When I/O is connected to the
|
connected to the terminal. When I/O is connected to the
|
||||||
terminal then the callback function for that part is not used.
|
terminal then the callback function for that part is not used.
|
||||||
|
|
||||||
There is one extra option:
|
There are two extra options:
|
||||||
"term_name" name to use for the buffer name, instead of
|
"term_name" name to use for the buffer name, instead
|
||||||
the command name.
|
of the command name.
|
||||||
|
"term_finish" What todo when the job is finished:
|
||||||
|
"close": close any windows
|
||||||
|
"open": open window if needed
|
||||||
|
Note that "open" can be interruptive.
|
||||||
|
See |term++close| and |term++open|.
|
||||||
{only available when compiled with the |+terminal| feature}
|
{only available when compiled with the |+terminal| feature}
|
||||||
|
|
||||||
term_wait({buf} [, {time}]) *term_wait()*
|
term_wait({buf} [, {time}]) *term_wait()*
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 05
|
*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 10
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@@ -36,7 +36,7 @@ output from the job, also while editing in any other window.
|
|||||||
|
|
||||||
Typing ~
|
Typing ~
|
||||||
|
|
||||||
When the keyboard focus is in the terminal window, typed keys will be send to
|
When the keyboard focus is in the terminal window, typed keys will be sent to
|
||||||
the job. This uses a pty when possible. You can click outside of the
|
the job. This uses a pty when possible. You can click outside of the
|
||||||
terminal window to move keyboard focus elsewhere.
|
terminal window to move keyboard focus elsewhere.
|
||||||
|
|
||||||
@@ -47,7 +47,8 @@ See |CTRL-W| for more commands.
|
|||||||
|
|
||||||
Special in the terminal window: *CTRL-W_.* *CTRL-W_N*
|
Special in the terminal window: *CTRL-W_.* *CTRL-W_N*
|
||||||
CTRL-W . send a CTRL-W to the job in the terminal
|
CTRL-W . send a CTRL-W to the job in the terminal
|
||||||
CTRL-W N go to Terminal Normal mode, see |Terminal-mode|
|
CTRL-W N go to Terminal-Normal mode, see |Terminal-mode|
|
||||||
|
CTRL-\ CTRL-N go to Terminal-Normal mode, see |Terminal-mode|
|
||||||
CTRL-W " {reg} paste register {reg} *CTRL-W_quote*
|
CTRL-W " {reg} paste register {reg} *CTRL-W_quote*
|
||||||
Also works with the = register to insert the result of
|
Also works with the = register to insert the result of
|
||||||
evaluating an expression.
|
evaluating an expression.
|
||||||
@@ -62,10 +63,8 @@ the job. For example:
|
|||||||
'termkey' N go to terminal Normal mode, see below
|
'termkey' N go to terminal Normal mode, see below
|
||||||
'termkey' CTRL-N same as CTRL-W N
|
'termkey' CTRL-N same as CTRL-W N
|
||||||
*t_CTRL-\_CTRL-N*
|
*t_CTRL-\_CTRL-N*
|
||||||
The special key combination CTRL-\ CTRL-N can be used to prefix one Normal
|
The special key combination CTRL-\ CTRL-N can be used to switch to Normal
|
||||||
mode command. This is especially useful for remote commands, when you don't
|
mode, just like this works in any other mode.
|
||||||
know whether Vim currently has focus in a terminal window. Note that only one
|
|
||||||
Normal mode command can be used.
|
|
||||||
|
|
||||||
|
|
||||||
Size ~
|
Size ~
|
||||||
@@ -76,7 +75,7 @@ See option 'termsize' for controlling the size of the terminal window.
|
|||||||
|
|
||||||
Syntax ~
|
Syntax ~
|
||||||
|
|
||||||
:ter[minal] [command] *:ter* *:terminal*
|
:[range]ter[minal] [options] [command] *:ter* *:terminal*
|
||||||
Open a new terminal window.
|
Open a new terminal window.
|
||||||
|
|
||||||
If [command] is provided run it as a job and connect
|
If [command] is provided run it as a job and connect
|
||||||
@@ -86,9 +85,27 @@ Syntax ~
|
|||||||
A new buffer will be created, using [command] or
|
A new buffer will be created, using [command] or
|
||||||
'shell' as the name, prefixed with a "!". If a buffer
|
'shell' as the name, prefixed with a "!". If a buffer
|
||||||
by this name already exists a number is added in
|
by this name already exists a number is added in
|
||||||
parenthesis. E.g. if "gdb" exists the second terminal
|
parentheses. E.g. if "gdb" exists the second terminal
|
||||||
buffer will use "!gdb (1)".
|
buffer will use "!gdb (1)".
|
||||||
|
|
||||||
|
If [range] is given it is used for the terminal size.
|
||||||
|
One number specifies the number of rows. Unless the
|
||||||
|
"vertical" modifier is used, then it is the number of
|
||||||
|
columns.
|
||||||
|
|
||||||
|
Two comma separated numbers are used as "rows,cols".
|
||||||
|
E.g. `:24,80gdb` opens a terminal with 24 rows and 80
|
||||||
|
columns. However, if the terminal window spans the
|
||||||
|
Vim window with, there is no vertical split, the Vim
|
||||||
|
window width is used.
|
||||||
|
*term++close* *term++open*
|
||||||
|
Supported [options] are:
|
||||||
|
++close The terminal window will close
|
||||||
|
automatically when the job terminates.
|
||||||
|
++open When the job terminates and no window
|
||||||
|
show it, a window will be opened.
|
||||||
|
Note that this can be interruptive.
|
||||||
|
|
||||||
When the buffer associated with the terminal is wiped out the job is killed,
|
When the buffer associated with the terminal is wiped out the job is killed,
|
||||||
similar to calling `job_stop(job, "kill")`
|
similar to calling `job_stop(job, "kill")`
|
||||||
|
|
||||||
@@ -133,23 +150,26 @@ terminal. |term_setsize()| can be used only when in the first or second mode,
|
|||||||
not when 'termsize' is "rowsXcols".
|
not when 'termsize' is "rowsXcols".
|
||||||
|
|
||||||
|
|
||||||
Terminal Normal mode ~
|
Terminal-Job and Terminal-Normal mode ~
|
||||||
*Terminal-mode*
|
*Terminal-mode*
|
||||||
When the job is running the contents of the terminal is under control of the
|
When the job is running the contents of the terminal is under control of the
|
||||||
job. That includes the cursor position. The terminal contents can change at
|
job. That includes the cursor position. Typed keys are sent to the job.
|
||||||
any time.
|
The terminal contents can change at any time. This is called Terminal-Job
|
||||||
|
mode.
|
||||||
|
|
||||||
Use CTRL-W N (or 'termkey' N) to go to Terminal Normal mode. Now the contents
|
Use CTRL-W N (or 'termkey' N) to switch to Terminal-Normal mode. Now the
|
||||||
of the terminal window is under control of Vim, the job output is suspended.
|
contents of the terminal window is under control of Vim, the job output is
|
||||||
|
suspended. CTRL-\ CTRL-N does the same.
|
||||||
*E946*
|
*E946*
|
||||||
In this mode you can move the cursor around with the usual Vim commands,
|
In Terminal-Normal mode you can move the cursor around with the usual Vim
|
||||||
Visually mark text, yank text, etc. But you cannot change the contents of the
|
commands, Visually mark text, yank text, etc. But you cannot change the
|
||||||
buffer. The commands that would start insert mode, such as 'i' and 'a',
|
contents of the buffer. The commands that would start insert mode, such as
|
||||||
return control of the window to the job. Any pending output will now be
|
'i' and 'a', return to Terminal-Job mode. The window will be updated to show
|
||||||
displayed.
|
the contents of the terminal.
|
||||||
|
|
||||||
In Terminal mode the statusline and window title show "(Terminal)". If the
|
In Terminal-Normal mode the statusline and window title show "(Terminal)". If
|
||||||
job ends while in Terminal mode this changes to "(Terminal-finished)".
|
the job ends while in Terminal-Normal mode this changes to
|
||||||
|
"(Terminal-finished)".
|
||||||
|
|
||||||
|
|
||||||
Unix ~
|
Unix ~
|
||||||
|
@@ -4419,6 +4419,19 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (STRCMP(hi->hi_key, "term_finish") == 0)
|
||||||
|
{
|
||||||
|
if (!(supported & JO2_TERM_FINISH))
|
||||||
|
break;
|
||||||
|
val = get_tv_string(item);
|
||||||
|
if (STRCMP(val, "open") != 0 && STRCMP(val, "close") != 0)
|
||||||
|
{
|
||||||
|
EMSG2(_(e_invarg2), "drop");
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
opt->jo_set2 |= JO2_TERM_FINISH;
|
||||||
|
opt->jo_term_finish = *val;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (STRCMP(hi->hi_key, "waittime") == 0)
|
else if (STRCMP(hi->hi_key, "waittime") == 0)
|
||||||
{
|
{
|
||||||
|
@@ -1685,7 +1685,8 @@ struct channel_S {
|
|||||||
#define JO2_OUT_MSG 0x0001 /* "out_msg" */
|
#define JO2_OUT_MSG 0x0001 /* "out_msg" */
|
||||||
#define JO2_ERR_MSG 0x0002 /* "err_msg" (JO_OUT_ << 1) */
|
#define JO2_ERR_MSG 0x0002 /* "err_msg" (JO_OUT_ << 1) */
|
||||||
#define JO2_TERM_NAME 0x0004 /* "term_name" */
|
#define JO2_TERM_NAME 0x0004 /* "term_name" */
|
||||||
#define JO2_ALL 0x0007
|
#define JO2_TERM_FINISH 0x0008 /* "term_finish" */
|
||||||
|
#define JO2_ALL 0x000F
|
||||||
|
|
||||||
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
|
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
|
||||||
#define JO_CB_ALL \
|
#define JO_CB_ALL \
|
||||||
@@ -1743,6 +1744,7 @@ typedef struct
|
|||||||
int jo_term_rows;
|
int jo_term_rows;
|
||||||
int jo_term_cols;
|
int jo_term_cols;
|
||||||
char_u *jo_term_name;
|
char_u *jo_term_name;
|
||||||
|
int jo_term_finish;
|
||||||
#endif
|
#endif
|
||||||
} jobopt_T;
|
} jobopt_T;
|
||||||
|
|
||||||
|
@@ -36,18 +36,14 @@
|
|||||||
* that buffer, attributes come from the scrollback buffer tl_scrollback.
|
* that buffer, attributes come from the scrollback buffer tl_scrollback.
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
* - When the job ends:
|
|
||||||
* - Need an option or argument to drop the window+buffer right away, to be
|
|
||||||
* used for a shell or Vim. 'termfinish'; "close", "open" (open window when
|
|
||||||
* job finishes).
|
|
||||||
* patch by Yasuhiro: #1950
|
|
||||||
* - add option values to the command:
|
* - add option values to the command:
|
||||||
* :term <24x80> <close> vim notes.txt
|
|
||||||
* or use:
|
|
||||||
* :term ++24x80 ++close vim notes.txt
|
* :term ++24x80 ++close vim notes.txt
|
||||||
|
* - When using term_finish "open" have a way to specify how the window is to
|
||||||
|
* be opened. E.g. term_opencmd "10split buffer %d".
|
||||||
* - support different cursor shapes, colors and attributes
|
* - support different cursor shapes, colors and attributes
|
||||||
* - make term_getcursor() return type (none/block/bar/underline) and
|
* - make term_getcursor() return type (none/block/bar/underline) and
|
||||||
* attributes (color, blink, etc.)
|
* attributes (color, blink, etc.)
|
||||||
|
* - Make argument list work on MS-Windows. #1954
|
||||||
* - MS-Windows: no redraw for 'updatetime' #1915
|
* - MS-Windows: no redraw for 'updatetime' #1915
|
||||||
* - To set BS correctly, check get_stty(); Pass the fd of the pty.
|
* - To set BS correctly, check get_stty(); Pass the fd of the pty.
|
||||||
* For the GUI fill termios with default values, perhaps like pangoterm:
|
* For the GUI fill termios with default values, perhaps like pangoterm:
|
||||||
@@ -124,6 +120,7 @@ struct terminal_S {
|
|||||||
|
|
||||||
int tl_normal_mode; /* TRUE: Terminal-Normal mode */
|
int tl_normal_mode; /* TRUE: Terminal-Normal mode */
|
||||||
int tl_channel_closed;
|
int tl_channel_closed;
|
||||||
|
int tl_finish; /* 'c' for ++close, 'o' for ++open */
|
||||||
|
|
||||||
#ifdef WIN3264
|
#ifdef WIN3264
|
||||||
void *tl_winpty_config;
|
void *tl_winpty_config;
|
||||||
@@ -257,6 +254,7 @@ term_start(char_u *cmd, jobopt_T *opt)
|
|||||||
return;
|
return;
|
||||||
term->tl_dirty_row_end = MAX_ROW;
|
term->tl_dirty_row_end = MAX_ROW;
|
||||||
term->tl_cursor_visible = TRUE;
|
term->tl_cursor_visible = TRUE;
|
||||||
|
term->tl_finish = opt->jo_term_finish;
|
||||||
ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
|
ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
|
||||||
|
|
||||||
/* Open a new window or tab. */
|
/* Open a new window or tab. */
|
||||||
@@ -361,9 +359,31 @@ term_start(char_u *cmd, jobopt_T *opt)
|
|||||||
ex_terminal(exarg_T *eap)
|
ex_terminal(exarg_T *eap)
|
||||||
{
|
{
|
||||||
jobopt_T opt;
|
jobopt_T opt;
|
||||||
|
char_u *cmd;
|
||||||
|
|
||||||
init_job_options(&opt);
|
init_job_options(&opt);
|
||||||
|
|
||||||
|
cmd = eap->arg;
|
||||||
|
while (*cmd && *cmd == '+' && *(cmd + 1) == '+')
|
||||||
|
{
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
cmd += 2;
|
||||||
|
p = skiptowhite(cmd);
|
||||||
|
if ((int)(p - cmd) == 5 && STRNICMP(cmd, "close", 5) == 0)
|
||||||
|
opt.jo_term_finish = 'c';
|
||||||
|
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "open", 4) == 0)
|
||||||
|
opt.jo_term_finish = 'o';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*p)
|
||||||
|
*p = NUL;
|
||||||
|
EMSG2(_("E181: Invalid attribute: %s"), cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cmd = skipwhite(p);
|
||||||
|
}
|
||||||
|
|
||||||
if (eap->addr_count == 2)
|
if (eap->addr_count == 2)
|
||||||
{
|
{
|
||||||
opt.jo_term_rows = eap->line1;
|
opt.jo_term_rows = eap->line1;
|
||||||
@@ -378,7 +398,7 @@ ex_terminal(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
/* TODO: get more options from before the command */
|
/* TODO: get more options from before the command */
|
||||||
|
|
||||||
term_start(eap->arg, &opt);
|
term_start(cmd, &opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -846,6 +866,7 @@ set_terminal_mode(term_T *term, int normal_mode)
|
|||||||
static void
|
static void
|
||||||
cleanup_vterm(term_T *term)
|
cleanup_vterm(term_T *term)
|
||||||
{
|
{
|
||||||
|
if (term->tl_finish == 0)
|
||||||
move_terminal_to_buffer(term);
|
move_terminal_to_buffer(term);
|
||||||
term_free_vterm(term);
|
term_free_vterm(term);
|
||||||
set_terminal_mode(term, FALSE);
|
set_terminal_mode(term, FALSE);
|
||||||
@@ -1415,6 +1436,7 @@ term_channel_closed(channel_T *ch)
|
|||||||
if (term->tl_job == ch->ch_job)
|
if (term->tl_job == ch->ch_job)
|
||||||
{
|
{
|
||||||
term->tl_channel_closed = TRUE;
|
term->tl_channel_closed = TRUE;
|
||||||
|
did_one = TRUE;
|
||||||
|
|
||||||
vim_free(term->tl_title);
|
vim_free(term->tl_title);
|
||||||
term->tl_title = NULL;
|
term->tl_title = NULL;
|
||||||
@@ -1423,10 +1445,29 @@ term_channel_closed(channel_T *ch)
|
|||||||
|
|
||||||
/* Unless in Terminal-Normal mode: clear the vterm. */
|
/* Unless in Terminal-Normal mode: clear the vterm. */
|
||||||
if (!term->tl_normal_mode)
|
if (!term->tl_normal_mode)
|
||||||
|
{
|
||||||
|
int fnum = term->tl_buffer->b_fnum;
|
||||||
|
|
||||||
cleanup_vterm(term);
|
cleanup_vterm(term);
|
||||||
|
|
||||||
|
if (term->tl_finish == 'c')
|
||||||
|
{
|
||||||
|
/* ++close or term_finish == "close" */
|
||||||
|
curbuf = term->tl_buffer;
|
||||||
|
do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (term->tl_finish == 'o' && term->tl_buffer->b_nwindows == 0)
|
||||||
|
{
|
||||||
|
char buf[50];
|
||||||
|
|
||||||
|
/* TODO: use term_opencmd */
|
||||||
|
vim_snprintf(buf, sizeof(buf), "botright sbuf %d", fnum);
|
||||||
|
do_cmdline_cmd((char_u *)buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
|
redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
|
||||||
did_one = TRUE;
|
|
||||||
}
|
}
|
||||||
if (did_one)
|
if (did_one)
|
||||||
{
|
{
|
||||||
@@ -2298,7 +2339,7 @@ f_term_start(typval_T *argvars, typval_T *rettv)
|
|||||||
&& get_job_options(&argvars[1], &opt,
|
&& get_job_options(&argvars[1], &opt,
|
||||||
JO_TIMEOUT_ALL + JO_STOPONEXIT
|
JO_TIMEOUT_ALL + JO_STOPONEXIT
|
||||||
+ JO_EXIT_CB + JO_CLOSE_CALLBACK
|
+ JO_EXIT_CB + JO_CLOSE_CALLBACK
|
||||||
+ JO2_TERM_NAME) == FAIL)
|
+ JO2_TERM_NAME + JO2_TERM_FINISH) == FAIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
term_start(cmd, &opt);
|
term_start(cmd, &opt);
|
||||||
|
@@ -264,3 +264,43 @@ func Test_terminal_size()
|
|||||||
bwipe!
|
bwipe!
|
||||||
call assert_equal([6, 20], size)
|
call assert_equal([6, 20], size)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_finish_close()
|
||||||
|
call assert_equal(1, winnr('$'))
|
||||||
|
|
||||||
|
" TODO: use something that takes much less than a whole second
|
||||||
|
if has('win32')
|
||||||
|
let cmd = $windir . '\system32\timeout.exe 1'
|
||||||
|
else
|
||||||
|
let cmd = 'sleep 1'
|
||||||
|
endif
|
||||||
|
exe 'terminal ++close ' . cmd
|
||||||
|
let buf = bufnr('')
|
||||||
|
call assert_equal(2, winnr('$'))
|
||||||
|
|
||||||
|
wincmd p
|
||||||
|
sleep 1200 msec
|
||||||
|
call assert_equal(1, winnr('$'))
|
||||||
|
|
||||||
|
call term_start(cmd, {'term_finish': 'close'})
|
||||||
|
call assert_equal(2, winnr('$'))
|
||||||
|
let buf = bufnr('')
|
||||||
|
wincmd p
|
||||||
|
sleep 1200 msec
|
||||||
|
call assert_equal(1, winnr('$'))
|
||||||
|
|
||||||
|
exe 'terminal ++open ' . cmd
|
||||||
|
let buf = bufnr('')
|
||||||
|
close
|
||||||
|
sleep 1200 msec
|
||||||
|
call assert_equal(2, winnr('$'))
|
||||||
|
bwipe
|
||||||
|
|
||||||
|
call term_start(cmd, {'term_finish': 'open'})
|
||||||
|
let buf = bufnr('')
|
||||||
|
close
|
||||||
|
sleep 1200 msec
|
||||||
|
call assert_equal(2, winnr('$'))
|
||||||
|
|
||||||
|
bwipe
|
||||||
|
endfunc
|
||||||
|
@@ -769,6 +769,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
896,
|
||||||
/**/
|
/**/
|
||||||
895,
|
895,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user