summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-09-08 20:47:00 +0200
committerBram Moolenaar <Bram@vim.org>2017-09-08 20:47:00 +0200
commit3c518400d1a51929572dd9fcf77dba94d78d7545 (patch)
treed87d536f1d0c3621ed013f0cf2b1b9ffe18b3ee1
parent1a735d6c9bf4204492b9f9aeba280737fab46ed3 (diff)
downloadvim-git-3c518400d1a51929572dd9fcf77dba94d78d7545.tar.gz
patch 8.0.1076: term_start() does not take callbacksv8.0.1076
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.
-rw-r--r--src/channel.c11
-rw-r--r--src/proto/terminal.pro3
-rw-r--r--src/terminal.c56
-rw-r--r--src/version.c2
4 files changed, 48 insertions, 24 deletions
diff --git a/src/channel.c b/src/channel.c
index c401df290..dfb8ac989 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -3692,13 +3692,10 @@ channel_send(
{
res = fd_write(fd, (char *)buf, len);
#ifdef WIN32
- if (channel->ch_named_pipe)
+ if (channel->ch_named_pipe && res < 0)
{
- if (res < 0)
- {
- DisconnectNamedPipe((HANDLE)fd);
- ConnectNamedPipe((HANDLE)fd, NULL);
- }
+ DisconnectNamedPipe((HANDLE)fd);
+ ConnectNamedPipe((HANDLE)fd, NULL);
}
#endif
@@ -4084,6 +4081,7 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
if (ret > 0 && fd != INVALID_FD && FD_ISSET(fd, rfds))
{
channel_read(channel, part, "channel_select_check");
+ FD_CLR(fd, rfds);
--ret;
}
}
@@ -4093,6 +4091,7 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
&& FD_ISSET(in_part->ch_fd, wfds))
{
channel_write_input(channel);
+ FD_CLR(in_part->ch_fd, wfds);
--ret;
}
}
diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro
index 3811ba7a5..639318d51 100644
--- a/src/proto/terminal.pro
+++ b/src/proto/terminal.pro
@@ -3,6 +3,7 @@ void ex_terminal(exarg_T *eap);
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);
@@ -16,7 +17,6 @@ int term_update_window(win_T *wp);
int term_is_finished(buf_T *buf);
int term_show_buffer(buf_T *buf);
void term_change_in_curbuf(void);
-void term_send_eof(channel_T *ch);
int term_get_attr(buf_T *buf, linenr_T lnum, int col);
char_u *term_get_status_text(term_T *term);
int set_ref_in_term(int copyID);
@@ -35,5 +35,6 @@ void f_term_scrape(typval_T *argvars, typval_T *rettv);
void f_term_sendkeys(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);
int terminal_enabled(void);
/* vim: set ft=c : */
diff --git a/src/terminal.c b/src/terminal.c
index eddca8ee7..c4313eeab 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -245,7 +245,11 @@ setup_job_options(jobopt_T *opt, int rows, int cols)
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 *opt, int forceit)
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 *opt, int forceit)
|| (!(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 *opt, int forceit)
{
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 *opt, int forceit)
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 *opt, int forceit)
{
/* split failed */
vim_free(term);
- return;
+ return NULL;
}
}
term->tl_buffer = curbuf;
@@ -419,6 +424,7 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
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 *opt, int forceit)
/* 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, channel_T *channel)
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, typval_T *rettv)
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 *rettv)
if (opt.jo_vertical)
cmdmod.split = WSP_VERT;
- term_start(&argvars[0], &opt, FALSE);
+ buf = term_start(&argvars[0], &opt, FALSE);
- if (curbuf->b_term != NULL)
- rettv->vval.v_number = curbuf->b_fnum;
+ 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 *opt)
/* 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);
}
/*
diff --git a/src/version.c b/src/version.c
index f8a10e3f9..ad59f5e63 100644
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1076,
+/**/
1075,
/**/
1074,