summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-09-08 14:39:30 +0200
committerBram Moolenaar <Bram@vim.org>2017-09-08 14:39:30 +0200
commit2dc9d26c14e410c09e538cccfa90da19ae344ba4 (patch)
treea64bfe611511770d918f712be72d9e5c4378ba82
parentba2929b6afd2fc20479912a8dec789be26a38244 (diff)
patch 8.0.1074: ":term NONE" does not work on MS-Windowsv8.0.1074
Problem: ":term NONE" does not work on MS-Windows. Solution: Make it work. Split "pty" into "pty_in" and "pty_out". (Yasuhiro Matsumoto, closes #2058, closes #2045)
-rw-r--r--runtime/doc/eval.txt21
-rw-r--r--src/channel.c43
-rw-r--r--src/evalfunc.c2
-rw-r--r--src/os_unix.c10
-rw-r--r--src/structs.h6
-rw-r--r--src/terminal.c107
-rw-r--r--src/testdir/test_terminal.vim29
-rw-r--r--src/version.c2
8 files changed, 177 insertions, 43 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index f9c6ae3b46..af43bf28fd 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2401,7 +2401,7 @@ term_getscrolled({buf}) Number get the scroll count of a terminal
term_getsize({buf}) List get the size of a terminal
term_getstatus({buf}) String get the status of a terminal
term_gettitle({buf}) String get the title of a terminal
-term_gettty({buf}) String get the tty name of a terminal
+term_getttty({buf}, [{input}]) String get the tty name of a terminal
term_list() List get the list of terminal buffers
term_scrape({buf}, {row}) List get row of a terminal screen
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
@@ -5245,7 +5245,8 @@ job_info({job}) *job_info()*
"status" what |job_status()| returns
"channel" what |job_getchannel()| returns
"process" process ID
- "tty" controlling terminal name, empty when none
+ "tty_in" terminal input name, empty when none
+ "tty_out" terminal output name, empty when none
"exitval" only valid when "status" is "dead"
"exit_cb" function to be called on exit
"stoponexit" |job-stoponexit|
@@ -8092,10 +8093,13 @@ term_gettitle({buf}) *term_gettitle()*
string is returned.
{only available when compiled with the |+terminal| feature}
-term_gettty({buf}) *term_gettty()*
+term_gettty({buf} [, {input}]) *term_gettty()*
Get the name of the controlling terminal associated with
- terminal window {buf}.
- {buf} is used as with |term_getsize()|.
+ terminal window {buf}. {buf} is used as with |term_getsize()|.
+
+ When {input} is omitted or 0, return the name for writing
+ (stdout). When {input} is 1 return the name for reading
+ (stdin). On UNIX, both return same name.
{only available when compiled with the |+terminal| feature}
term_list() *term_list()*
@@ -8173,10 +8177,9 @@ term_start({cmd}, {options}) *term_start()*
specified "botright sbuf %d" is used
"eof_chars" Text to send after all buffer lines were
written to the terminal. When not set
- CTRL-D is used. For Python use CTRL-Z or
- "exit()". For a shell use "exit". A CR
- is always added.
- {only on MS-Windows}
+ CTRL-D is used on MS-Windows. For Python
+ use CTRL-Z or "exit()". For a shell use
+ "exit". A CR is always added.
{only available when compiled with the |+terminal| feature}
diff --git a/src/channel.c b/src/channel.c
index 30a4304d8a..c401df2907 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -969,7 +969,13 @@ ch_close_part(channel_T *channel, ch_part_T part)
if ((part == PART_IN || channel->CH_IN_FD != *fd)
&& (part == PART_OUT || channel->CH_OUT_FD != *fd)
&& (part == PART_ERR || channel->CH_ERR_FD != *fd))
+ {
+#ifdef WIN32
+ if (channel->ch_named_pipe)
+ DisconnectNamedPipe((HANDLE)fd);
+#endif
fd_close(*fd);
+ }
}
*fd = INVALID_FD;
@@ -3086,7 +3092,20 @@ channel_wait(channel_T *channel, sock_T fd, int timeout)
if (r && nread > 0)
return CW_READY;
if (r == 0)
- return CW_ERROR;
+ {
+ DWORD err = GetLastError();
+
+ if (err != ERROR_BAD_PIPE && err != ERROR_BROKEN_PIPE)
+ return CW_ERROR;
+
+ if (channel->ch_named_pipe)
+ {
+ DisconnectNamedPipe((HANDLE)fd);
+ ConnectNamedPipe((HANDLE)fd, NULL);
+ }
+ else
+ return CW_ERROR;
+ }
/* perhaps write some buffer lines */
channel_write_any_lines();
@@ -3670,7 +3689,20 @@ channel_send(
if (part == PART_SOCK)
res = sock_write(fd, (char *)buf, len);
else
+ {
res = fd_write(fd, (char *)buf, len);
+#ifdef WIN32
+ if (channel->ch_named_pipe)
+ {
+ if (res < 0)
+ {
+ DisconnectNamedPipe((HANDLE)fd);
+ ConnectNamedPipe((HANDLE)fd, NULL);
+ }
+ }
+#endif
+
+ }
if (res < 0 && (errno == EWOULDBLOCK
#ifdef EAGAIN
|| errno == EAGAIN
@@ -4849,7 +4881,8 @@ job_free_contents(job_T *job)
}
mch_clear_job(job);
- vim_free(job->jv_tty_name);
+ vim_free(job->jv_tty_in);
+ vim_free(job->jv_tty_out);
vim_free(job->jv_stoponexit);
free_callback(job->jv_exit_cb, job->jv_exit_partial);
}
@@ -5503,8 +5536,10 @@ job_info(job_T *job, dict_T *dict)
nr = job->jv_proc_info.dwProcessId;
#endif
dict_add_nr_str(dict, "process", nr, NULL);
- dict_add_nr_str(dict, "tty", 0L,
- job->jv_tty_name != NULL ? job->jv_tty_name : (char_u *)"");
+ dict_add_nr_str(dict, "tty_in", 0L,
+ job->jv_tty_in != NULL ? job->jv_tty_in : (char_u *)"");
+ dict_add_nr_str(dict, "tty_out", 0L,
+ job->jv_tty_out != NULL ? job->jv_tty_out : (char_u *)"");
dict_add_nr_str(dict, "exitval", job->jv_exitval, NULL);
dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);
diff --git a/src/evalfunc.c b/src/evalfunc.c
index cf9c8d8ec3..a2542e2c5e 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -843,7 +843,7 @@ static struct fst
{"term_getsize", 1, 1, f_term_getsize},
{"term_getstatus", 1, 1, f_term_getstatus},
{"term_gettitle", 1, 1, f_term_gettitle},
- {"term_gettty", 1, 1, f_term_gettty},
+ {"term_gettty", 1, 2, f_term_gettty},
{"term_list", 0, 0, f_term_list},
{"term_scrape", 2, 2, f_term_scrape},
{"term_sendkeys", 2, 2, f_term_sendkeys},
diff --git a/src/os_unix.c b/src/os_unix.c
index 1ec59fcdcf..3366efd1da 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -5263,7 +5263,11 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
&& (!(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);
+ {
+ open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
+ if (job->jv_tty_out != NULL)
+ job->jv_tty_in = vim_strsave(job->jv_tty_out);
+ }
/* TODO: without the channel feature connect the child to /dev/null? */
/* Open pipes for stdin, stdout, stderr. */
@@ -5687,7 +5691,9 @@ mch_create_pty_channel(job_T *job, jobopt_T *options)
int pty_slave_fd = -1;
channel_T *channel;
- open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
+ open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
+ if (job->jv_tty_out != NULL)
+ job->jv_tty_in = vim_strsave(job->jv_tty_out);
close(pty_slave_fd);
channel = add_channel();
diff --git a/src/structs.h b/src/structs.h
index f19377e36a..772b4e7064 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1487,7 +1487,8 @@ struct jobvar_S
PROCESS_INFORMATION jv_proc_info;
HANDLE jv_job_object;
#endif
- char_u *jv_tty_name; /* controlling tty, allocated */
+ char_u *jv_tty_in; /* controlling tty input, allocated */
+ char_u *jv_tty_out; /* controlling tty output, allocated */
jobstatus_T jv_status;
char_u *jv_stoponexit; /* allocated */
int jv_exitval;
@@ -1652,6 +1653,9 @@ struct channel_S {
/* callback for Netbeans when channel is
* closed */
+#ifdef WIN32
+ int ch_named_pipe; /* using named pipe instead of pty */
+#endif
char_u *ch_callback; /* call when any msg is not handled */
partial_T *ch_partial;
char_u *ch_close_cb; /* call when channel is closed */
diff --git a/src/terminal.c b/src/terminal.c
index 3ceb360fbc..9c4e75948c 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -38,8 +38,7 @@
* in tl_scrollback are no longer used.
*
* TODO:
- * - ":term NONE" does not work on MS-Windows.
- * https://github.com/vim/vim/pull/2056
+ * - patch to use GUI or cterm colors for vterm. Yasuhiro, #2067
* - Redirecting output does not work on MS-Windows.
* - implement term_setsize()
* - add test for giving error for invalid 'termsize' value.
@@ -97,7 +96,8 @@ struct terminal_S {
/* used when tl_job is NULL and only a pty was created */
int tl_tty_fd;
- char_u *tl_tty_name;
+ char_u *tl_tty_in;
+ char_u *tl_tty_out;
int tl_normal_mode; /* TRUE: Terminal-Normal mode */
int tl_channel_closed;
@@ -2666,14 +2666,32 @@ f_term_gettty(typval_T *argvars, typval_T *rettv)
{
buf_T *buf = term_get_buf(argvars);
char_u *p;
+ int num = 0;
rettv->v_type = VAR_STRING;
if (buf == NULL)
return;
- if (buf->b_term->tl_job != NULL)
- p = buf->b_term->tl_job->jv_tty_name;
- else
- p = buf->b_term->tl_tty_name;
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ num = get_tv_number(&argvars[1]);
+
+ switch (num)
+ {
+ case 0:
+ if (buf->b_term->tl_job != NULL)
+ p = buf->b_term->tl_job->jv_tty_out;
+ else
+ p = buf->b_term->tl_tty_out;
+ break;
+ case 1:
+ if (buf->b_term->tl_job != NULL)
+ p = buf->b_term->tl_job->jv_tty_in;
+ else
+ p = buf->b_term->tl_tty_in;
+ break;
+ default:
+ EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
+ return;
+ }
if (p != NULL)
rettv->vval.v_string = vim_strsave(p);
}
@@ -3055,7 +3073,6 @@ term_and_job_init(
HANDLE child_thread_handle;
void *winpty_err;
void *spawn_config = NULL;
- char buf[MAX_PATH];
garray_T ga;
char_u *cmd;
@@ -3094,7 +3111,6 @@ term_and_job_init(
if (term->tl_winpty == NULL)
goto failed;
- /* TODO: if the command is "NONE" only create a pty. */
spawn_config = winpty_spawn_config_new(
WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN |
WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN,
@@ -3162,9 +3178,10 @@ term_and_job_init(
job->jv_proc_info.dwProcessId = GetProcessId(child_process_handle);
job->jv_job_object = jo;
job->jv_status = JOB_STARTED;
- sprintf(buf, "winpty://%lu",
- GetProcessId(winpty_agent_process(term->tl_winpty)));
- job->jv_tty_name = vim_strsave((char_u*)buf);
+ job->jv_tty_in = utf16_to_enc(
+ (short_u*)winpty_conin_name(term->tl_winpty), NULL);
+ job->jv_tty_out = utf16_to_enc(
+ (short_u*)winpty_conout_name(term->tl_winpty), NULL);
++job->jv_refcount;
term->tl_job = job;
@@ -3205,9 +3222,68 @@ failed:
}
static int
-create_pty_only(term_T *term, jobopt_T *opt)
+create_pty_only(term_T *term, jobopt_T *options)
{
- /* TODO: implement this */
+ HANDLE hPipeIn = INVALID_HANDLE_VALUE;
+ HANDLE hPipeOut = INVALID_HANDLE_VALUE;
+ char in_name[80], out_name[80];
+ channel_T *channel = NULL;
+
+ create_vterm(term, term->tl_rows, term->tl_cols);
+
+ vim_snprintf(in_name, sizeof(in_name), "\\\\.\\pipe\\vim-%d-in-%d",
+ GetCurrentProcessId(),
+ curbuf->b_fnum);
+ hPipeIn = CreateNamedPipe(in_name, PIPE_ACCESS_OUTBOUND,
+ PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ 0, 0, NMPWAIT_NOWAIT, NULL);
+ if (hPipeIn == INVALID_HANDLE_VALUE)
+ goto failed;
+
+ vim_snprintf(out_name, sizeof(out_name), "\\\\.\\pipe\\vim-%d-out-%d",
+ GetCurrentProcessId(),
+ curbuf->b_fnum);
+ hPipeOut = CreateNamedPipe(out_name, PIPE_ACCESS_INBOUND,
+ PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ 0, 0, 0, NULL);
+ if (hPipeOut == INVALID_HANDLE_VALUE)
+ goto failed;
+
+ ConnectNamedPipe(hPipeIn, NULL);
+ ConnectNamedPipe(hPipeOut, NULL);
+
+ term->tl_job = job_alloc();
+ if (term->tl_job == NULL)
+ goto failed;
+ ++term->tl_job->jv_refcount;
+
+ /* behave like the job is already finished */
+ term->tl_job->jv_status = JOB_FINISHED;
+
+ channel = add_channel();
+ if (channel == NULL)
+ goto failed;
+ term->tl_job->jv_channel = channel;
+ channel->ch_keep_open = TRUE;
+ channel->ch_named_pipe = TRUE;
+
+ channel_set_pipes(channel,
+ (sock_T)hPipeIn,
+ (sock_T)hPipeOut,
+ (sock_T)hPipeOut);
+ channel_set_job(channel, term->tl_job, options);
+ term->tl_job->jv_tty_in = vim_strsave((char_u*)in_name);
+ term->tl_job->jv_tty_out = vim_strsave((char_u*)out_name);
+
+ return OK;
+
+failed:
+ if (hPipeIn != NULL)
+ CloseHandle(hPipeIn);
+ if (hPipeOut != NULL)
+ CloseHandle(hPipeOut);
return FAIL;
}
@@ -3234,7 +3310,8 @@ term_free_vterm(term_T *term)
static void
term_report_winsize(term_T *term, int rows, int cols)
{
- winpty_set_size(term->tl_winpty, cols, rows, NULL);
+ if (term->tl_winpty)
+ winpty_set_size(term->tl_winpty, cols, rows, NULL);
}
int
diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim
index 800567920d..efc491d92b 100644
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -36,11 +36,11 @@ endfunc
func Test_terminal_basic()
let buf = Run_shell_in_terminal({})
if has("unix")
- call assert_match("^/dev/", job_info(g:job).tty)
- call assert_match("^/dev/", term_gettty(''))
+ call assert_match('^/dev/', job_info(g:job).tty_out)
+ call assert_match('^/dev/', term_gettty(''))
else
- call assert_match("^winpty://", job_info(g:job).tty)
- call assert_match("^winpty://", term_gettty(''))
+ call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out)
+ call assert_match('^\\\\.\\pipe\\', term_gettty(''))
endif
call assert_equal('t', mode())
call assert_match('%aR[^\n]*running]', execute('ls'))
@@ -539,10 +539,6 @@ func Test_terminal_write_stdin()
endfunc
func Test_terminal_no_cmd()
- " Todo: make this work on all systems.
- if !has('unix')
- return
- endif
" Todo: make this work in the GUI
if !has('gui_running')
return
@@ -550,11 +546,20 @@ func Test_terminal_no_cmd()
let buf = term_start('NONE', {})
call assert_notequal(0, buf)
- let pty = job_info(term_getjob(buf))['tty']
+ let pty = job_info(term_getjob(buf))['tty_out']
call assert_notequal('', pty)
- call system('echo "look here" > ' . pty)
+ if has('win32')
+ silent exe '!cmd /c "echo look here > ' . pty . '"'
+ else
+ call system('echo "look here" > ' . pty)
+ endif
call term_wait(buf)
- call assert_equal('look here', term_getline(buf, 1))
+
+ let result = term_getline(buf, 1)
+ if has('win32')
+ let result = substitute(result, '\s\+$', '', '')
+ endif
+ call assert_equal('look here', result)
bwipe!
endfunc
@@ -600,6 +605,7 @@ func Test_terminal_redir_file()
call WaitFor('len(readfile("Xfile")) > 0')
call assert_match('123', readfile('Xfile')[0])
call delete('Xfile')
+ bwipe
endif
if has('unix')
@@ -608,6 +614,7 @@ func Test_terminal_redir_file()
call WaitFor('len(readfile("Xfile")) > 0')
call assert_match('executing job failed', readfile('Xfile')[0])
call delete('Xfile')
+ bwipe
call writefile(['one line'], 'Xfile')
let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
diff --git a/src/version.c b/src/version.c
index 9ec37eb667..2ab1b17d3b 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 */
/**/
+ 1074,
+/**/
1073,
/**/
1072,