changeset 12192:6947d5bcf57f v8.0.0976

patch 8.0.0976: cannot send lines to a terminal job commit https://github.com/vim/vim/commit/b241208a13d3e9def36d749b1e824ae694aa85f8 Author: Bram Moolenaar <Bram@vim.org> 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.
author Christian Brabandt <cb@256bit.org>
date Sun, 20 Aug 2017 18:15:04 +0200
parents fee055edaaef
children 5abe784eb500
files runtime/doc/terminal.txt src/ex_cmds.h src/os_unix.c src/terminal.c src/testdir/test_terminal.vim src/version.c
diffstat 6 files changed, 93 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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),
--- 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)
     {
--- 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);
 
--- 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)
--- 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,