diff options
author | Bram Moolenaar <Bram@vim.org> | 2017-09-08 14:39:30 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2017-09-08 14:39:30 +0200 |
commit | 2dc9d26c14e410c09e538cccfa90da19ae344ba4 (patch) | |
tree | a64bfe611511770d918f712be72d9e5c4378ba82 /src | |
parent | ba2929b6afd2fc20479912a8dec789be26a38244 (diff) | |
download | vim-git-2dc9d26c14e410c09e538cccfa90da19ae344ba4.tar.gz |
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)
Diffstat (limited to 'src')
-rw-r--r-- | src/channel.c | 43 | ||||
-rw-r--r-- | src/evalfunc.c | 2 | ||||
-rw-r--r-- | src/os_unix.c | 10 | ||||
-rw-r--r-- | src/structs.h | 6 | ||||
-rw-r--r-- | src/terminal.c | 107 | ||||
-rw-r--r-- | src/testdir/test_terminal.vim | 29 | ||||
-rw-r--r-- | src/version.c | 2 |
7 files changed, 165 insertions, 34 deletions
diff --git a/src/channel.c b/src/channel.c index 30a4304d8..c401df290 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 cf9c8d8ec..a2542e2c5 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 1ec59fcdc..3366efd1d 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 f19377e36..772b4e706 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 3ceb360fb..9c4e75948 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 800567920..efc491d92 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 9ec37eb66..2ab1b17d3 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, |