mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.0.1593: :qall never exits with an active terminal window
Problem: :qall never exits with an active terminal window. Solution: Add a way to kill a job in a terminal window.
This commit is contained in:
parent
b5b7562475
commit
25cdd9c33b
@ -1,4 +1,4 @@
|
|||||||
*eval.txt* For Vim version 8.0. Last change: 2018 Mar 09
|
*eval.txt* For Vim version 8.0. Last change: 2018 Mar 10
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -2435,6 +2435,7 @@ term_gettty({buf}, [{input}]) String get the tty name of a terminal
|
|||||||
term_list() List get the list of terminal buffers
|
term_list() List get the list of terminal buffers
|
||||||
term_scrape({buf}, {row}) List get row of a terminal screen
|
term_scrape({buf}, {row}) List get row of a terminal screen
|
||||||
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
|
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
|
||||||
|
term_setkill({buf}, {how}) none set signal to stop job in terminal
|
||||||
term_setrestore({buf}, {command}) none set command to restore terminal
|
term_setrestore({buf}, {command}) none set command to restore terminal
|
||||||
term_start({cmd}, {options}) Job open a terminal window and run a job
|
term_start({cmd}, {options}) Job open a terminal window and run a job
|
||||||
term_wait({buf} [, {time}]) Number wait for screen to be updated
|
term_wait({buf} [, {time}]) Number wait for screen to be updated
|
||||||
@ -8276,6 +8277,8 @@ term_getline({buf}, {row}) *term_getline()*
|
|||||||
The first line has {row} one. When {row} is "." the cursor
|
The first line has {row} one. When {row} is "." the cursor
|
||||||
line is used. When {row} is invalid an empty string is
|
line is used. When {row} is invalid an empty string is
|
||||||
returned.
|
returned.
|
||||||
|
|
||||||
|
To get attributes of each character use |term_scrape()|.
|
||||||
{only available when compiled with the |+terminal| feature}
|
{only available when compiled with the |+terminal| feature}
|
||||||
|
|
||||||
term_getscrolled({buf}) *term_getscrolled()*
|
term_getscrolled({buf}) *term_getscrolled()*
|
||||||
@ -8361,6 +8364,18 @@ term_sendkeys({buf}, {keys}) *term_sendkeys()*
|
|||||||
means the character CTRL-X.
|
means the character CTRL-X.
|
||||||
{only available when compiled with the |+terminal| feature}
|
{only available when compiled with the |+terminal| feature}
|
||||||
|
|
||||||
|
term_setkill({buf}, {how}) *term_setkill()*
|
||||||
|
When exiting Vim or trying to close the terminal window in
|
||||||
|
another way, {how} defines whether the job in the terminal can
|
||||||
|
be stopped.
|
||||||
|
When {how} is empty (the default), the job will not be
|
||||||
|
stopped, trying to exit will result in |E947|.
|
||||||
|
Otherwise, {how} specifies what signal to send to the job.
|
||||||
|
See |job_stop()| for the values.
|
||||||
|
|
||||||
|
After sending the signal Vim will wait for up to a second to
|
||||||
|
check that the job actually stopped.
|
||||||
|
|
||||||
term_setrestore({buf}, {command}) *term_setrestore()*
|
term_setrestore({buf}, {command}) *term_setrestore()*
|
||||||
Set the command to write in a session file to restore the job
|
Set the command to write in a session file to restore the job
|
||||||
in this terminal. The line written in the session file is: >
|
in this terminal. The line written in the session file is: >
|
||||||
@ -8416,6 +8431,8 @@ term_start({cmd}, {options}) *term_start()*
|
|||||||
"hidden" do not open a window
|
"hidden" do not open a window
|
||||||
"norestore" do not add the terminal window to a
|
"norestore" do not add the terminal window to a
|
||||||
session file
|
session file
|
||||||
|
"term_kill" what to do when trying to close the
|
||||||
|
terminal window, see |term_setkill()|
|
||||||
"term_finish" What to do when the job is finished:
|
"term_finish" What to do when the job is finished:
|
||||||
"close": close any windows
|
"close": close any windows
|
||||||
"open": open window if needed
|
"open": open window if needed
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
*terminal.txt* For Vim version 8.0. Last change: 2018 Mar 09
|
*terminal.txt* For Vim version 8.0. Last change: 2018 Mar 10
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -166,6 +166,9 @@ Syntax ~
|
|||||||
no window will be used.
|
no window will be used.
|
||||||
++norestore Do not include this terminal window
|
++norestore Do not include this terminal window
|
||||||
in a session file.
|
in a session file.
|
||||||
|
++kill={how} When trying to close the terminal
|
||||||
|
window kill the job with {how}. See
|
||||||
|
|term_setkill()| for the values.
|
||||||
++rows={height} Use {height} for the terminal window
|
++rows={height} Use {height} for the terminal window
|
||||||
height. If the terminal uses the full
|
height. If the terminal uses the full
|
||||||
Vim height (no window above or below
|
Vim height (no window above or below
|
||||||
@ -189,8 +192,12 @@ Syntax ~
|
|||||||
If you want to use more options use the |term_start()|
|
If you want to use more options use the |term_start()|
|
||||||
function.
|
function.
|
||||||
|
|
||||||
When the buffer associated with the terminal is unloaded or wiped out the job
|
When the buffer associated with the terminal is forcibly unloaded or wiped out
|
||||||
is killed, similar to calling `job_stop(job, "kill")`
|
the job is killed, similar to calling `job_stop(job, "kill")` .
|
||||||
|
Closing the window normally results in |E947|. When a kill method was set
|
||||||
|
with "++kill={how}" or |term_setkill()| then closing the window will use that
|
||||||
|
way to kill or interrupt the job. For example: >
|
||||||
|
:term ++kill=term tail -f /tmp/log
|
||||||
|
|
||||||
So long as the job is running the window behaves like it contains a modified
|
So long as the job is running the window behaves like it contains a modified
|
||||||
buffer. Trying to close the window with `CTRL-W :quit` fails. When using
|
buffer. Trying to close the window with `CTRL-W :quit` fails. When using
|
||||||
|
@ -4746,50 +4746,57 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
|
|||||||
{
|
{
|
||||||
if (!(supported2 & JO2_TERM_ROWS))
|
if (!(supported2 & JO2_TERM_ROWS))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO2_TERM_ROWS;
|
opt->jo_set2 |= JO2_TERM_ROWS;
|
||||||
opt->jo_term_rows = get_tv_number(item);
|
opt->jo_term_rows = get_tv_number(item);
|
||||||
}
|
}
|
||||||
else if (STRCMP(hi->hi_key, "term_cols") == 0)
|
else if (STRCMP(hi->hi_key, "term_cols") == 0)
|
||||||
{
|
{
|
||||||
if (!(supported2 & JO2_TERM_COLS))
|
if (!(supported2 & JO2_TERM_COLS))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO2_TERM_COLS;
|
opt->jo_set2 |= JO2_TERM_COLS;
|
||||||
opt->jo_term_cols = get_tv_number(item);
|
opt->jo_term_cols = get_tv_number(item);
|
||||||
}
|
}
|
||||||
else if (STRCMP(hi->hi_key, "vertical") == 0)
|
else if (STRCMP(hi->hi_key, "vertical") == 0)
|
||||||
{
|
{
|
||||||
if (!(supported2 & JO2_VERTICAL))
|
if (!(supported2 & JO2_VERTICAL))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO2_VERTICAL;
|
opt->jo_set2 |= JO2_VERTICAL;
|
||||||
opt->jo_vertical = get_tv_number(item);
|
opt->jo_vertical = get_tv_number(item);
|
||||||
}
|
}
|
||||||
else if (STRCMP(hi->hi_key, "curwin") == 0)
|
else if (STRCMP(hi->hi_key, "curwin") == 0)
|
||||||
{
|
{
|
||||||
if (!(supported2 & JO2_CURWIN))
|
if (!(supported2 & JO2_CURWIN))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO2_CURWIN;
|
opt->jo_set2 |= JO2_CURWIN;
|
||||||
opt->jo_curwin = get_tv_number(item);
|
opt->jo_curwin = get_tv_number(item);
|
||||||
}
|
}
|
||||||
else if (STRCMP(hi->hi_key, "hidden") == 0)
|
else if (STRCMP(hi->hi_key, "hidden") == 0)
|
||||||
{
|
{
|
||||||
if (!(supported2 & JO2_HIDDEN))
|
if (!(supported2 & JO2_HIDDEN))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO2_HIDDEN;
|
opt->jo_set2 |= JO2_HIDDEN;
|
||||||
opt->jo_hidden = get_tv_number(item);
|
opt->jo_hidden = get_tv_number(item);
|
||||||
}
|
}
|
||||||
else if (STRCMP(hi->hi_key, "norestore") == 0)
|
else if (STRCMP(hi->hi_key, "norestore") == 0)
|
||||||
{
|
{
|
||||||
if (!(supported2 & JO2_NORESTORE))
|
if (!(supported2 & JO2_NORESTORE))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO2_NORESTORE;
|
opt->jo_set2 |= JO2_NORESTORE;
|
||||||
opt->jo_term_norestore = get_tv_number(item);
|
opt->jo_term_norestore = get_tv_number(item);
|
||||||
}
|
}
|
||||||
|
else if (STRCMP(hi->hi_key, "term_kill") == 0)
|
||||||
|
{
|
||||||
|
if (!(supported2 & JO2_TERM_KILL))
|
||||||
|
break;
|
||||||
|
opt->jo_set2 |= JO2_TERM_KILL;
|
||||||
|
opt->jo_term_kill = get_tv_string_chk(item);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (STRCMP(hi->hi_key, "env") == 0)
|
else if (STRCMP(hi->hi_key, "env") == 0)
|
||||||
{
|
{
|
||||||
if (!(supported2 & JO2_ENV))
|
if (!(supported2 & JO2_ENV))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO2_ENV;
|
opt->jo_set2 |= JO2_ENV;
|
||||||
opt->jo_env = item->vval.v_dict;
|
opt->jo_env = item->vval.v_dict;
|
||||||
++item->vval.v_dict->dv_refcount;
|
++item->vval.v_dict->dv_refcount;
|
||||||
}
|
}
|
||||||
@ -4803,7 +4810,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
|
|||||||
EMSG2(_(e_invargval), "cwd");
|
EMSG2(_(e_invargval), "cwd");
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
opt->jo_set |= JO2_CWD;
|
opt->jo_set2 |= JO2_CWD;
|
||||||
}
|
}
|
||||||
else if (STRCMP(hi->hi_key, "waittime") == 0)
|
else if (STRCMP(hi->hi_key, "waittime") == 0)
|
||||||
{
|
{
|
||||||
|
@ -867,6 +867,7 @@ static struct fst
|
|||||||
{"term_list", 0, 0, f_term_list},
|
{"term_list", 0, 0, f_term_list},
|
||||||
{"term_scrape", 2, 2, f_term_scrape},
|
{"term_scrape", 2, 2, f_term_scrape},
|
||||||
{"term_sendkeys", 2, 2, f_term_sendkeys},
|
{"term_sendkeys", 2, 2, f_term_sendkeys},
|
||||||
|
{"term_setkill", 2, 2, f_term_setkill},
|
||||||
{"term_setrestore", 2, 2, f_term_setrestore},
|
{"term_setrestore", 2, 2, f_term_setrestore},
|
||||||
{"term_start", 1, 2, f_term_start},
|
{"term_start", 1, 2, f_term_start},
|
||||||
{"term_wait", 1, 2, f_term_wait},
|
{"term_wait", 1, 2, f_term_wait},
|
||||||
|
@ -2254,7 +2254,7 @@ add_bufnum(int *bufnrs, int *bufnump, int nr)
|
|||||||
/*
|
/*
|
||||||
* Return TRUE if any buffer was changed and cannot be abandoned.
|
* Return TRUE if any buffer was changed and cannot be abandoned.
|
||||||
* That changed buffer becomes the current buffer.
|
* That changed buffer becomes the current buffer.
|
||||||
* When "unload" is true the current buffer is unloaded instead of making it
|
* When "unload" is TRUE the current buffer is unloaded instead of making it
|
||||||
* hidden. This is used for ":q!".
|
* hidden. This is used for ":q!".
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
@ -2272,6 +2272,7 @@ check_changed_any(
|
|||||||
tabpage_T *tp;
|
tabpage_T *tp;
|
||||||
win_T *wp;
|
win_T *wp;
|
||||||
|
|
||||||
|
/* Make a list of all buffers, with the most important ones first. */
|
||||||
FOR_ALL_BUFFERS(buf)
|
FOR_ALL_BUFFERS(buf)
|
||||||
++bufcount;
|
++bufcount;
|
||||||
|
|
||||||
@ -2284,17 +2285,19 @@ check_changed_any(
|
|||||||
|
|
||||||
/* curbuf */
|
/* curbuf */
|
||||||
bufnrs[bufnum++] = curbuf->b_fnum;
|
bufnrs[bufnum++] = curbuf->b_fnum;
|
||||||
/* buf in curtab */
|
|
||||||
|
/* buffers in current tab */
|
||||||
FOR_ALL_WINDOWS(wp)
|
FOR_ALL_WINDOWS(wp)
|
||||||
if (wp->w_buffer != curbuf)
|
if (wp->w_buffer != curbuf)
|
||||||
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
|
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
|
||||||
|
|
||||||
/* buf in other tab */
|
/* buffers in other tabs */
|
||||||
FOR_ALL_TABPAGES(tp)
|
FOR_ALL_TABPAGES(tp)
|
||||||
if (tp != curtab)
|
if (tp != curtab)
|
||||||
for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
|
for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
|
||||||
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
|
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
|
||||||
/* any other buf */
|
|
||||||
|
/* any other buffer */
|
||||||
FOR_ALL_BUFFERS(buf)
|
FOR_ALL_BUFFERS(buf)
|
||||||
add_bufnum(bufnrs, &bufnum, buf->b_fnum);
|
add_bufnum(bufnrs, &bufnum, buf->b_fnum);
|
||||||
|
|
||||||
@ -2308,6 +2311,14 @@ check_changed_any(
|
|||||||
bufref_T bufref;
|
bufref_T bufref;
|
||||||
|
|
||||||
set_bufref(&bufref, buf);
|
set_bufref(&bufref, buf);
|
||||||
|
#ifdef FEAT_TERMINAL
|
||||||
|
if (term_job_running(buf->b_term))
|
||||||
|
{
|
||||||
|
if (term_try_stop_job(buf) == FAIL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
/* Try auto-writing the buffer. If this fails but the buffer no
|
/* Try auto-writing the buffer. If this fails but the buffer no
|
||||||
* longer exists it's not changed, that's OK. */
|
* longer exists it's not changed, that's OK. */
|
||||||
if (check_changed(buf, (p_awa ? CCGD_AW : 0)
|
if (check_changed(buf, (p_awa ? CCGD_AW : 0)
|
||||||
@ -2320,6 +2331,7 @@ check_changed_any(
|
|||||||
if (i >= bufnum)
|
if (i >= bufnum)
|
||||||
goto theend;
|
goto theend;
|
||||||
|
|
||||||
|
/* Get here if "buf" cannot be abandoned. */
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
exiting = FALSE;
|
exiting = FALSE;
|
||||||
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
|
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
void ex_terminal(exarg_T *eap);
|
void ex_terminal(exarg_T *eap);
|
||||||
int term_write_session(FILE *fd, win_T *wp);
|
int term_write_session(FILE *fd, win_T *wp);
|
||||||
int term_should_restore(buf_T *buf);
|
int term_should_restore(buf_T *buf);
|
||||||
void f_term_setrestore(typval_T *argvars, typval_T *rettv);
|
|
||||||
void free_terminal(buf_T *buf);
|
void free_terminal(buf_T *buf);
|
||||||
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
|
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
|
||||||
int term_job_running(term_T *term);
|
int term_job_running(term_T *term);
|
||||||
int term_none_open(term_T *term);
|
int term_none_open(term_T *term);
|
||||||
|
int term_try_stop_job(buf_T *buf);
|
||||||
int term_in_normal_mode(void);
|
int term_in_normal_mode(void);
|
||||||
void term_enter_job_mode(void);
|
void term_enter_job_mode(void);
|
||||||
int send_keys_to_term(term_T *term, int c, int typed);
|
int send_keys_to_term(term_T *term, int c, int typed);
|
||||||
@ -41,6 +41,8 @@ void f_term_gettty(typval_T *argvars, typval_T *rettv);
|
|||||||
void f_term_list(typval_T *argvars, typval_T *rettv);
|
void f_term_list(typval_T *argvars, typval_T *rettv);
|
||||||
void f_term_scrape(typval_T *argvars, typval_T *rettv);
|
void f_term_scrape(typval_T *argvars, typval_T *rettv);
|
||||||
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
|
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
|
||||||
|
void f_term_setrestore(typval_T *argvars, typval_T *rettv);
|
||||||
|
void f_term_setkill(typval_T *argvars, typval_T *rettv);
|
||||||
void f_term_start(typval_T *argvars, typval_T *rettv);
|
void f_term_start(typval_T *argvars, typval_T *rettv);
|
||||||
void f_term_wait(typval_T *argvars, typval_T *rettv);
|
void f_term_wait(typval_T *argvars, typval_T *rettv);
|
||||||
void term_send_eof(channel_T *ch);
|
void term_send_eof(channel_T *ch);
|
||||||
|
@ -1707,7 +1707,8 @@ struct channel_S {
|
|||||||
#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */
|
#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */
|
||||||
#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */
|
#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */
|
||||||
#define JO2_NORESTORE 0x2000 /* "norestore" */
|
#define JO2_NORESTORE 0x2000 /* "norestore" */
|
||||||
#define JO2_ALL 0x2FFF
|
#define JO2_TERM_KILL 0x4000 /* "term_kill" */
|
||||||
|
#define JO2_ALL 0x7FFF
|
||||||
|
|
||||||
#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 \
|
||||||
@ -1775,6 +1776,7 @@ typedef struct
|
|||||||
char_u *jo_term_opencmd;
|
char_u *jo_term_opencmd;
|
||||||
int jo_term_finish;
|
int jo_term_finish;
|
||||||
char_u *jo_eof_chars;
|
char_u *jo_eof_chars;
|
||||||
|
char_u *jo_term_kill;
|
||||||
#endif
|
#endif
|
||||||
} jobopt_T;
|
} jobopt_T;
|
||||||
|
|
||||||
|
132
src/terminal.c
132
src/terminal.c
@ -137,6 +137,7 @@ struct terminal_S {
|
|||||||
#if defined(FEAT_SESSION)
|
#if defined(FEAT_SESSION)
|
||||||
char_u *tl_command;
|
char_u *tl_command;
|
||||||
#endif
|
#endif
|
||||||
|
char_u *tl_kill;
|
||||||
|
|
||||||
/* last known vterm size */
|
/* last known vterm size */
|
||||||
int tl_rows;
|
int tl_rows;
|
||||||
@ -535,6 +536,13 @@ term_start(typval_T *argvar, jobopt_T *opt, int without_job, int forceit)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (opt->jo_term_kill != NULL)
|
||||||
|
{
|
||||||
|
char_u *p = skiptowhite(opt->jo_term_kill);
|
||||||
|
|
||||||
|
term->tl_kill = vim_strnsave(opt->jo_term_kill, p - opt->jo_term_kill);
|
||||||
|
}
|
||||||
|
|
||||||
/* System dependent: setup the vterm and maybe start the job in it. */
|
/* System dependent: setup the vterm and maybe start the job in it. */
|
||||||
if (argvar->v_type == VAR_STRING
|
if (argvar->v_type == VAR_STRING
|
||||||
&& argvar->vval.v_string != NULL
|
&& argvar->vval.v_string != NULL
|
||||||
@ -611,6 +619,13 @@ ex_terminal(exarg_T *eap)
|
|||||||
opt.jo_hidden = 1;
|
opt.jo_hidden = 1;
|
||||||
else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
|
else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
|
||||||
opt.jo_term_norestore = 1;
|
opt.jo_term_norestore = 1;
|
||||||
|
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "kill", 4) == 0
|
||||||
|
&& ep != NULL)
|
||||||
|
{
|
||||||
|
opt.jo_set2 |= JO2_TERM_KILL;
|
||||||
|
opt.jo_term_kill = ep + 1;
|
||||||
|
p = skiptowhite(cmd);
|
||||||
|
}
|
||||||
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0
|
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0
|
||||||
&& ep != NULL && isdigit(ep[1]))
|
&& ep != NULL && isdigit(ep[1]))
|
||||||
{
|
{
|
||||||
@ -644,7 +659,7 @@ ex_terminal(exarg_T *eap)
|
|||||||
if (*p)
|
if (*p)
|
||||||
*p = NUL;
|
*p = NUL;
|
||||||
EMSG2(_("E181: Invalid attribute: %s"), cmd);
|
EMSG2(_("E181: Invalid attribute: %s"), cmd);
|
||||||
return;
|
goto theend;
|
||||||
}
|
}
|
||||||
cmd = skipwhite(p);
|
cmd = skipwhite(p);
|
||||||
}
|
}
|
||||||
@ -667,6 +682,8 @@ ex_terminal(exarg_T *eap)
|
|||||||
argvar[1].v_type = VAR_UNKNOWN;
|
argvar[1].v_type = VAR_UNKNOWN;
|
||||||
term_start(argvar, &opt, FALSE, eap->forceit);
|
term_start(argvar, &opt, FALSE, eap->forceit);
|
||||||
vim_free(tofree);
|
vim_free(tofree);
|
||||||
|
|
||||||
|
theend:
|
||||||
vim_free(opt.jo_eof_chars);
|
vim_free(opt.jo_eof_chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,6 +775,7 @@ free_terminal(buf_T *buf)
|
|||||||
#ifdef FEAT_SESSION
|
#ifdef FEAT_SESSION
|
||||||
vim_free(term->tl_command);
|
vim_free(term->tl_command);
|
||||||
#endif
|
#endif
|
||||||
|
vim_free(term->tl_kill);
|
||||||
vim_free(term->tl_status_text);
|
vim_free(term->tl_status_text);
|
||||||
vim_free(term->tl_opencmd);
|
vim_free(term->tl_opencmd);
|
||||||
vim_free(term->tl_eof_chars);
|
vim_free(term->tl_eof_chars);
|
||||||
@ -1080,6 +1098,56 @@ term_none_open(term_T *term)
|
|||||||
&& term->tl_job->jv_channel->ch_keep_open;
|
&& term->tl_job->jv_channel->ch_keep_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used when exiting: kill the job in "buf" if so desired.
|
||||||
|
* Return OK when the job finished.
|
||||||
|
* Return FAIL when the job is still running.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
term_try_stop_job(buf_T *buf)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
char *how = (char *)buf->b_term->tl_kill;
|
||||||
|
|
||||||
|
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
|
||||||
|
if ((how == NULL || *how == NUL) && (p_confirm || cmdmod.confirm))
|
||||||
|
{
|
||||||
|
char_u buff[DIALOG_MSG_SIZE];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dialog_msg(buff, _("Kill job in \"%s\"?"), buf->b_fname);
|
||||||
|
ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
|
||||||
|
if (ret == VIM_YES)
|
||||||
|
how = "kill";
|
||||||
|
else if (ret == VIM_CANCEL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (how == NULL || *how == NUL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
job_stop(buf->b_term->tl_job, NULL, how);
|
||||||
|
|
||||||
|
/* wait for up to a second for the job to die */
|
||||||
|
for (count = 0; count < 100; ++count)
|
||||||
|
{
|
||||||
|
/* buffer, terminal and job may be cleaned up while waiting */
|
||||||
|
if (!buf_valid(buf)
|
||||||
|
|| buf->b_term == NULL
|
||||||
|
|| buf->b_term->tl_job == NULL)
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
/* call job_status() to update jv_status */
|
||||||
|
job_status(buf->b_term->tl_job);
|
||||||
|
if (buf->b_term->tl_job->jv_status >= JOB_ENDED)
|
||||||
|
return OK;
|
||||||
|
ui_delay(10L, FALSE);
|
||||||
|
mch_check_messages();
|
||||||
|
parse_queued_messages();
|
||||||
|
}
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the last line of the scrollback buffer to the buffer in the window.
|
* Add the last line of the scrollback buffer to the buffer in the window.
|
||||||
*/
|
*/
|
||||||
@ -2922,10 +2990,11 @@ set_terminal_default_colors(int cterm_fg, int cterm_bg)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the buffer from the first argument in "argvars".
|
* Get the buffer from the first argument in "argvars".
|
||||||
* Returns NULL when the buffer is not for a terminal window.
|
* Returns NULL when the buffer is not for a terminal window and logs a message
|
||||||
|
* with "where".
|
||||||
*/
|
*/
|
||||||
static buf_T *
|
static buf_T *
|
||||||
term_get_buf(typval_T *argvars)
|
term_get_buf(typval_T *argvars, char *where)
|
||||||
{
|
{
|
||||||
buf_T *buf;
|
buf_T *buf;
|
||||||
|
|
||||||
@ -2934,7 +3003,10 @@ term_get_buf(typval_T *argvars)
|
|||||||
buf = get_buf_tv(&argvars[0], FALSE);
|
buf = get_buf_tv(&argvars[0], FALSE);
|
||||||
--emsg_off;
|
--emsg_off;
|
||||||
if (buf == NULL || buf->b_term == NULL)
|
if (buf == NULL || buf->b_term == NULL)
|
||||||
|
{
|
||||||
|
ch_log(NULL, "%s: invalid buffer argument", where);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2980,7 +3052,7 @@ dump_term_color(FILE *fd, VTermColor *color)
|
|||||||
void
|
void
|
||||||
f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED)
|
f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_dumpwrite()");
|
||||||
term_T *term;
|
term_T *term;
|
||||||
char_u *fname;
|
char_u *fname;
|
||||||
int max_height = 0;
|
int max_height = 0;
|
||||||
@ -3719,7 +3791,7 @@ f_term_dumpload(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_getaltscreen(typval_T *argvars, typval_T *rettv)
|
f_term_getaltscreen(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_getaltscreen()");
|
||||||
|
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return;
|
return;
|
||||||
@ -3766,7 +3838,7 @@ f_term_getattr(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_getcursor(typval_T *argvars, typval_T *rettv)
|
f_term_getcursor(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_getcursor()");
|
||||||
term_T *term;
|
term_T *term;
|
||||||
list_T *l;
|
list_T *l;
|
||||||
dict_T *d;
|
dict_T *d;
|
||||||
@ -3800,7 +3872,7 @@ f_term_getcursor(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_getjob(typval_T *argvars, typval_T *rettv)
|
f_term_getjob(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_getjob()");
|
||||||
|
|
||||||
rettv->v_type = VAR_JOB;
|
rettv->v_type = VAR_JOB;
|
||||||
rettv->vval.v_job = NULL;
|
rettv->vval.v_job = NULL;
|
||||||
@ -3828,7 +3900,7 @@ get_row_number(typval_T *tv, term_T *term)
|
|||||||
void
|
void
|
||||||
f_term_getline(typval_T *argvars, typval_T *rettv)
|
f_term_getline(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_getline()");
|
||||||
term_T *term;
|
term_T *term;
|
||||||
int row;
|
int row;
|
||||||
|
|
||||||
@ -3875,7 +3947,7 @@ f_term_getline(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_getscrolled(typval_T *argvars, typval_T *rettv)
|
f_term_getscrolled(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_getscrolled()");
|
||||||
|
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return;
|
return;
|
||||||
@ -3888,7 +3960,7 @@ f_term_getscrolled(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_getsize(typval_T *argvars, typval_T *rettv)
|
f_term_getsize(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_getsize()");
|
||||||
list_T *l;
|
list_T *l;
|
||||||
|
|
||||||
if (rettv_list_alloc(rettv) == FAIL)
|
if (rettv_list_alloc(rettv) == FAIL)
|
||||||
@ -3907,7 +3979,7 @@ f_term_getsize(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_getstatus(typval_T *argvars, typval_T *rettv)
|
f_term_getstatus(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_getstatus()");
|
||||||
term_T *term;
|
term_T *term;
|
||||||
char_u val[100];
|
char_u val[100];
|
||||||
|
|
||||||
@ -3931,7 +4003,7 @@ f_term_getstatus(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_gettitle(typval_T *argvars, typval_T *rettv)
|
f_term_gettitle(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_gettitle()");
|
||||||
|
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
@ -3947,7 +4019,7 @@ f_term_gettitle(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_gettty(typval_T *argvars, typval_T *rettv)
|
f_term_gettty(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_gettty()");
|
||||||
char_u *p;
|
char_u *p;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
@ -4005,7 +4077,7 @@ f_term_list(typval_T *argvars UNUSED, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_scrape(typval_T *argvars, typval_T *rettv)
|
f_term_scrape(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_scrape()");
|
||||||
VTermScreen *screen = NULL;
|
VTermScreen *screen = NULL;
|
||||||
VTermPos pos;
|
VTermPos pos;
|
||||||
list_T *l;
|
list_T *l;
|
||||||
@ -4114,7 +4186,7 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_sendkeys(typval_T *argvars, typval_T *rettv)
|
f_term_sendkeys(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_sendkeys()");
|
||||||
char_u *msg;
|
char_u *msg;
|
||||||
term_T *term;
|
term_T *term;
|
||||||
|
|
||||||
@ -4143,7 +4215,7 @@ f_term_sendkeys(typval_T *argvars, typval_T *rettv)
|
|||||||
f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||||
{
|
{
|
||||||
#if defined(FEAT_SESSION)
|
#if defined(FEAT_SESSION)
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_setrestore()");
|
||||||
term_T *term;
|
term_T *term;
|
||||||
char_u *cmd;
|
char_u *cmd;
|
||||||
|
|
||||||
@ -4159,6 +4231,27 @@ f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "term_setkill(buf, how)" function
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
f_term_setkill(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||||
|
{
|
||||||
|
buf_T *buf = term_get_buf(argvars, "term_setkill()");
|
||||||
|
term_T *term;
|
||||||
|
char_u *how;
|
||||||
|
|
||||||
|
if (buf == NULL)
|
||||||
|
return;
|
||||||
|
term = buf->b_term;
|
||||||
|
vim_free(term->tl_kill);
|
||||||
|
how = get_tv_string_chk(&argvars[1]);
|
||||||
|
if (how != NULL)
|
||||||
|
term->tl_kill = vim_strsave(how);
|
||||||
|
else
|
||||||
|
term->tl_kill = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "term_start(command, options)" function
|
* "term_start(command, options)" function
|
||||||
*/
|
*/
|
||||||
@ -4177,7 +4270,7 @@ f_term_start(typval_T *argvars, typval_T *rettv)
|
|||||||
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
|
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
|
||||||
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
|
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
|
||||||
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
|
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
|
||||||
+ JO2_NORESTORE) == FAIL)
|
+ JO2_NORESTORE + JO2_TERM_KILL) == FAIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (opt.jo_vertical)
|
if (opt.jo_vertical)
|
||||||
@ -4194,13 +4287,10 @@ f_term_start(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
|
f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
|
||||||
{
|
{
|
||||||
buf_T *buf = term_get_buf(argvars);
|
buf_T *buf = term_get_buf(argvars, "term_wait()");
|
||||||
|
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
{
|
|
||||||
ch_log(NULL, "term_wait(): invalid argument");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (buf->b_term->tl_job == NULL)
|
if (buf->b_term->tl_job == NULL)
|
||||||
{
|
{
|
||||||
ch_log(NULL, "term_wait(): no job to wait for");
|
ch_log(NULL, "term_wait(): no job to wait for");
|
||||||
|
@ -5,6 +5,7 @@ if !has('terminal')
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
source shared.vim
|
source shared.vim
|
||||||
|
source screendump.vim
|
||||||
|
|
||||||
let s:python = PythonProg()
|
let s:python = PythonProg()
|
||||||
|
|
||||||
@ -839,3 +840,48 @@ func Test_terminal_response_to_control_sequence()
|
|||||||
call delete('Xescape')
|
call delete('Xescape')
|
||||||
unlet g:job
|
unlet g:job
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Run Vim in a terminal, then start a terminal in that Vim with a kill
|
||||||
|
" argument, check that :qall works.
|
||||||
|
func Test_terminal_qall_kill_arg()
|
||||||
|
if !CanRunVimInTerminal()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let buf = RunVimInTerminal('', {})
|
||||||
|
|
||||||
|
" Open a terminal window and wait for the prompt to appear
|
||||||
|
call term_sendkeys(buf, ":term ++kill=kill\<CR>")
|
||||||
|
call WaitFor({-> term_getline(buf, 10) =~ '\[running]'})
|
||||||
|
call WaitFor({-> term_getline(buf, 1) !~ '^\s*$'})
|
||||||
|
|
||||||
|
" make Vim exit, it will kill the shell
|
||||||
|
call term_sendkeys(buf, "\<C-W>:qall\<CR>")
|
||||||
|
call WaitFor({-> term_getstatus(buf) == "finished"})
|
||||||
|
|
||||||
|
" close the terminal window where Vim was running
|
||||||
|
quit
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Run Vim in a terminal, then start a terminal in that Vim with a kill
|
||||||
|
" argument, check that :qall works.
|
||||||
|
func Test_terminal_qall_kill_func()
|
||||||
|
if !CanRunVimInTerminal()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let buf = RunVimInTerminal('', {})
|
||||||
|
|
||||||
|
" Open a terminal window and wait for the prompt to appear
|
||||||
|
call term_sendkeys(buf, ":term\<CR>")
|
||||||
|
call WaitFor({-> term_getline(buf, 10) =~ '\[running]'})
|
||||||
|
call WaitFor({-> term_getline(buf, 1) !~ '^\s*$'})
|
||||||
|
|
||||||
|
" set kill using term_setkill()
|
||||||
|
call term_sendkeys(buf, "\<C-W>:call term_setkill(bufnr('%'), 'kill')\<CR>")
|
||||||
|
|
||||||
|
" make Vim exit, it will kill the shell
|
||||||
|
call term_sendkeys(buf, "\<C-W>:qall\<CR>")
|
||||||
|
call WaitFor({-> term_getstatus(buf) == "finished"})
|
||||||
|
|
||||||
|
" close the terminal window where Vim was running
|
||||||
|
quit
|
||||||
|
endfunc
|
||||||
|
@ -766,6 +766,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 */
|
||||||
|
/**/
|
||||||
|
1593,
|
||||||
/**/
|
/**/
|
||||||
1592,
|
1592,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user