patch 8.0.0896: cannot close a terminal window when the job ends

Problem:    Cannot automaticlaly close a terminal window when the job ends.
Solution:   Add the ++close argument to :term.  Add the term_finish option to
            term_start(). (Yasuhiro  Matsumoto, closes #1950)  Also add
            ++open.
diff --git a/src/channel.c b/src/channel.c
index a4f1cc7..4e1458c 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -4419,6 +4419,19 @@
 		    return FAIL;
 		}
 	    }
+	    else if (STRCMP(hi->hi_key, "term_finish") == 0)
+	    {
+		if (!(supported & JO2_TERM_FINISH))
+		    break;
+		val = get_tv_string(item);
+		if (STRCMP(val, "open") != 0 && STRCMP(val, "close") != 0)
+		{
+		    EMSG2(_(e_invarg2), "drop");
+		    return FAIL;
+		}
+		opt->jo_set2 |= JO2_TERM_FINISH;
+		opt->jo_term_finish = *val;
+	    }
 #endif
 	    else if (STRCMP(hi->hi_key, "waittime") == 0)
 	    {
diff --git a/src/structs.h b/src/structs.h
index 83c55a9..618cabf 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1685,7 +1685,8 @@
 #define JO2_OUT_MSG	    0x0001	/* "out_msg" */
 #define JO2_ERR_MSG	    0x0002	/* "err_msg" (JO_OUT_ << 1) */
 #define JO2_TERM_NAME	    0x0004	/* "term_name" */
-#define JO2_ALL		    0x0007
+#define JO2_TERM_FINISH	    0x0008	/* "term_finish" */
+#define JO2_ALL		    0x000F
 
 #define JO_MODE_ALL	(JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
 #define JO_CB_ALL \
@@ -1743,6 +1744,7 @@
     int		jo_term_rows;
     int		jo_term_cols;
     char_u	*jo_term_name;
+    int		jo_term_finish;
 #endif
 } jobopt_T;
 
diff --git a/src/terminal.c b/src/terminal.c
index 36d5cf1..b1cb61f 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -36,18 +36,14 @@
  * that buffer, attributes come from the scrollback buffer tl_scrollback.
  *
  * TODO:
- * - When the job ends:
- *   - Need an option or argument to drop the window+buffer right away, to be
- *     used for a shell or Vim. 'termfinish'; "close", "open" (open window when
- *     job finishes).
- *     patch by Yasuhiro: #1950
  * - add option values to the command:
- *      :term <24x80> <close> vim notes.txt
- *   or use:
  *      :term ++24x80 ++close vim notes.txt
+ * - When using term_finish "open" have a way to specify how the window is to
+ *   be opened.  E.g. term_opencmd "10split buffer %d".
  * - support different cursor shapes, colors and attributes
  * - make term_getcursor() return type (none/block/bar/underline) and
  *   attributes (color, blink, etc.)
+ * - Make argument list work on MS-Windows. #1954
  * - MS-Windows: no redraw for 'updatetime'  #1915
  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
  *   For the GUI fill termios with default values, perhaps like pangoterm:
@@ -124,6 +120,7 @@
 
     int		tl_normal_mode; /* TRUE: Terminal-Normal mode */
     int		tl_channel_closed;
+    int		tl_finish;	/* 'c' for ++close, 'o' for ++open */
 
 #ifdef WIN3264
     void	*tl_winpty_config;
@@ -257,6 +254,7 @@
 	return;
     term->tl_dirty_row_end = MAX_ROW;
     term->tl_cursor_visible = TRUE;
+    term->tl_finish = opt->jo_term_finish;
     ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
 
     /* Open a new window or tab. */
@@ -360,10 +358,32 @@
     void
 ex_terminal(exarg_T *eap)
 {
-    jobopt_T opt;
+    jobopt_T	opt;
+    char_u	*cmd;
 
     init_job_options(&opt);
 
+    cmd = eap->arg;
+    while (*cmd && *cmd == '+' && *(cmd + 1) == '+')
+    {
+	char_u  *p;
+
+	cmd += 2;
+	p = skiptowhite(cmd);
+	if ((int)(p - cmd) == 5 && STRNICMP(cmd, "close", 5) == 0)
+	    opt.jo_term_finish = 'c';
+	else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "open", 4) == 0)
+	    opt.jo_term_finish = 'o';
+	else
+	{
+	    if (*p)
+		*p = NUL;
+	    EMSG2(_("E181: Invalid attribute: %s"), cmd);
+	    return;
+	}
+	cmd = skipwhite(p);
+    }
+
     if (eap->addr_count == 2)
     {
 	opt.jo_term_rows = eap->line1;
@@ -378,7 +398,7 @@
     }
     /* TODO: get more options from before the command */
 
-    term_start(eap->arg, &opt);
+    term_start(cmd, &opt);
 }
 
 /*
@@ -846,7 +866,8 @@
     static void
 cleanup_vterm(term_T *term)
 {
-    move_terminal_to_buffer(term);
+    if (term->tl_finish == 0)
+	move_terminal_to_buffer(term);
     term_free_vterm(term);
     set_terminal_mode(term, FALSE);
 }
@@ -1415,6 +1436,7 @@
 	if (term->tl_job == ch->ch_job)
 	{
 	    term->tl_channel_closed = TRUE;
+	    did_one = TRUE;
 
 	    vim_free(term->tl_title);
 	    term->tl_title = NULL;
@@ -1423,10 +1445,29 @@
 
 	    /* Unless in Terminal-Normal mode: clear the vterm. */
 	    if (!term->tl_normal_mode)
+	    {
+		int	fnum = term->tl_buffer->b_fnum;
+
 		cleanup_vterm(term);
 
+		if (term->tl_finish == 'c')
+		{
+		    /* ++close or term_finish == "close" */
+		    curbuf = term->tl_buffer;
+		    do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
+		    break;
+		}
+		if (term->tl_finish == 'o' && term->tl_buffer->b_nwindows == 0)
+		{
+		    char buf[50];
+
+		    /* TODO: use term_opencmd */
+		    vim_snprintf(buf, sizeof(buf), "botright sbuf %d", fnum);
+		    do_cmdline_cmd((char_u *)buf);
+		}
+	    }
+
 	    redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
-	    did_one = TRUE;
 	}
     if (did_one)
     {
@@ -2298,7 +2339,7 @@
 	    && get_job_options(&argvars[1], &opt,
 		JO_TIMEOUT_ALL + JO_STOPONEXIT
 		+ JO_EXIT_CB + JO_CLOSE_CALLBACK
-		+ JO2_TERM_NAME) == FAIL)
+		+ JO2_TERM_NAME + JO2_TERM_FINISH) == FAIL)
 	return;
 
     term_start(cmd, &opt);
diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim
index cd884e1..89a784b 100644
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -264,3 +264,43 @@
   bwipe!
   call assert_equal([6, 20], size)
 endfunc
+
+func Test_finish_close()
+  call assert_equal(1, winnr('$'))
+
+  " TODO: use something that takes much less than a whole second
+  if has('win32')
+    let cmd = $windir . '\system32\timeout.exe 1'
+  else
+    let cmd = 'sleep 1'
+  endif
+  exe 'terminal ++close ' . cmd
+  let buf = bufnr('')
+  call assert_equal(2, winnr('$'))
+
+  wincmd p
+  sleep 1200 msec
+  call assert_equal(1, winnr('$'))
+
+  call term_start(cmd, {'term_finish': 'close'})
+  call assert_equal(2, winnr('$'))
+  let buf = bufnr('')
+  wincmd p
+  sleep 1200 msec
+  call assert_equal(1, winnr('$'))
+
+  exe 'terminal ++open ' . cmd
+  let buf = bufnr('')
+  close
+  sleep 1200 msec
+  call assert_equal(2, winnr('$'))
+  bwipe
+
+  call term_start(cmd, {'term_finish': 'open'})
+  let buf = bufnr('')
+  close
+  sleep 1200 msec
+  call assert_equal(2, winnr('$'))
+
+  bwipe
+endfunc
diff --git a/src/version.c b/src/version.c
index cb64bde..5459482 100644
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    896,
+/**/
     895,
 /**/
     894,