]> granicus.if.org Git - vim/commitdiff
patch 8.0.1593: :qall never exits with an active terminal window v8.0.1593
authorBram Moolenaar <Bram@vim.org>
Sat, 10 Mar 2018 19:28:12 +0000 (20:28 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 10 Mar 2018 19:28:12 +0000 (20:28 +0100)
Problem:    :qall never exits with an active terminal window.
Solution:   Add a way to kill a job in a terminal window.

runtime/doc/eval.txt
runtime/doc/terminal.txt
src/channel.c
src/evalfunc.c
src/ex_cmds2.c
src/proto/terminal.pro
src/structs.h
src/terminal.c
src/testdir/test_terminal.vim
src/version.c

index e153f2fe3c6ca0843cfd128aebd4f7e5fa7ba153..737233365bd55b733a65b736550654ccb0d3f716 100644 (file)
@@ -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
@@ -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_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
@@ -8276,6 +8277,8 @@ term_getline({buf}, {row})                                *term_getline()*
                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()*
@@ -8361,6 +8364,18 @@ term_sendkeys({buf}, {keys})                             *term_sendkeys()*
                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: >
@@ -8416,6 +8431,8 @@ term_start({cmd}, {options})                              *term_start()*
                   "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
index ff7950c866b29f1078e6760518b7c20bdd035e6b..d6c3d199fe5b9d6d14821b924d6eb5d018b67333 100644 (file)
@@ -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
@@ -166,6 +166,9 @@ Syntax ~
                                        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
@@ -189,8 +192,12 @@ Syntax ~
                        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")`
+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
index 7c574427a7f5133c5e83f75d93dc7f9113d0a47b..1f41445c62e084992c21c1f2c05f73e442354cb9 100644 (file)
@@ -4746,50 +4746,57 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
            {
                if (!(supported2 & JO2_TERM_ROWS))
                    break;
-               opt->jo_set |= JO2_TERM_ROWS;
+               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_set |= JO2_TERM_COLS;
+               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_set |= JO2_VERTICAL;
+               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_set |= JO2_CURWIN;
+               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_set |= JO2_HIDDEN;
+               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_set |= JO2_NORESTORE;
+               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_set |= JO2_ENV;
+               opt->jo_set2 |= JO2_ENV;
                opt->jo_env = item->vval.v_dict;
                ++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");
                    return FAIL;
                }
-               opt->jo_set |= JO2_CWD;
+               opt->jo_set2 |= JO2_CWD;
            }
            else if (STRCMP(hi->hi_key, "waittime") == 0)
            {
index aa0ec60739aae5ccdf91f42830588f52b25e1778..1620efe50179f6547a7910eee05fa9d33efd3965 100644 (file)
@@ -867,6 +867,7 @@ static struct fst
     {"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},
index 424bac8c737844f618f44d19dc22175cad69d8e7..ae4ce337d0f56f9dbca71e787d0d09770f62af39 100644 (file)
@@ -2254,7 +2254,7 @@ add_bufnum(int *bufnrs, int *bufnump, int nr)
 /*
  * 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
+ * When "unload" is TRUE the current buffer is unloaded instead of making it
  * hidden.  This is used for ":q!".
  */
     int
@@ -2272,6 +2272,7 @@ check_changed_any(
     tabpage_T   *tp;
     win_T      *wp;
 
+    /* Make a list of all buffers, with the most important ones first. */
     FOR_ALL_BUFFERS(buf)
        ++bufcount;
 
@@ -2284,17 +2285,19 @@ check_changed_any(
 
     /* curbuf */
     bufnrs[bufnum++] = curbuf->b_fnum;
-    /* buf in curtab */
+
+    /* buffers in current tab */
     FOR_ALL_WINDOWS(wp)
        if (wp->w_buffer != curbuf)
            add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
 
-    /* buf in other tab */
+    /* 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 buf */
+
+    /* any other buffer */
     FOR_ALL_BUFFERS(buf)
        add_bufnum(bufnrs, &bufnum, buf->b_fnum);
 
@@ -2308,6 +2311,14 @@ check_changed_any(
            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,6 +2331,7 @@ check_changed_any(
     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)
index aefa40d84db99c9ae72d95339d369511fe35dc3c..f7d06c050bb0621e4c26fd7245ff11e083ade062 100644 (file)
@@ -2,11 +2,11 @@
 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_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,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_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);
index d6959bc4bd1f9c0ce20a791ed82787cf079d2248..db2792bbd7111c18929a669a9d9d0837bad34768 100644 (file)
@@ -1707,7 +1707,8 @@ struct channel_S {
 #define JO2_TERM_OPENCMD    0x0800     /* "term_opencmd" */
 #define JO2_EOF_CHARS      0x1000      /* "eof_chars" */
 #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_CB_ALL \
@@ -1775,6 +1776,7 @@ typedef struct
     char_u     *jo_term_opencmd;
     int                jo_term_finish;
     char_u     *jo_eof_chars;
+    char_u     *jo_term_kill;
 #endif
 } jobopt_T;
 
index 547897fcfac49e1beedbd9619684635172c9aa6c..cc83055175fa4ca471d1dfcad12c6f707a486c66 100644 (file)
@@ -137,6 +137,7 @@ struct terminal_S {
 #if defined(FEAT_SESSION)
     char_u     *tl_command;
 #endif
+    char_u     *tl_kill;
 
     /* last known vterm size */
     int                tl_rows;
@@ -535,6 +536,13 @@ term_start(typval_T *argvar, jobopt_T *opt, int without_job, int forceit)
     }
 #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,6 +619,13 @@ ex_terminal(exarg_T *eap)
            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,7 +659,7 @@ ex_terminal(exarg_T *eap)
            if (*p)
                *p = NUL;
            EMSG2(_("E181: Invalid attribute: %s"), cmd);
-           return;
+           goto theend;
        }
        cmd = skipwhite(p);
     }
@@ -667,6 +682,8 @@ ex_terminal(exarg_T *eap)
     argvar[1].v_type = VAR_UNKNOWN;
     term_start(argvar, &opt, FALSE, eap->forceit);
     vim_free(tofree);
+
+theend:
     vim_free(opt.jo_eof_chars);
 }
 
@@ -758,6 +775,7 @@ free_terminal(buf_T *buf)
 #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);
@@ -1080,6 +1098,56 @@ term_none_open(term_T *term)
        && 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.
  */
@@ -2922,10 +2990,11 @@ set_terminal_default_colors(int cterm_fg, int cterm_bg)
 
 /*
  * 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 *
-term_get_buf(typval_T *argvars)
+term_get_buf(typval_T *argvars, char *where)
 {
     buf_T *buf;
 
@@ -2934,7 +3003,10 @@ term_get_buf(typval_T *argvars)
     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,7 +3052,7 @@ dump_term_color(FILE *fd, VTermColor *color)
     void
 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;
     char_u     *fname;
     int                max_height = 0;
@@ -3719,7 +3791,7 @@ f_term_dumpload(typval_T *argvars, typval_T *rettv)
     void
 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)
        return;
@@ -3766,7 +3838,7 @@ f_term_getattr(typval_T *argvars, typval_T *rettv)
     void
 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;
     list_T     *l;
     dict_T     *d;
@@ -3800,7 +3872,7 @@ f_term_getcursor(typval_T *argvars, typval_T *rettv)
     void
 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->vval.v_job = NULL;
@@ -3828,7 +3900,7 @@ get_row_number(typval_T *tv, term_T *term)
     void
 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;
     int                    row;
 
@@ -3875,7 +3947,7 @@ f_term_getline(typval_T *argvars, typval_T *rettv)
     void
 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)
        return;
@@ -3888,7 +3960,7 @@ f_term_getscrolled(typval_T *argvars, typval_T *rettv)
     void
 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;
 
     if (rettv_list_alloc(rettv) == FAIL)
@@ -3907,7 +3979,7 @@ f_term_getsize(typval_T *argvars, typval_T *rettv)
     void
 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;
     char_u     val[100];
 
@@ -3931,7 +4003,7 @@ f_term_getstatus(typval_T *argvars, typval_T *rettv)
     void
 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;
     if (buf == NULL)
@@ -3947,7 +4019,7 @@ f_term_gettitle(typval_T *argvars, typval_T *rettv)
     void
 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;
     int                num = 0;
 
@@ -4005,7 +4077,7 @@ f_term_list(typval_T *argvars UNUSED, typval_T *rettv)
     void
 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;
     VTermPos       pos;
     list_T         *l;
@@ -4114,7 +4186,7 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
     void
 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;
     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)
 {
 #if defined(FEAT_SESSION)
-    buf_T      *buf = term_get_buf(argvars);
+    buf_T      *buf = term_get_buf(argvars, "term_setrestore()");
     term_T     *term;
     char_u     *cmd;
 
@@ -4159,6 +4231,27 @@ f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
 #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
  */
@@ -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_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
                    + JO2_CWD + JO2_ENV + JO2_EOF_CHARS
-                   + JO2_NORESTORE) == FAIL)
+                   + JO2_NORESTORE + JO2_TERM_KILL) == FAIL)
        return;
 
     if (opt.jo_vertical)
@@ -4194,13 +4287,10 @@ f_term_start(typval_T *argvars, typval_T *rettv)
     void
 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)
-    {
-       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");
index 0e04abd5c13865d567f673c277d4e7a1a22d658a..ef6b176eec8f95a7ba44c42e350deea332f8fcdf 100644 (file)
@@ -5,6 +5,7 @@ if !has('terminal')
 endif
 
 source shared.vim
+source screendump.vim
 
 let s:python = PythonProg()
 
@@ -839,3 +840,48 @@ func Test_terminal_response_to_control_sequence()
   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
index 89b6eef14d3b734a4d1ce064310644d607439b84..727c21fe1c66d960186ffc6341f4dbf24a4a970a 100644 (file)
@@ -766,6 +766,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1593,
 /**/
     1592,
 /**/