diff options
author | Bram Moolenaar <Bram@vim.org> | 2017-09-08 20:47:00 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2017-09-08 20:47:00 +0200 |
commit | 3c518400d1a51929572dd9fcf77dba94d78d7545 (patch) | |
tree | d87d536f1d0c3621ed013f0cf2b1b9ffe18b3ee1 | |
parent | 1a735d6c9bf4204492b9f9aeba280737fab46ed3 (diff) | |
download | vim-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.c | 11 | ||||
-rw-r--r-- | src/proto/terminal.pro | 3 | ||||
-rw-r--r-- | src/terminal.c | 56 | ||||
-rw-r--r-- | src/version.c | 2 |
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, |