patch 8.0.0761: options not set properly for a terminal buffer

Problem:    Options of a buffer for a terminal window are not set properly.
Solution:   Add "terminal" value for 'buftype'.  Make 'buftype' and
            'bufhidden' not depend on the quickfix feature.
            Also set the buffer name and show "running" or "finished" in the
            window title.
diff --git a/src/terminal.c b/src/terminal.c
index 3f1a91d..f5a9fd1 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -33,9 +33,8 @@
  * while, if the terminal window is visible, the screen contents is drawn.
  *
  * TODO:
- * - cursor flickers when moving the cursor
- * - set buffer options to be scratch, hidden, nomodifiable, etc.
- * - set buffer name to command, add (1) to avoid duplicates.
+ * - do not store terminal buffer in viminfo
+ * - put terminal title in the statusline
  * - Add a scrollback buffer (contains lines to scroll off the top).
  *   Can use the buf_T lines, store attributes somewhere else?
  * - When the job ends:
@@ -53,7 +52,6 @@
  * - support minimal size when 'termsize' is empty?
  * - implement "term" for job_start(): more job options when starting a
  *   terminal.
- * - implement ":buf {term-buf-name}"
  * - implement term_list()			list of buffers with a terminal
  * - implement term_getsize(buf)
  * - implement term_setsize(buf)
@@ -192,7 +190,31 @@
     term->tl_next = first_term;
     first_term = term;
 
-    /* TODO: set buffer type, hidden, etc. */
+    if (buflist_findname(cmd) == NULL)
+	curbuf->b_ffname = vim_strsave(cmd);
+    else
+    {
+	int	i;
+	size_t	len = STRLEN(cmd) + 10;
+	char_u	*p = alloc(len);
+
+	for (i = 1; p != NULL; ++i)
+	{
+	    vim_snprintf((char *)p, len, "%s (%d)", cmd, i);
+	    if (buflist_findname(p) == NULL)
+	    {
+		curbuf->b_ffname = p;
+		break;
+	    }
+	}
+    }
+    curbuf->b_fname = curbuf->b_ffname;
+
+    /* Mark the buffer as changed, so that it's not easy to abandon the job. */
+    curbuf->b_changed = TRUE;
+    curbuf->b_p_ma = FALSE;
+    set_string_option_direct((char_u *)"buftype", -1,
+				  (char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0);
 
     set_term_and_win_size(term);
 
@@ -490,6 +512,26 @@
     }
 }
 
+/*
+ * Called when a job has finished.
+ */
+    void
+term_job_ended(job_T *job)
+{
+    if (curbuf->b_term != NULL && curbuf->b_term->tl_job == job)
+	maketitle();
+}
+
+/*
+ * Return TRUE if the job for "buf" is still running.
+ */
+    int
+term_job_running(buf_T *buf)
+{
+    return buf->b_term != NULL && buf->b_term->tl_job != NULL
+	&& buf->b_term->tl_job->jv_status == JOB_STARTED;
+}
+
     static void
 position_cursor(win_T *wp, VTermPos *pos)
 {
@@ -850,13 +892,20 @@
     opt->jo_out_mode = MODE_RAW;
     opt->jo_err_mode = MODE_RAW;
     opt->jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE;
+
     opt->jo_io[PART_OUT] = JIO_BUFFER;
     opt->jo_io[PART_ERR] = JIO_BUFFER;
-    opt->jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT));
+    opt->jo_set |= JO_OUT_IO + JO_ERR_IO;
+
+    opt->jo_modifiable[PART_OUT] = 0;
+    opt->jo_modifiable[PART_ERR] = 0;
+    opt->jo_set |= JO_OUT_MODIFIABLE + JO_ERR_MODIFIABLE;
+
     opt->jo_io_buf[PART_OUT] = curbuf->b_fnum;
     opt->jo_io_buf[PART_ERR] = curbuf->b_fnum;
     opt->jo_pty = TRUE;
-    opt->jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT));
+    opt->jo_set |= JO_OUT_BUF + JO_ERR_BUF;
+
     opt->jo_term_rows = rows;
     opt->jo_term_cols = cols;
 }