# HG changeset patch # User Christian Brabandt # Date 1503245704 -7200 # Node ID 6947d5bcf57ff9bae4b2b83eebb2c3784b60dcb6 # Parent fee055edaaef4da6070e442f280f4256509e5ad2 patch 8.0.0976: cannot send lines to a terminal job commit https://github.com/vim/vim/commit/b241208a13d3e9def36d749b1e824ae694aa85f8 Author: Bram Moolenaar Date: Sun Aug 20 18:09:14 2017 +0200 patch 8.0.0976: cannot send lines to a terminal job Problem: Cannot send lines to a terminal job. Solution: Make [range]terminal send selected lines to the job. Use ++rows and ++cols for the terminal size. diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -1,4 +1,4 @@ -*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 12 +*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 20 VIM REFERENCE MANUAL by Bram Moolenaar @@ -102,10 +102,9 @@ Syntax ~ parentheses. E.g. if "gdb" exists the second terminal buffer will use "!gdb (1)". - If [range] is given it is used for the terminal size. - One number specifies the number of rows. Unless the - "vertical" modifier is used, then it is the number of - columns. + If [range] is given the specified lines are used as + input for the job. It will not be possible to type + keys in the terminal window. Two comma separated numbers are used as "rows,cols". E.g. `:24,80gdb` opens a terminal with 24 rows and 80 @@ -125,6 +124,10 @@ Syntax ~ cannot be |abandon|ed. ++hidden Open the terminal in a hidden buffer, no window will be used. + ++rows={height} Use {height} for the terminal window + height. + ++cols={width} Use {width} for the terminal window + width. If you want to use more options use the |term_start()| function. diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1484,8 +1484,8 @@ EX(CMD_tearoff, "tearoff", ex_tearoff, NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN, ADDR_LINES), EX(CMD_terminal, "terminal", ex_terminal, - RANGE|NOTADR|BANG|FILES|TRLBAR|CMDWIN, - ADDR_OTHER), + RANGE|BANG|FILES|TRLBAR|CMDWIN, + ADDR_LINES), EX(CMD_tfirst, "tfirst", ex_tag, RANGE|NOTADR|BANG|TRLBAR|ZEROR, ADDR_LINES), diff --git a/src/os_unix.c b/src/os_unix.c --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5238,6 +5238,7 @@ mch_job_start(char **argv, job_T *job, j int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE; int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE; int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE; + int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER; int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT; SIGSET_DECL(curset) @@ -5247,7 +5248,10 @@ mch_job_start(char **argv, job_T *job, j /* default is to fail */ job->jv_status = JOB_FAILED; - if (options->jo_pty) + if (options->jo_pty + && (!(use_file_for_in || use_null_for_in) + || !(use_file_for_in || use_null_for_out) + || !(use_out_for_err || use_file_for_err || use_null_for_err))) open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name); /* TODO: without the channel feature connect the child to /dev/null? */ @@ -5263,8 +5267,12 @@ mch_job_start(char **argv, job_T *job, j goto failed; } } - else if (!use_null_for_in && pty_master_fd < 0 && pipe(fd_in) < 0) - goto failed; + else + /* When writing buffer lines to the input don't use the pty, so that + * the pipe can be closed when all lines were written. */ + if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in) + && pipe(fd_in) < 0) + goto failed; if (use_file_for_out) { diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -38,7 +38,7 @@ * in tl_scrollback are no longer used. * * TODO: - * - make [range]terminal pipe [range] lines to the terminal + * - test writing lines to terminal job when implemented for MS-Windows * - implement term_setsize() * - add test for giving error for invalid 'termsize' value. * - support minimal size when 'termsize' is "rows*cols". @@ -447,10 +447,14 @@ ex_terminal(exarg_T *eap) cmd = eap->arg; while (*cmd && *cmd == '+' && *(cmd + 1) == '+') { - char_u *p; + char_u *p, *ep; cmd += 2; p = skiptowhite(cmd); + ep = vim_strchr(cmd, '='); + if (ep != NULL && ep < p) + p = ep; + 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) @@ -459,6 +463,20 @@ ex_terminal(exarg_T *eap) opt.jo_curwin = 1; else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0) opt.jo_hidden = 1; + else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0 + && ep != NULL && isdigit(ep[1])) + { + opt.jo_set2 |= JO2_TERM_ROWS; + opt.jo_term_rows = atoi((char *)ep + 1); + p = skiptowhite(cmd); + } + else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "cols", 4) == 0 + && ep != NULL && isdigit(ep[1])) + { + opt.jo_set2 |= JO2_TERM_COLS; + opt.jo_term_cols = atoi((char *)ep + 1); + p = skiptowhite(cmd); + } else { if (*p) @@ -472,17 +490,14 @@ ex_terminal(exarg_T *eap) /* Make a copy, an autocommand may set 'shell'. */ tofree = cmd = vim_strsave(p_sh); - if (eap->addr_count == 2) + if (eap->addr_count > 0) { - opt.jo_term_rows = eap->line1; - opt.jo_term_cols = eap->line2; - } - else if (eap->addr_count == 1) - { - if (cmdmod.split & WSP_VERT) - opt.jo_term_cols = eap->line2; - else - opt.jo_term_rows = eap->line2; + /* Write lines from current buffer to the job. */ + opt.jo_set |= JO_IN_IO | JO_IN_BUF | JO_IN_TOP | JO_IN_BOT; + opt.jo_io[PART_IN] = JIO_BUFFER; + opt.jo_io_buf[PART_IN] = curbuf->b_fnum; + opt.jo_in_top = eap->line1; + opt.jo_in_bot = eap->line2; } argvar.v_type = VAR_STRING; @@ -1078,6 +1093,29 @@ term_vgetc() } /* + * Get the part that is connected to the tty. Normally this is PART_IN, but + * when writing buffer lines to the job it can be another. This makes it + * possible to do "1,5term vim -". + */ + static ch_part_T +get_tty_part(term_T *term) +{ +#ifdef UNIX + ch_part_T parts[3] = {PART_IN, PART_OUT, PART_ERR}; + int i; + + for (i = 0; i < 3; ++i) + { + int fd = term->tl_job->jv_channel->ch_part[parts[i]].ch_fd; + + if (isatty(fd)) + return parts[i]; + } +#endif + return PART_IN; +} + +/* * Send keys to terminal. * Return FAIL when the key needs to be handled in Normal mode. * Return OK when the key was dropped or sent to the terminal. @@ -1148,8 +1186,8 @@ send_keys_to_term(term_T *term, int c, i len = term_convert_key(term, c, msg); if (len > 0) /* TODO: if FAIL is returned, stop? */ - channel_send(term->tl_job->jv_channel, PART_IN, - (char_u *)msg, (int)len, NULL); + channel_send(term->tl_job->jv_channel, get_tty_part(term), + (char_u *)msg, (int)len, NULL); return OK; } @@ -1332,7 +1370,8 @@ terminal_loop(void) #ifdef UNIX { - int fd = curbuf->b_term->tl_job->jv_channel->ch_part[PART_IN].ch_fd; + int part = get_tty_part(curbuf->b_term); + int fd = curbuf->b_term->tl_job->jv_channel->ch_part[part].ch_fd; if (isatty(fd)) { @@ -2823,7 +2862,12 @@ dyn_winpty_init(int verbose) * Return OK or FAIL. */ static int -term_and_job_init(term_T *term, int rows, int cols, typval_T *argvar, jobopt_T *opt) +term_and_job_init( + term_T *term, + int rows, + int cols, + typval_T *argvar, + jobopt_T *opt) { WCHAR *p = NULL; channel_T *channel = NULL; @@ -3020,7 +3064,12 @@ terminal_enabled(void) * Return OK or FAIL. */ static int -term_and_job_init(term_T *term, int rows, int cols, typval_T *argvar, jobopt_T *opt) +term_and_job_init( + term_T *term, + int rows, + int cols, + typval_T *argvar, + jobopt_T *opt) { create_vterm(term, rows, cols); diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -251,7 +251,7 @@ endfunc func Test_terminal_size() let cmd = Get_cat_123_cmd() - exe '5terminal ' . cmd + exe 'terminal ++rows=5 ' . cmd let size = term_getsize('') bwipe! call assert_equal(5, size[0]) @@ -262,7 +262,7 @@ func Test_terminal_size() call assert_equal(6, size[0]) vsplit - exe '5,33terminal ' . cmd + exe 'terminal ++rows=5 ++cols=33 ' . cmd let size = term_getsize('') bwipe! call assert_equal([5, 33], size) @@ -272,7 +272,7 @@ func Test_terminal_size() bwipe! call assert_equal([6, 36], size) - exe 'vertical 20terminal ' . cmd + exe 'vertical terminal ++cols=20 ' . cmd let size = term_getsize('') bwipe! call assert_equal(20, size[1]) @@ -283,7 +283,7 @@ func Test_terminal_size() call assert_equal(26, size[1]) split - exe 'vertical 6,20terminal ' . cmd + exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd let size = term_getsize('') bwipe! call assert_equal([6, 20], size) diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 976, +/**/ 975, /**/ 974,