Skip to content

Commit 2dc9d26

Browse files
committed
patch 8.0.1074: ":term NONE" does not work on MS-Windows
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)
1 parent ba2929b commit 2dc9d26

8 files changed

Lines changed: 177 additions & 43 deletions

File tree

runtime/doc/eval.txt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,7 +2401,7 @@ term_getscrolled({buf}) Number get the scroll count of a terminal
24012401
term_getsize({buf}) List get the size of a terminal
24022402
term_getstatus({buf}) String get the status of a terminal
24032403
term_gettitle({buf}) String get the title of a terminal
2404-
term_gettty({buf}) String get the tty name of a terminal
2404+
term_getttty({buf}, [{input}]) String get the tty name of a terminal
24052405
term_list() List get the list of terminal buffers
24062406
term_scrape({buf}, {row}) List get row of a terminal screen
24072407
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
@@ -5245,7 +5245,8 @@ job_info({job}) *job_info()*
52455245
"status" what |job_status()| returns
52465246
"channel" what |job_getchannel()| returns
52475247
"process" process ID
5248-
"tty" controlling terminal name, empty when none
5248+
"tty_in" terminal input name, empty when none
5249+
"tty_out" terminal output name, empty when none
52495250
"exitval" only valid when "status" is "dead"
52505251
"exit_cb" function to be called on exit
52515252
"stoponexit" |job-stoponexit|
@@ -8092,10 +8093,13 @@ term_gettitle({buf}) *term_gettitle()*
80928093
string is returned.
80938094
{only available when compiled with the |+terminal| feature}
80948095

8095-
term_gettty({buf}) *term_gettty()*
8096+
term_gettty({buf} [, {input}]) *term_gettty()*
80968097
Get the name of the controlling terminal associated with
8097-
terminal window {buf}.
8098-
{buf} is used as with |term_getsize()|.
8098+
terminal window {buf}. {buf} is used as with |term_getsize()|.
8099+
8100+
When {input} is omitted or 0, return the name for writing
8101+
(stdout). When {input} is 1 return the name for reading
8102+
(stdin). On UNIX, both return same name.
80998103
{only available when compiled with the |+terminal| feature}
81008104

81018105
term_list() *term_list()*
@@ -8173,10 +8177,9 @@ term_start({cmd}, {options}) *term_start()*
81738177
specified "botright sbuf %d" is used
81748178
"eof_chars" Text to send after all buffer lines were
81758179
written to the terminal. When not set
8176-
CTRL-D is used. For Python use CTRL-Z or
8177-
"exit()". For a shell use "exit". A CR
8178-
is always added.
8179-
{only on MS-Windows}
8180+
CTRL-D is used on MS-Windows. For Python
8181+
use CTRL-Z or "exit()". For a shell use
8182+
"exit". A CR is always added.
81808183

81818184
{only available when compiled with the |+terminal| feature}
81828185

src/channel.c

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,13 @@ ch_close_part(channel_T *channel, ch_part_T part)
969969
if ((part == PART_IN || channel->CH_IN_FD != *fd)
970970
&& (part == PART_OUT || channel->CH_OUT_FD != *fd)
971971
&& (part == PART_ERR || channel->CH_ERR_FD != *fd))
972+
{
973+
#ifdef WIN32
974+
if (channel->ch_named_pipe)
975+
DisconnectNamedPipe((HANDLE)fd);
976+
#endif
972977
fd_close(*fd);
978+
}
973979
}
974980
*fd = INVALID_FD;
975981

@@ -3086,7 +3092,20 @@ channel_wait(channel_T *channel, sock_T fd, int timeout)
30863092
if (r && nread > 0)
30873093
return CW_READY;
30883094
if (r == 0)
3089-
return CW_ERROR;
3095+
{
3096+
DWORD err = GetLastError();
3097+
3098+
if (err != ERROR_BAD_PIPE && err != ERROR_BROKEN_PIPE)
3099+
return CW_ERROR;
3100+
3101+
if (channel->ch_named_pipe)
3102+
{
3103+
DisconnectNamedPipe((HANDLE)fd);
3104+
ConnectNamedPipe((HANDLE)fd, NULL);
3105+
}
3106+
else
3107+
return CW_ERROR;
3108+
}
30903109

30913110
/* perhaps write some buffer lines */
30923111
channel_write_any_lines();
@@ -3670,7 +3689,20 @@ channel_send(
36703689
if (part == PART_SOCK)
36713690
res = sock_write(fd, (char *)buf, len);
36723691
else
3692+
{
36733693
res = fd_write(fd, (char *)buf, len);
3694+
#ifdef WIN32
3695+
if (channel->ch_named_pipe)
3696+
{
3697+
if (res < 0)
3698+
{
3699+
DisconnectNamedPipe((HANDLE)fd);
3700+
ConnectNamedPipe((HANDLE)fd, NULL);
3701+
}
3702+
}
3703+
#endif
3704+
3705+
}
36743706
if (res < 0 && (errno == EWOULDBLOCK
36753707
#ifdef EAGAIN
36763708
|| errno == EAGAIN
@@ -4849,7 +4881,8 @@ job_free_contents(job_T *job)
48494881
}
48504882
mch_clear_job(job);
48514883

4852-
vim_free(job->jv_tty_name);
4884+
vim_free(job->jv_tty_in);
4885+
vim_free(job->jv_tty_out);
48534886
vim_free(job->jv_stoponexit);
48544887
free_callback(job->jv_exit_cb, job->jv_exit_partial);
48554888
}
@@ -5503,8 +5536,10 @@ job_info(job_T *job, dict_T *dict)
55035536
nr = job->jv_proc_info.dwProcessId;
55045537
#endif
55055538
dict_add_nr_str(dict, "process", nr, NULL);
5506-
dict_add_nr_str(dict, "tty", 0L,
5507-
job->jv_tty_name != NULL ? job->jv_tty_name : (char_u *)"");
5539+
dict_add_nr_str(dict, "tty_in", 0L,
5540+
job->jv_tty_in != NULL ? job->jv_tty_in : (char_u *)"");
5541+
dict_add_nr_str(dict, "tty_out", 0L,
5542+
job->jv_tty_out != NULL ? job->jv_tty_out : (char_u *)"");
55085543

55095544
dict_add_nr_str(dict, "exitval", job->jv_exitval, NULL);
55105545
dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);

src/evalfunc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ static struct fst
843843
{"term_getsize", 1, 1, f_term_getsize},
844844
{"term_getstatus", 1, 1, f_term_getstatus},
845845
{"term_gettitle", 1, 1, f_term_gettitle},
846-
{"term_gettty", 1, 1, f_term_gettty},
846+
{"term_gettty", 1, 2, f_term_gettty},
847847
{"term_list", 0, 0, f_term_list},
848848
{"term_scrape", 2, 2, f_term_scrape},
849849
{"term_sendkeys", 2, 2, f_term_sendkeys},

src/os_unix.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5263,7 +5263,11 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
52635263
&& (!(use_file_for_in || use_null_for_in)
52645264
|| !(use_file_for_in || use_null_for_out)
52655265
|| !(use_out_for_err || use_file_for_err || use_null_for_err)))
5266-
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
5266+
{
5267+
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5268+
if (job->jv_tty_out != NULL)
5269+
job->jv_tty_in = vim_strsave(job->jv_tty_out);
5270+
}
52675271

52685272
/* TODO: without the channel feature connect the child to /dev/null? */
52695273
/* Open pipes for stdin, stdout, stderr. */
@@ -5687,7 +5691,9 @@ mch_create_pty_channel(job_T *job, jobopt_T *options)
56875691
int pty_slave_fd = -1;
56885692
channel_T *channel;
56895693

5690-
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
5694+
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5695+
if (job->jv_tty_out != NULL)
5696+
job->jv_tty_in = vim_strsave(job->jv_tty_out);
56915697
close(pty_slave_fd);
56925698

56935699
channel = add_channel();

src/structs.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,8 @@ struct jobvar_S
14871487
PROCESS_INFORMATION jv_proc_info;
14881488
HANDLE jv_job_object;
14891489
#endif
1490-
char_u *jv_tty_name; /* controlling tty, allocated */
1490+
char_u *jv_tty_in; /* controlling tty input, allocated */
1491+
char_u *jv_tty_out; /* controlling tty output, allocated */
14911492
jobstatus_T jv_status;
14921493
char_u *jv_stoponexit; /* allocated */
14931494
int jv_exitval;
@@ -1652,6 +1653,9 @@ struct channel_S {
16521653
/* callback for Netbeans when channel is
16531654
* closed */
16541655

1656+
#ifdef WIN32
1657+
int ch_named_pipe; /* using named pipe instead of pty */
1658+
#endif
16551659
char_u *ch_callback; /* call when any msg is not handled */
16561660
partial_T *ch_partial;
16571661
char_u *ch_close_cb; /* call when channel is closed */

src/terminal.c

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@
3838
* in tl_scrollback are no longer used.
3939
*
4040
* TODO:
41-
* - ":term NONE" does not work on MS-Windows.
42-
* https://github.com/vim/vim/pull/2056
41+
* - patch to use GUI or cterm colors for vterm. Yasuhiro, #2067
4342
* - Redirecting output does not work on MS-Windows.
4443
* - implement term_setsize()
4544
* - add test for giving error for invalid 'termsize' value.
@@ -97,7 +96,8 @@ struct terminal_S {
9796

9897
/* used when tl_job is NULL and only a pty was created */
9998
int tl_tty_fd;
100-
char_u *tl_tty_name;
99+
char_u *tl_tty_in;
100+
char_u *tl_tty_out;
101101

102102
int tl_normal_mode; /* TRUE: Terminal-Normal mode */
103103
int tl_channel_closed;
@@ -2666,14 +2666,32 @@ f_term_gettty(typval_T *argvars, typval_T *rettv)
26662666
{
26672667
buf_T *buf = term_get_buf(argvars);
26682668
char_u *p;
2669+
int num = 0;
26692670

26702671
rettv->v_type = VAR_STRING;
26712672
if (buf == NULL)
26722673
return;
2673-
if (buf->b_term->tl_job != NULL)
2674-
p = buf->b_term->tl_job->jv_tty_name;
2675-
else
2676-
p = buf->b_term->tl_tty_name;
2674+
if (argvars[1].v_type != VAR_UNKNOWN)
2675+
num = get_tv_number(&argvars[1]);
2676+
2677+
switch (num)
2678+
{
2679+
case 0:
2680+
if (buf->b_term->tl_job != NULL)
2681+
p = buf->b_term->tl_job->jv_tty_out;
2682+
else
2683+
p = buf->b_term->tl_tty_out;
2684+
break;
2685+
case 1:
2686+
if (buf->b_term->tl_job != NULL)
2687+
p = buf->b_term->tl_job->jv_tty_in;
2688+
else
2689+
p = buf->b_term->tl_tty_in;
2690+
break;
2691+
default:
2692+
EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
2693+
return;
2694+
}
26772695
if (p != NULL)
26782696
rettv->vval.v_string = vim_strsave(p);
26792697
}
@@ -3055,7 +3073,6 @@ term_and_job_init(
30553073
HANDLE child_thread_handle;
30563074
void *winpty_err;
30573075
void *spawn_config = NULL;
3058-
char buf[MAX_PATH];
30593076
garray_T ga;
30603077
char_u *cmd;
30613078

@@ -3094,7 +3111,6 @@ term_and_job_init(
30943111
if (term->tl_winpty == NULL)
30953112
goto failed;
30963113

3097-
/* TODO: if the command is "NONE" only create a pty. */
30983114
spawn_config = winpty_spawn_config_new(
30993115
WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN |
31003116
WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN,
@@ -3162,9 +3178,10 @@ term_and_job_init(
31623178
job->jv_proc_info.dwProcessId = GetProcessId(child_process_handle);
31633179
job->jv_job_object = jo;
31643180
job->jv_status = JOB_STARTED;
3165-
sprintf(buf, "winpty://%lu",
3166-
GetProcessId(winpty_agent_process(term->tl_winpty)));
3167-
job->jv_tty_name = vim_strsave((char_u*)buf);
3181+
job->jv_tty_in = utf16_to_enc(
3182+
(short_u*)winpty_conin_name(term->tl_winpty), NULL);
3183+
job->jv_tty_out = utf16_to_enc(
3184+
(short_u*)winpty_conout_name(term->tl_winpty), NULL);
31683185
++job->jv_refcount;
31693186
term->tl_job = job;
31703187

@@ -3205,9 +3222,68 @@ term_and_job_init(
32053222
}
32063223

32073224
static int
3208-
create_pty_only(term_T *term, jobopt_T *opt)
3225+
create_pty_only(term_T *term, jobopt_T *options)
32093226
{
3210-
/* TODO: implement this */
3227+
HANDLE hPipeIn = INVALID_HANDLE_VALUE;
3228+
HANDLE hPipeOut = INVALID_HANDLE_VALUE;
3229+
char in_name[80], out_name[80];
3230+
channel_T *channel = NULL;
3231+
3232+
create_vterm(term, term->tl_rows, term->tl_cols);
3233+
3234+
vim_snprintf(in_name, sizeof(in_name), "\\\\.\\pipe\\vim-%d-in-%d",
3235+
GetCurrentProcessId(),
3236+
curbuf->b_fnum);
3237+
hPipeIn = CreateNamedPipe(in_name, PIPE_ACCESS_OUTBOUND,
3238+
PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
3239+
PIPE_UNLIMITED_INSTANCES,
3240+
0, 0, NMPWAIT_NOWAIT, NULL);
3241+
if (hPipeIn == INVALID_HANDLE_VALUE)
3242+
goto failed;
3243+
3244+
vim_snprintf(out_name, sizeof(out_name), "\\\\.\\pipe\\vim-%d-out-%d",
3245+
GetCurrentProcessId(),
3246+
curbuf->b_fnum);
3247+
hPipeOut = CreateNamedPipe(out_name, PIPE_ACCESS_INBOUND,
3248+
PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
3249+
PIPE_UNLIMITED_INSTANCES,
3250+
0, 0, 0, NULL);
3251+
if (hPipeOut == INVALID_HANDLE_VALUE)
3252+
goto failed;
3253+
3254+
ConnectNamedPipe(hPipeIn, NULL);
3255+
ConnectNamedPipe(hPipeOut, NULL);
3256+
3257+
term->tl_job = job_alloc();
3258+
if (term->tl_job == NULL)
3259+
goto failed;
3260+
++term->tl_job->jv_refcount;
3261+
3262+
/* behave like the job is already finished */
3263+
term->tl_job->jv_status = JOB_FINISHED;
3264+
3265+
channel = add_channel();
3266+
if (channel == NULL)
3267+
goto failed;
3268+
term->tl_job->jv_channel = channel;
3269+
channel->ch_keep_open = TRUE;
3270+
channel->ch_named_pipe = TRUE;
3271+
3272+
channel_set_pipes(channel,
3273+
(sock_T)hPipeIn,
3274+
(sock_T)hPipeOut,
3275+
(sock_T)hPipeOut);
3276+
channel_set_job(channel, term->tl_job, options);
3277+
term->tl_job->jv_tty_in = vim_strsave((char_u*)in_name);
3278+
term->tl_job->jv_tty_out = vim_strsave((char_u*)out_name);
3279+
3280+
return OK;
3281+
3282+
failed:
3283+
if (hPipeIn != NULL)
3284+
CloseHandle(hPipeIn);
3285+
if (hPipeOut != NULL)
3286+
CloseHandle(hPipeOut);
32113287
return FAIL;
32123288
}
32133289

@@ -3234,7 +3310,8 @@ term_free_vterm(term_T *term)
32343310
static void
32353311
term_report_winsize(term_T *term, int rows, int cols)
32363312
{
3237-
winpty_set_size(term->tl_winpty, cols, rows, NULL);
3313+
if (term->tl_winpty)
3314+
winpty_set_size(term->tl_winpty, cols, rows, NULL);
32383315
}
32393316

32403317
int

0 commit comments

Comments
 (0)