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 -- b...@moolenaar.net -- 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 vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui