diff src/terminal.c @ 12393:128cd982c7b8 v8.0.1076

patch 8.0.1076: term_start() does not take callbacks commit https://github.com/vim/vim/commit/3c518400d1a51929572dd9fcf77dba94d78d7545 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Sep 8 20:47:00 2017 +0200 patch 8.0.1076: term_start() does not take callbacks Problem: term_start() does not take callbacks. When using two terminals without a job only one is read from. A terminal without a window returns the wrong pty. Solution: Support "callback", "out_cb" and "err_cb". Fix terminal without a window. Fix reading from multiple channels.
author Christian Brabandt <cb@256bit.org>
date Fri, 08 Sep 2017 21:00:04 +0200
parents 438c64b76eef
children eb8d5c4936f1
line wrap: on
line diff
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -245,7 +245,11 @@ setup_job_options(jobopt_T *opt, int row
 	opt->jo_term_cols = cols;
 }
 
-    static void
+/*
+ * Start a terminal window and return its buffer.
+ * Returns NULL when failed.
+ */
+    static buf_T *
 term_start(typval_T *argvar, jobopt_T *opt, int forceit)
 {
     exarg_T	split_ea;
@@ -253,9 +257,10 @@ term_start(typval_T *argvar, jobopt_T *o
     term_T	*term;
     buf_T	*old_curbuf = NULL;
     int		res;
+    buf_T	*newbuf;
 
     if (check_restricted() || check_secure())
-	return;
+	return NULL;
 
     if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO))
 					 == (JO_IN_IO + JO_OUT_IO + JO_ERR_IO)
@@ -263,12 +268,12 @@ term_start(typval_T *argvar, jobopt_T *o
 	|| (!(opt->jo_set & JO_ERR_IO) && (opt->jo_set & JO_ERR_BUF)))
     {
 	EMSG(_(e_invarg));
-	return;
+	return NULL;
     }
 
     term = (term_T *)alloc_clear(sizeof(term_T));
     if (term == NULL)
-	return;
+	return NULL;
     term->tl_dirty_row_end = MAX_ROW;
     term->tl_cursor_visible = TRUE;
     term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK;
@@ -283,13 +288,13 @@ term_start(typval_T *argvar, jobopt_T *o
 	{
 	    no_write_message();
 	    vim_free(term);
-	    return;
+	    return NULL;
 	}
 	if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE,
 		     ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
 	{
 	    vim_free(term);
-	    return;
+	    return NULL;
 	}
     }
     else if (opt->jo_hidden)
@@ -303,7 +308,7 @@ term_start(typval_T *argvar, jobopt_T *o
 	if (buf == NULL || ml_open(buf) == FAIL)
 	{
 	    vim_free(term);
-	    return;
+	    return NULL;
 	}
 	old_curbuf = curbuf;
 	--curbuf->b_nwindows;
@@ -333,7 +338,7 @@ term_start(typval_T *argvar, jobopt_T *o
 	{
 	    /* split failed */
 	    vim_free(term);
-	    return;
+	    return NULL;
 	}
     }
     term->tl_buffer = curbuf;
@@ -419,6 +424,7 @@ term_start(typval_T *argvar, jobopt_T *o
     else
 	res = term_and_job_init(term, argvar, opt);
 
+    newbuf = curbuf;
     if (res == OK)
     {
 	/* Get and remember the size we ended up with.  Update the pty. */
@@ -453,7 +459,9 @@ term_start(typval_T *argvar, jobopt_T *o
 	/* Wiping out the buffer will also close the window and call
 	 * free_terminal(). */
 	do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
+	return NULL;
     }
+    return newbuf;
 }
 
 /*
@@ -688,7 +696,7 @@ write_to_term(buf_T *buffer, char_u *msg
 	    update_screen(0);
 	    update_cursor(term, TRUE);
 	}
-	else
+	else if (buffer->b_nwindows > 0)
 	    redraw_after_callback(TRUE);
     }
 }
@@ -879,6 +887,20 @@ term_job_running(term_T *term)
 }
 
 /*
+ * Return TRUE if "term" has an active channel and used ":term NONE".
+ */
+    int
+term_none_open(term_T *term)
+{
+    /* Also consider the job finished when the channel is closed, to avoid a
+     * race condition when updating the title. */
+    return term != NULL
+	&& term->tl_job != NULL
+	&& channel_is_open(term->tl_job->jv_channel)
+	&& term->tl_job->jv_channel->ch_keep_open;
+}
+
+/*
  * Add the last line of the scrollback buffer to the buffer in the window.
  */
     static void
@@ -2379,6 +2401,8 @@ term_get_status_text(term_T *term)
 	}
 	else if (term->tl_title != NULL)
 	    txt = term->tl_title;
+	else if (term_none_open(term))
+	    txt = (char_u *)_("active");
 	else if (term_job_running(term))
 	    txt = (char_u *)_("running");
 	else
@@ -2858,11 +2882,13 @@ f_term_sendkeys(typval_T *argvars, typva
 f_term_start(typval_T *argvars, typval_T *rettv)
 {
     jobopt_T	opt;
+    buf_T	*buf;
 
     init_job_options(&opt);
     if (argvars[1].v_type != VAR_UNKNOWN
 	    && get_job_options(&argvars[1], &opt,
 		JO_TIMEOUT_ALL + JO_STOPONEXIT
+		    + JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK
 		    + JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO,
 		JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
 		    + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
@@ -2871,10 +2897,10 @@ f_term_start(typval_T *argvars, typval_T
 
     if (opt.jo_vertical)
 	cmdmod.split = WSP_VERT;
-    term_start(&argvars[0], &opt, FALSE);
-
-    if (curbuf->b_term != NULL)
-	rettv->vval.v_number = curbuf->b_fnum;
+    buf = term_start(&argvars[0], &opt, FALSE);
+
+    if (buf != NULL && buf->b_term != NULL)
+	rettv->vval.v_number = buf->b_fnum;
 }
 
 /*
@@ -3359,8 +3385,6 @@ term_and_job_init(
     static int
 create_pty_only(term_T *term, jobopt_T *opt)
 {
-    int ret;
-
     create_vterm(term, term->tl_rows, term->tl_cols);
 
     term->tl_job = job_alloc();
@@ -3371,9 +3395,7 @@ create_pty_only(term_T *term, jobopt_T *
     /* behave like the job is already finished */
     term->tl_job->jv_status = JOB_FINISHED;
 
-    ret = mch_create_pty_channel(term->tl_job, opt);
-
-    return ret;
+    return mch_create_pty_channel(term->tl_job, opt);
 }
 
 /*