Skip to content

Commit 5a1feb8

Browse files
committed
patch 8.0.0744: terminal window does not use a pty
Problem: A terminal window uses pipes instead of a pty. Solution: Add pty support.
1 parent 825680f commit 5a1feb8

File tree

8 files changed

+102
-64
lines changed

8 files changed

+102
-64
lines changed

src/channel.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,16 @@ ch_close_part(channel_T *channel, ch_part_T part)
10131013
if (part == PART_SOCK)
10141014
sock_close(*fd);
10151015
else
1016-
fd_close(*fd);
1016+
{
1017+
/* When using a pty the same FD is set on multiple parts, only
1018+
* close it when the last reference is closed. */
1019+
if ((part == PART_IN || channel->ch_part[PART_IN].ch_fd != *fd)
1020+
&& (part == PART_OUT
1021+
|| channel->ch_part[PART_OUT].ch_fd != *fd)
1022+
&& (part == PART_ERR
1023+
|| channel->ch_part[PART_ERR].ch_fd != *fd))
1024+
fd_close(*fd);
1025+
}
10171026
*fd = INVALID_FD;
10181027

10191028
channel->ch_to_be_closed &= ~(1 << part);
@@ -4280,6 +4289,12 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
42804289
opt->jo_io_name[part] =
42814290
get_tv_string_buf_chk(item, opt->jo_io_name_buf[part]);
42824291
}
4292+
else if (STRCMP(hi->hi_key, "pty") == 0)
4293+
{
4294+
if (!(supported & JO_MODE))
4295+
break;
4296+
opt->jo_pty = get_tv_number(item);
4297+
}
42834298
else if (STRCMP(hi->hi_key, "in_buf") == 0
42844299
|| STRCMP(hi->hi_key, "out_buf") == 0
42854300
|| STRCMP(hi->hi_key, "err_buf") == 0)
@@ -5074,10 +5089,10 @@ job_start(typval_T *argvars, jobopt_T *opt_arg)
50745089
ch_logs(NULL, "Starting job: %s", (char *)ga.ga_data);
50755090
ga_clear(&ga);
50765091
}
5077-
mch_start_job(argv, job, &opt);
5092+
mch_job_start(argv, job, &opt);
50785093
#else
50795094
ch_logs(NULL, "Starting job: %s", (char *)cmd);
5080-
mch_start_job((char *)cmd, job, &opt);
5095+
mch_job_start((char *)cmd, job, &opt);
50815096
#endif
50825097

50835098
/* If the channel is reading from a buffer, write lines now. */

src/os_unix.c

Lines changed: 75 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4096,6 +4096,32 @@ set_default_child_environment(void)
40964096
{
40974097
set_child_environment(Rows, Columns, "dumb");
40984098
}
4099+
#endif
4100+
4101+
#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
4102+
static void
4103+
open_pty(int *pty_master_fd, int *pty_slave_fd)
4104+
{
4105+
char *tty_name;
4106+
4107+
*pty_master_fd = OpenPTY(&tty_name); /* open pty */
4108+
if (*pty_master_fd >= 0)
4109+
{
4110+
/* Leaving out O_NOCTTY may lead to waitpid() always returning
4111+
* 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4112+
* adding O_NOCTTY always works when defined. */
4113+
#ifdef O_NOCTTY
4114+
*pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4115+
#else
4116+
*pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4117+
#endif
4118+
if (*pty_slave_fd < 0)
4119+
{
4120+
close(*pty_master_fd);
4121+
*pty_master_fd = -1;
4122+
}
4123+
}
4124+
}
40994125
#endif
41004126

41014127
int
@@ -4206,7 +4232,6 @@ mch_call_shell(
42064232
int pty_master_fd = -1; /* for pty's */
42074233
# ifdef FEAT_GUI
42084234
int pty_slave_fd = -1;
4209-
char *tty_name;
42104235
# endif
42114236
int fd_toshell[2]; /* for pipes */
42124237
int fd_fromshell[2];
@@ -4269,25 +4294,7 @@ mch_call_shell(
42694294
* If the slave can't be opened, close the master pty.
42704295
*/
42714296
if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
4272-
{
4273-
pty_master_fd = OpenPTY(&tty_name); /* open pty */
4274-
if (pty_master_fd >= 0)
4275-
{
4276-
/* Leaving out O_NOCTTY may lead to waitpid() always returning
4277-
* 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4278-
* adding O_NOCTTY always works when defined. */
4279-
#ifdef O_NOCTTY
4280-
pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4281-
#else
4282-
pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4283-
#endif
4284-
if (pty_slave_fd < 0)
4285-
{
4286-
close(pty_master_fd);
4287-
pty_master_fd = -1;
4288-
}
4289-
}
4290-
}
4297+
open_pty(&pty_master_fd, &pty_slave_fd);
42914298
/*
42924299
* If not opening a pty or it didn't work, try using pipes.
42934300
*/
@@ -5100,12 +5107,14 @@ mch_call_shell(
51005107

51015108
#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
51025109
void
5103-
mch_start_job(char **argv, job_T *job, jobopt_T *options)
5110+
mch_job_start(char **argv, job_T *job, jobopt_T *options)
51045111
{
51055112
pid_t pid;
51065113
int fd_in[2]; /* for stdin */
51075114
int fd_out[2]; /* for stdout */
51085115
int fd_err[2]; /* for stderr */
5116+
int pty_master_fd = -1;
5117+
int pty_slave_fd = -1;
51095118
channel_T *channel = NULL;
51105119
int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
51115120
int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
@@ -5128,6 +5137,9 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
51285137
fd_err[0] = -1;
51295138
fd_err[1] = -1;
51305139

5140+
if (options->jo_pty)
5141+
open_pty(&pty_master_fd, &pty_slave_fd);
5142+
51315143
/* TODO: without the channel feature connect the child to /dev/null? */
51325144
/* Open pipes for stdin, stdout, stderr. */
51335145
if (use_file_for_in)
@@ -5141,7 +5153,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
51415153
goto failed;
51425154
}
51435155
}
5144-
else if (!use_null_for_in && pipe(fd_in) < 0)
5156+
else if (!use_null_for_in && pty_master_fd < 0 && pipe(fd_in) < 0)
51455157
goto failed;
51465158

51475159
if (use_file_for_out)
@@ -5155,7 +5167,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
51555167
goto failed;
51565168
}
51575169
}
5158-
else if (!use_null_for_out && pipe(fd_out) < 0)
5170+
else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
51595171
goto failed;
51605172

51615173
if (use_file_for_err)
@@ -5169,7 +5181,8 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
51695181
goto failed;
51705182
}
51715183
}
5172-
else if (!use_out_for_err && !use_null_for_err && pipe(fd_err) < 0)
5184+
else if (!use_out_for_err && !use_null_for_err
5185+
&& pty_master_fd < 0 && pipe(fd_err) < 0)
51735186
goto failed;
51745187

51755188
if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
@@ -5224,54 +5237,53 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
52245237
null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
52255238

52265239
/* set up stdin for the child */
5240+
close(0);
52275241
if (use_null_for_in && null_fd >= 0)
5228-
{
5229-
close(0);
52305242
ignored = dup(null_fd);
5231-
}
5243+
else if (fd_in[0] < 0)
5244+
ignored = dup(pty_slave_fd);
52325245
else
5233-
{
5234-
if (!use_file_for_in)
5235-
close(fd_in[1]);
5236-
close(0);
52375246
ignored = dup(fd_in[0]);
5238-
close(fd_in[0]);
5239-
}
52405247

52415248
/* set up stderr for the child */
5249+
close(2);
52425250
if (use_null_for_err && null_fd >= 0)
52435251
{
5244-
close(2);
52455252
ignored = dup(null_fd);
52465253
stderr_works = FALSE;
52475254
}
52485255
else if (use_out_for_err)
5249-
{
5250-
close(2);
52515256
ignored = dup(fd_out[1]);
5252-
}
5257+
else if (fd_err[1] < 0)
5258+
ignored = dup(pty_slave_fd);
52535259
else
5254-
{
5255-
if (!use_file_for_err)
5256-
close(fd_err[0]);
5257-
close(2);
52585260
ignored = dup(fd_err[1]);
5259-
close(fd_err[1]);
5260-
}
52615261

52625262
/* set up stdout for the child */
5263+
close(1);
52635264
if (use_null_for_out && null_fd >= 0)
5264-
{
5265-
close(1);
52665265
ignored = dup(null_fd);
5267-
}
5266+
else if (fd_out[1] < 0)
5267+
ignored = dup(pty_slave_fd);
52685268
else
5269-
{
5270-
if (!use_file_for_out)
5271-
close(fd_out[0]);
5272-
close(1);
52735269
ignored = dup(fd_out[1]);
5270+
5271+
if (fd_in[0] >= 0)
5272+
close(fd_in[0]);
5273+
if (fd_in[1] >= 0)
5274+
close(fd_in[1]);
5275+
if (fd_out[0] >= 0)
5276+
close(fd_out[0]);
5277+
if (fd_out[1] >= 0)
52745278
close(fd_out[1]);
5279+
if (fd_err[0] >= 0)
5280+
close(fd_err[0]);
5281+
if (fd_err[1] >= 0)
5282+
close(fd_err[1]);
5283+
if (pty_master_fd >= 0)
5284+
{
5285+
close(pty_master_fd); /* not used */
5286+
close(pty_slave_fd); /* duped above */
52755287
}
52765288

52775289
if (null_fd >= 0)
@@ -5296,7 +5308,9 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
52965308
job->jv_status = JOB_STARTED;
52975309
job->jv_channel = channel; /* ch_refcount was set above */
52985310

5299-
/* child stdin, stdout and stderr */
5311+
if (pty_master_fd >= 0)
5312+
close(pty_slave_fd); /* duped above */
5313+
/* close child stdin, stdout and stderr */
53005314
if (!use_file_for_in && fd_in[0] >= 0)
53015315
close(fd_in[0]);
53025316
if (!use_file_for_out && fd_out[1] >= 0)
@@ -5306,12 +5320,12 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
53065320
if (channel != NULL)
53075321
{
53085322
channel_set_pipes(channel,
5309-
use_file_for_in || use_null_for_in
5310-
? INVALID_FD : fd_in[1],
5311-
use_file_for_out || use_null_for_out
5312-
? INVALID_FD : fd_out[0],
5313-
use_out_for_err || use_file_for_err || use_null_for_err
5314-
? INVALID_FD : fd_err[0]);
5323+
use_file_for_in || use_null_for_in
5324+
? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1],
5325+
use_file_for_out || use_null_for_out
5326+
? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0],
5327+
use_out_for_err || use_file_for_err || use_null_for_err
5328+
? INVALID_FD : fd_err[0] < 0 ? pty_master_fd : fd_err[0]);
53155329
channel_set_job(channel, job, options);
53165330
}
53175331

@@ -5332,6 +5346,10 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
53325346
close(fd_err[0]);
53335347
if (fd_err[1] >= 0)
53345348
close(fd_err[1]);
5349+
if (pty_master_fd >= 0)
5350+
close(pty_master_fd);
5351+
if (pty_slave_fd >= 0)
5352+
close(pty_slave_fd);
53355353
}
53365354

53375355
char *

src/os_win32.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4964,7 +4964,7 @@ job_io_file_open(
49644964
}
49654965

49664966
void
4967-
mch_start_job(char *cmd, job_T *job, jobopt_T *options)
4967+
mch_job_start(char *cmd, job_T *job, jobopt_T *options)
49684968
{
49694969
STARTUPINFO si;
49704970
PROCESS_INFORMATION pi;

src/proto/os_unix.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void mch_set_shellsize(void);
5757
void mch_new_shellsize(void);
5858
int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
5959
int mch_call_shell(char_u *cmd, int options);
60-
void mch_start_job(char **argv, job_T *job, jobopt_T *options);
60+
void mch_job_start(char **argv, job_T *job, jobopt_T *options);
6161
char *mch_job_status(job_T *job);
6262
job_T *mch_detect_ended_job(job_T *job_list);
6363
int mch_stop_job(job_T *job, char_u *how);

src/proto/os_win32.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void mch_set_shellsize(void);
4141
void mch_new_shellsize(void);
4242
void mch_set_winsize_now(void);
4343
int mch_call_shell(char_u *cmd, int options);
44-
void mch_start_job(char *cmd, job_T *job, jobopt_T *options);
44+
void mch_job_start(char *cmd, job_T *job, jobopt_T *options);
4545
char *mch_job_status(job_T *job);
4646
job_T *mch_detect_ended_job(job_T *job_list);
4747
int mch_stop_job(job_T *job, char_u *how);

src/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,7 @@ typedef struct
17051705
char_u jo_io_name_buf[4][NUMBUFLEN];
17061706
char_u *jo_io_name[4]; /* not allocated! */
17071707
int jo_io_buf[4];
1708+
int jo_pty;
17081709
int jo_modifiable[4];
17091710
int jo_message[4];
17101711
channel_T *jo_channel;

src/terminal.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
* TODO:
3535
* - When 'termsize' is set and dragging the separator the terminal gets messed
3636
* up.
37-
* - Use a pty for I/O with the job.
3837
* - set buffer options to be scratch, hidden, nomodifiable, etc.
3938
* - set buffer name to command, add (1) to avoid duplicates.
4039
* - If [command] is not given the 'shell' option is used.
@@ -52,6 +51,8 @@
5251
* - add test for giving error for invalid 'termsize' value.
5352
* - support minimal size when 'termsize' is "rows*cols".
5453
* - support minimal size when 'termsize' is empty?
54+
* - implement "term" for job_start(): more job options when starting a
55+
* terminal.
5556
* - implement ":buf {term-buf-name}"
5657
* - implement term_list() list of buffers with a terminal
5758
* - implement term_getsize(buf)
@@ -673,6 +674,7 @@ setup_job_options(jobopt_T *opt, int rows, int cols)
673674
opt->jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT));
674675
opt->jo_io_buf[PART_OUT] = curbuf->b_fnum;
675676
opt->jo_io_buf[PART_ERR] = curbuf->b_fnum;
677+
opt->jo_pty = TRUE;
676678
opt->jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT));
677679
opt->jo_term_rows = rows;
678680
opt->jo_term_cols = cols;

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,8 @@ static char *(features[]) =
769769

770770
static int included_patches[] =
771771
{ /* Add new patch number below this line */
772+
/**/
773+
744,
772774
/**/
773775
743,
774776
/**/

0 commit comments

Comments
 (0)