Patch 8.0.1593
Problem: :qall never exits with an active terminal window.
Solution: Add a way to kill a job in a terminal window.
Files: src/ex_cmds2.c, src/terminal.c, src/proto/terminal.pro,
src/structs.h, src/channel.c, src/evalfunc.c,
src/testdir/test_terminal.vim, runtime/doc/terminal.txt,
runtime/doc/eval.txt
*** ../vim-8.0.1592/src/ex_cmds2.c 2018-03-04 20:14:08.244064367 +0100
--- src/ex_cmds2.c 2018-03-10 17:09:46.692310947 +0100
***************
*** 2254,2260 ****
/*
* Return TRUE if any buffer was changed and cannot be abandoned.
* That changed buffer becomes the current buffer.
! * When "unload" is true the current buffer is unloaded instead of making it
* hidden. This is used for ":q!".
*/
int
--- 2254,2260 ----
/*
* Return TRUE if any buffer was changed and cannot be abandoned.
* That changed buffer becomes the current buffer.
! * When "unload" is TRUE the current buffer is unloaded instead of making it
* hidden. This is used for ":q!".
*/
int
***************
*** 2272,2277 ****
--- 2272,2278 ----
tabpage_T *tp;
win_T *wp;
+ /* Make a list of all buffers, with the most important ones first. */
FOR_ALL_BUFFERS(buf)
++bufcount;
***************
*** 2284,2300 ****
/* curbuf */
bufnrs[bufnum++] = curbuf->b_fnum;
! /* buf in curtab */
FOR_ALL_WINDOWS(wp)
if (wp->w_buffer != curbuf)
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
! /* buf in other tab */
FOR_ALL_TABPAGES(tp)
if (tp != curtab)
for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
! /* any other buf */
FOR_ALL_BUFFERS(buf)
add_bufnum(bufnrs, &bufnum, buf->b_fnum);
--- 2285,2303 ----
/* curbuf */
bufnrs[bufnum++] = curbuf->b_fnum;
!
! /* buffers in current tab */
FOR_ALL_WINDOWS(wp)
if (wp->w_buffer != curbuf)
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
! /* buffers in other tabs */
FOR_ALL_TABPAGES(tp)
if (tp != curtab)
for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
!
! /* any other buffer */
FOR_ALL_BUFFERS(buf)
add_bufnum(bufnrs, &bufnum, buf->b_fnum);
***************
*** 2308,2313 ****
--- 2311,2324 ----
bufref_T bufref;
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
* longer exists it's not changed, that's OK. */
if (check_changed(buf, (p_awa ? CCGD_AW : 0)
***************
*** 2320,2325 ****
--- 2331,2337 ----
if (i >= bufnum)
goto theend;
+ /* Get here if "buf" cannot be abandoned. */
ret = TRUE;
exiting = FALSE;
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
*** ../vim-8.0.1592/src/terminal.c 2018-03-09 21:33:29.244607400 +0100
--- src/terminal.c 2018-03-10 19:25:43.386676907 +0100
***************
*** 137,142 ****
--- 137,143 ----
#if defined(FEAT_SESSION)
char_u *tl_command;
#endif
+ char_u *tl_kill;
/* last known vterm size */
int tl_rows;
***************
*** 535,540 ****
--- 536,548 ----
}
#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. */
if (argvar->v_type == VAR_STRING
&& argvar->vval.v_string != NULL
***************
*** 611,616 ****
--- 619,631 ----
opt.jo_hidden = 1;
else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
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
&& ep != NULL && isdigit(ep[1]))
{
***************
*** 644,650 ****
if (*p)
*p = NUL;
EMSG2(_("E181: Invalid attribute: %s"), cmd);
! return;
}
cmd = skipwhite(p);
}
--- 659,665 ----
if (*p)
*p = NUL;
EMSG2(_("E181: Invalid attribute: %s"), cmd);
! goto theend;
}
cmd = skipwhite(p);
}
***************
*** 667,672 ****
--- 682,689 ----
argvar[1].v_type = VAR_UNKNOWN;
term_start(argvar, &opt, FALSE, eap->forceit);
vim_free(tofree);
+
+ theend:
vim_free(opt.jo_eof_chars);
}
***************
*** 758,763 ****
--- 775,781 ----
#ifdef FEAT_SESSION
vim_free(term->tl_command);
#endif
+ vim_free(term->tl_kill);
vim_free(term->tl_status_text);
vim_free(term->tl_opencmd);
vim_free(term->tl_eof_chars);
***************
*** 1081,1086 ****
--- 1099,1154 ----
}
/*
+ * 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.
*/
static void
***************
*** 2922,2931 ****
/*
* Get the buffer from the first argument in "argvars".
! * Returns NULL when the buffer is not for a terminal window.
*/
static buf_T *
! term_get_buf(typval_T *argvars)
{
buf_T *buf;
--- 2990,3000 ----
/*
* Get the buffer from the first argument in "argvars".
! * Returns NULL when the buffer is not for a terminal window and logs a
message
! * with "where".
*/
static buf_T *
! term_get_buf(typval_T *argvars, char *where)
{
buf_T *buf;
***************
*** 2934,2940 ****
--- 3003,3012 ----
buf = get_buf_tv(&argvars[0], FALSE);
--emsg_off;
if (buf == NULL || buf->b_term == NULL)
+ {
+ ch_log(NULL, "%s: invalid buffer argument", where);
return NULL;
+ }
return buf;
}
***************
*** 2980,2986 ****
void
f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED)
{
! buf_T *buf = term_get_buf(argvars);
term_T *term;
char_u *fname;
int max_height = 0;
--- 3052,3058 ----
void
f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED)
{
! buf_T *buf = term_get_buf(argvars, "term_dumpwrite()");
term_T *term;
char_u *fname;
int max_height = 0;
***************
*** 3719,3725 ****
void
f_term_getaltscreen(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
if (buf == NULL)
return;
--- 3791,3797 ----
void
f_term_getaltscreen(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_getaltscreen()");
if (buf == NULL)
return;
***************
*** 3766,3772 ****
void
f_term_getcursor(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
term_T *term;
list_T *l;
dict_T *d;
--- 3838,3844 ----
void
f_term_getcursor(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_getcursor()");
term_T *term;
list_T *l;
dict_T *d;
***************
*** 3800,3806 ****
void
f_term_getjob(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
rettv->v_type = VAR_JOB;
rettv->vval.v_job = NULL;
--- 3872,3878 ----
void
f_term_getjob(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_getjob()");
rettv->v_type = VAR_JOB;
rettv->vval.v_job = NULL;
***************
*** 3828,3834 ****
void
f_term_getline(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
term_T *term;
int row;
--- 3900,3906 ----
void
f_term_getline(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_getline()");
term_T *term;
int row;
***************
*** 3875,3881 ****
void
f_term_getscrolled(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
if (buf == NULL)
return;
--- 3947,3953 ----
void
f_term_getscrolled(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_getscrolled()");
if (buf == NULL)
return;
***************
*** 3888,3894 ****
void
f_term_getsize(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
list_T *l;
if (rettv_list_alloc(rettv) == FAIL)
--- 3960,3966 ----
void
f_term_getsize(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_getsize()");
list_T *l;
if (rettv_list_alloc(rettv) == FAIL)
***************
*** 3907,3913 ****
void
f_term_getstatus(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
term_T *term;
char_u val[100];
--- 3979,3985 ----
void
f_term_getstatus(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_getstatus()");
term_T *term;
char_u val[100];
***************
*** 3931,3937 ****
void
f_term_gettitle(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
rettv->v_type = VAR_STRING;
if (buf == NULL)
--- 4003,4009 ----
void
f_term_gettitle(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_gettitle()");
rettv->v_type = VAR_STRING;
if (buf == NULL)
***************
*** 3947,3953 ****
void
f_term_gettty(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
char_u *p;
int num = 0;
--- 4019,4025 ----
void
f_term_gettty(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_gettty()");
char_u *p;
int num = 0;
***************
*** 4005,4011 ****
void
f_term_scrape(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
VTermScreen *screen = NULL;
VTermPos pos;
list_T *l;
--- 4077,4083 ----
void
f_term_scrape(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_scrape()");
VTermScreen *screen = NULL;
VTermPos pos;
list_T *l;
***************
*** 4114,4120 ****
void
f_term_sendkeys(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars);
char_u *msg;
term_T *term;
--- 4186,4192 ----
void
f_term_sendkeys(typval_T *argvars, typval_T *rettv)
{
! buf_T *buf = term_get_buf(argvars, "term_sendkeys()");
char_u *msg;
term_T *term;
***************
*** 4143,4149 ****
f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
#if defined(FEAT_SESSION)
! buf_T *buf = term_get_buf(argvars);
term_T *term;
char_u *cmd;
--- 4215,4221 ----
f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
#if defined(FEAT_SESSION)
! buf_T *buf = term_get_buf(argvars, "term_setrestore()");
term_T *term;
char_u *cmd;
***************
*** 4160,4165 ****
--- 4232,4258 ----
}
/*
+ * "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
*/
void
***************
*** 4177,4183 ****
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
! + JO2_NORESTORE) == FAIL)
return;
if (opt.jo_vertical)
--- 4270,4276 ----
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
! + JO2_NORESTORE + JO2_TERM_KILL) == FAIL)
return;
if (opt.jo_vertical)
***************
*** 4194,4206 ****
void
f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
{
! buf_T *buf = term_get_buf(argvars);
if (buf == NULL)
- {
- ch_log(NULL, "term_wait(): invalid argument");
return;
- }
if (buf->b_term->tl_job == NULL)
{
ch_log(NULL, "term_wait(): no job to wait for");
--- 4287,4296 ----
void
f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
{
! buf_T *buf = term_get_buf(argvars, "term_wait()");
if (buf == NULL)
return;
if (buf->b_term->tl_job == NULL)
{
ch_log(NULL, "term_wait(): no job to wait for");
*** ../vim-8.0.1592/src/proto/terminal.pro 2018-03-09 21:33:29.244607400
+0100
--- src/proto/terminal.pro 2018-03-10 16:42:12.906432147 +0100
***************
*** 2,12 ****
void ex_terminal(exarg_T *eap);
int term_write_session(FILE *fd, win_T *wp);
int term_should_restore(buf_T *buf);
- void f_term_setrestore(typval_T *argvars, typval_T *rettv);
void free_terminal(buf_T *buf);
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
int term_job_running(term_T *term);
int term_none_open(term_T *term);
int term_in_normal_mode(void);
void term_enter_job_mode(void);
int send_keys_to_term(term_T *term, int c, int typed);
--- 2,12 ----
void ex_terminal(exarg_T *eap);
int term_write_session(FILE *fd, win_T *wp);
int term_should_restore(buf_T *buf);
void free_terminal(buf_T *buf);
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
int term_job_running(term_T *term);
int term_none_open(term_T *term);
+ int term_try_stop_job(buf_T *buf);
int term_in_normal_mode(void);
void term_enter_job_mode(void);
int send_keys_to_term(term_T *term, int c, int typed);
***************
*** 41,46 ****
--- 41,48 ----
void f_term_list(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_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_wait(typval_T *argvars, typval_T *rettv);
void term_send_eof(channel_T *ch);
*** ../vim-8.0.1592/src/structs.h 2018-03-09 21:33:29.248607375 +0100
--- src/structs.h 2018-03-10 16:26:00.952400695 +0100
***************
*** 1707,1713 ****
#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */
#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */
#define JO2_NORESTORE 0x2000 /* "norestore" */
! #define JO2_ALL 0x2FFF
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
#define JO_CB_ALL \
--- 1707,1714 ----
#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */
#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */
#define JO2_NORESTORE 0x2000 /* "norestore" */
! #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_CB_ALL \
***************
*** 1775,1780 ****
--- 1776,1782 ----
char_u *jo_term_opencmd;
int jo_term_finish;
char_u *jo_eof_chars;
+ char_u *jo_term_kill;
#endif
} jobopt_T;
*** ../vim-8.0.1592/src/channel.c 2018-03-09 21:33:29.248607375 +0100
--- src/channel.c 2018-03-10 16:33:37.405595372 +0100
***************
*** 4746,4795 ****
{
if (!(supported2 & JO2_TERM_ROWS))
break;
! opt->jo_set |= JO2_TERM_ROWS;
opt->jo_term_rows = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "term_cols") == 0)
{
if (!(supported2 & JO2_TERM_COLS))
break;
! opt->jo_set |= JO2_TERM_COLS;
opt->jo_term_cols = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "vertical") == 0)
{
if (!(supported2 & JO2_VERTICAL))
break;
! opt->jo_set |= JO2_VERTICAL;
opt->jo_vertical = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "curwin") == 0)
{
if (!(supported2 & JO2_CURWIN))
break;
! opt->jo_set |= JO2_CURWIN;
opt->jo_curwin = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "hidden") == 0)
{
if (!(supported2 & JO2_HIDDEN))
break;
! opt->jo_set |= JO2_HIDDEN;
opt->jo_hidden = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "norestore") == 0)
{
if (!(supported2 & JO2_NORESTORE))
break;
! opt->jo_set |= JO2_NORESTORE;
opt->jo_term_norestore = get_tv_number(item);
}
#endif
else if (STRCMP(hi->hi_key, "env") == 0)
{
if (!(supported2 & JO2_ENV))
break;
! opt->jo_set |= JO2_ENV;
opt->jo_env = item->vval.v_dict;
++item->vval.v_dict->dv_refcount;
}
--- 4746,4802 ----
{
if (!(supported2 & JO2_TERM_ROWS))
break;
! opt->jo_set2 |= JO2_TERM_ROWS;
opt->jo_term_rows = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "term_cols") == 0)
{
if (!(supported2 & JO2_TERM_COLS))
break;
! opt->jo_set2 |= JO2_TERM_COLS;
opt->jo_term_cols = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "vertical") == 0)
{
if (!(supported2 & JO2_VERTICAL))
break;
! opt->jo_set2 |= JO2_VERTICAL;
opt->jo_vertical = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "curwin") == 0)
{
if (!(supported2 & JO2_CURWIN))
break;
! opt->jo_set2 |= JO2_CURWIN;
opt->jo_curwin = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "hidden") == 0)
{
if (!(supported2 & JO2_HIDDEN))
break;
! opt->jo_set2 |= JO2_HIDDEN;
opt->jo_hidden = get_tv_number(item);
}
else if (STRCMP(hi->hi_key, "norestore") == 0)
{
if (!(supported2 & JO2_NORESTORE))
break;
! opt->jo_set2 |= JO2_NORESTORE;
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
else if (STRCMP(hi->hi_key, "env") == 0)
{
if (!(supported2 & JO2_ENV))
break;
! opt->jo_set2 |= JO2_ENV;
opt->jo_env = item->vval.v_dict;
++item->vval.v_dict->dv_refcount;
}
***************
*** 4803,4809 ****
EMSG2(_(e_invargval), "cwd");
return FAIL;
}
! opt->jo_set |= JO2_CWD;
}
else if (STRCMP(hi->hi_key, "waittime") == 0)
{
--- 4810,4816 ----
EMSG2(_(e_invargval), "cwd");
return FAIL;
}
! opt->jo_set2 |= JO2_CWD;
}
else if (STRCMP(hi->hi_key, "waittime") == 0)
{
*** ../vim-8.0.1592/src/evalfunc.c 2018-03-09 21:33:29.248607375 +0100
--- src/evalfunc.c 2018-03-10 16:37:28.772175036 +0100
***************
*** 867,872 ****
--- 867,873 ----
{"term_list", 0, 0, f_term_list},
{"term_scrape", 2, 2, f_term_scrape},
{"term_sendkeys", 2, 2, f_term_sendkeys},
+ {"term_setkill", 2, 2, f_term_setkill},
{"term_setrestore", 2, 2, f_term_setrestore},
{"term_start", 1, 2, f_term_start},
{"term_wait", 1, 2, f_term_wait},
*** ../vim-8.0.1592/src/testdir/test_terminal.vim 2018-03-09
21:33:29.248607375 +0100
--- src/testdir/test_terminal.vim 2018-03-10 20:12:39.257284108 +0100
***************
*** 5,10 ****
--- 5,11 ----
endif
source shared.vim
+ source screendump.vim
let s:python = PythonProg()
***************
*** 839,841 ****
--- 840,887 ----
call delete('Xescape')
unlet g:job
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
*** ../vim-8.0.1592/runtime/doc/terminal.txt 2018-03-03 20:46:28.759725294
+0100
--- runtime/doc/terminal.txt 2018-03-10 16:55:45.829450728 +0100
***************
*** 20,25 ****
--- 20,26 ----
Terminal Modes |Terminal-mode|
Cursor style |terminal-cursor-style|
Special keys |terminal-special-keys|
+ Session |terminal-session|
Unix |terminal-unix|
MS-Windows |terminal-ms-windows|
2. Remote testing |terminal-testing|
***************
*** 163,168 ****
--- 164,174 ----
cannot be |abandon|ed.
++hidden Open the terminal in a hidden buffer,
no window will be used.
+ ++norestore Do not include this terminal window
+ 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
height. If the terminal uses the full
Vim height (no window above or below
***************
*** 186,193 ****
If you want to use more options use the |term_start()|
function.
! When the buffer associated with the terminal is unloaded or wiped out the job
! is killed, similar to calling `job_stop(job, "kill")`
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
--- 192,203 ----
If you want to use more options use the |term_start()|
function.
! When the buffer associated with the terminal is forcibly unloaded or wiped out
! 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
buffer. Trying to close the window with `CTRL-W :quit` fails. When using
***************
*** 286,291 ****
--- 296,317 ----
blinking will also be inverted.
+ Session ~
+ *terminal-session*
+ A terminal window will be restored when using a session file, if possible and
+ wanted.
+
+ If "terminal" was removed from 'sessionoptions' then no terminal windows will
+ be restored.
+
+ If the job in the terminal was finished the window will not be restored.
+
+ If the terminal can be restored, the command that was used to open it will be
+ used again. To change this use the |term_setrestore()| function. This can
+ also be used to not restore a specific terminal by setting the command to
+ "NONE".
+
+
Special keys ~
*terminal-special-keys*
Since the terminal emulator simulates an xterm, only escape sequences that
*** ../vim-8.0.1592/runtime/doc/eval.txt 2018-03-03 21:29:46.922813914
+0100
--- runtime/doc/eval.txt 2018-03-10 20:26:12.776249783 +0100
***************
*** 2430,2435 ****
--- 2435,2442 ----
term_list() List get the list of terminal buffers
term_scrape({buf}, {row}) List get row of a terminal screen
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_start({cmd}, {options}) Job open a terminal window and run a job
term_wait({buf} [, {time}]) Number wait for screen to be updated
test_alloc_fail({id}, {countdown}, {repeat})
***************
*** 8217,8222 ****
--- 8277,8284 ----
The first line has {row} one. When {row} is "." the cursor
line is used. When {row} is invalid an empty string is
returned.
+
+ To get attributes of each character use |term_scrape()|.
{only available when compiled with the |+terminal| feature}
term_getscrolled({buf})
*term_getscrolled()*
***************
*** 8302,8307 ****
--- 8364,8391 ----
means the character CTRL-X.
{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()*
+ Set the command to write in a session file to restore the job
+ in this terminal. The line written in the session file is: >
+ terminal ++curwin ++cols=%d ++rows=%d {command}
+ < Make sure to escape the command properly.
+
+ Use an empty {command} to run 'shell'.
+ Use "NONE" to not restore this window.
+ {only available when compiled with the |+terminal| feature}
+
term_setsize({buf}, {expr}) *term_setsize()*
Not implemented yet.
{only available when compiled with the |+terminal| feature}
***************
*** 8344,8349 ****
--- 8428,8438 ----
"curwin" use the current window, do not split the
window; fails if the current buffer
cannot be |abandon|ed
+ "hidden" do not open a window
+ "norestore" do not add the terminal window to a
+ 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:
"close": close any windows
"open": open window if needed
*** ../vim-8.0.1592/src/version.c 2018-03-09 21:33:29.248607375 +0100
--- src/version.c 2018-03-10 20:22:36.889590211 +0100
***************
*** 768,769 ****
--- 768,771 ----
{ /* Add new patch number below this line */
+ /**/
+ 1593,
/**/
--
Female engineers become irresistible at the age of consent and remain that
way until about thirty minutes after their clinical death. Longer if it's a
warm day.
(Scott Adams - The Dilbert principle)
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.