To: vim_dev@googlegroups.com Subject: Patch 8.0.0744 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0744 Problem: A terminal window uses pipes instead of a pty. Solution: Add pty support. Files: src/structs.h, src/os_unix.c, src/terminal.c, src/channel.c, src/proto/os_unix.pro, src/os_win32.c, src/proto/os_win32.pro *** ../vim-8.0.0743/src/structs.h 2017-07-20 23:04:42.967282191 +0200 --- src/structs.h 2017-07-22 17:58:36.776232195 +0200 *************** *** 1705,1710 **** --- 1705,1711 ---- char_u jo_io_name_buf[4][NUMBUFLEN]; char_u *jo_io_name[4]; /* not allocated! */ int jo_io_buf[4]; + int jo_pty; int jo_modifiable[4]; int jo_message[4]; channel_T *jo_channel; *** ../vim-8.0.0743/src/os_unix.c 2017-07-22 14:08:39.082860834 +0200 --- src/os_unix.c 2017-07-22 18:01:24.335023832 +0200 *************** *** 4098,4103 **** --- 4098,4129 ---- } #endif + #if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL) + static void + open_pty(int *pty_master_fd, int *pty_slave_fd) + { + char *tty_name; + + *pty_master_fd = OpenPTY(&tty_name); /* open pty */ + if (*pty_master_fd >= 0) + { + /* Leaving out O_NOCTTY may lead to waitpid() always returning + * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume + * adding O_NOCTTY always works when defined. */ + #ifdef O_NOCTTY + *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0); + #else + *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0); + #endif + if (*pty_slave_fd < 0) + { + close(*pty_master_fd); + *pty_master_fd = -1; + } + } + } + #endif + int mch_call_shell( char_u *cmd, *************** *** 4206,4212 **** int pty_master_fd = -1; /* for pty's */ # ifdef FEAT_GUI int pty_slave_fd = -1; - char *tty_name; # endif int fd_toshell[2]; /* for pipes */ int fd_fromshell[2]; --- 4232,4237 ---- *************** *** 4269,4293 **** * If the slave can't be opened, close the master pty. */ if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE))) ! { ! pty_master_fd = OpenPTY(&tty_name); /* open pty */ ! if (pty_master_fd >= 0) ! { ! /* Leaving out O_NOCTTY may lead to waitpid() always returning ! * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume ! * adding O_NOCTTY always works when defined. */ ! #ifdef O_NOCTTY ! pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0); ! #else ! pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0); ! #endif ! if (pty_slave_fd < 0) ! { ! close(pty_master_fd); ! pty_master_fd = -1; ! } ! } ! } /* * If not opening a pty or it didn't work, try using pipes. */ --- 4294,4300 ---- * If the slave can't be opened, close the master pty. */ if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE))) ! open_pty(&pty_master_fd, &pty_slave_fd); /* * If not opening a pty or it didn't work, try using pipes. */ *************** *** 5100,5111 **** #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) void ! mch_start_job(char **argv, job_T *job, jobopt_T *options) { pid_t pid; int fd_in[2]; /* for stdin */ int fd_out[2]; /* for stdout */ int fd_err[2]; /* for stderr */ channel_T *channel = NULL; int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL; int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL; --- 5107,5120 ---- #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) void ! mch_job_start(char **argv, job_T *job, jobopt_T *options) { pid_t pid; int fd_in[2]; /* for stdin */ int fd_out[2]; /* for stdout */ int fd_err[2]; /* for stderr */ + int pty_master_fd = -1; + int pty_slave_fd = -1; channel_T *channel = NULL; int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL; int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL; *************** *** 5128,5133 **** --- 5137,5145 ---- fd_err[0] = -1; fd_err[1] = -1; + if (options->jo_pty) + open_pty(&pty_master_fd, &pty_slave_fd); + /* TODO: without the channel feature connect the child to /dev/null? */ /* Open pipes for stdin, stdout, stderr. */ if (use_file_for_in) *************** *** 5141,5147 **** goto failed; } } ! else if (!use_null_for_in && pipe(fd_in) < 0) goto failed; if (use_file_for_out) --- 5153,5159 ---- goto failed; } } ! else if (!use_null_for_in && pty_master_fd < 0 && pipe(fd_in) < 0) goto failed; if (use_file_for_out) *************** *** 5155,5161 **** goto failed; } } ! else if (!use_null_for_out && pipe(fd_out) < 0) goto failed; if (use_file_for_err) --- 5167,5173 ---- goto failed; } } ! else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0) goto failed; if (use_file_for_err) *************** *** 5169,5175 **** goto failed; } } ! else if (!use_out_for_err && !use_null_for_err && pipe(fd_err) < 0) goto failed; if (!use_null_for_in || !use_null_for_out || !use_null_for_err) --- 5181,5188 ---- goto failed; } } ! else if (!use_out_for_err && !use_null_for_err ! && pty_master_fd < 0 && pipe(fd_err) < 0) goto failed; if (!use_null_for_in || !use_null_for_out || !use_null_for_err) *************** *** 5224,5277 **** null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0); /* set up stdin for the child */ if (use_null_for_in && null_fd >= 0) - { - close(0); ignored = dup(null_fd); ! } else - { - if (!use_file_for_in) - close(fd_in[1]); - close(0); ignored = dup(fd_in[0]); - close(fd_in[0]); - } /* set up stderr for the child */ if (use_null_for_err && null_fd >= 0) { - close(2); ignored = dup(null_fd); stderr_works = FALSE; } else if (use_out_for_err) - { - close(2); ignored = dup(fd_out[1]); ! } else - { - if (!use_file_for_err) - close(fd_err[0]); - close(2); ignored = dup(fd_err[1]); - close(fd_err[1]); - } /* set up stdout for the child */ if (use_null_for_out && null_fd >= 0) - { - close(1); ignored = dup(null_fd); ! } else - { - if (!use_file_for_out) - close(fd_out[0]); - close(1); ignored = dup(fd_out[1]); close(fd_out[1]); } if (null_fd >= 0) --- 5237,5289 ---- null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0); /* set up stdin for the child */ + close(0); if (use_null_for_in && null_fd >= 0) ignored = dup(null_fd); ! else if (fd_in[0] < 0) ! ignored = dup(pty_slave_fd); else ignored = dup(fd_in[0]); /* set up stderr for the child */ + close(2); if (use_null_for_err && null_fd >= 0) { ignored = dup(null_fd); stderr_works = FALSE; } else if (use_out_for_err) ignored = dup(fd_out[1]); ! else if (fd_err[1] < 0) ! ignored = dup(pty_slave_fd); else ignored = dup(fd_err[1]); /* set up stdout for the child */ + close(1); if (use_null_for_out && null_fd >= 0) ignored = dup(null_fd); ! else if (fd_out[1] < 0) ! ignored = dup(pty_slave_fd); else ignored = dup(fd_out[1]); + + if (fd_in[0] >= 0) + close(fd_in[0]); + if (fd_in[1] >= 0) + close(fd_in[1]); + if (fd_out[0] >= 0) + close(fd_out[0]); + if (fd_out[1] >= 0) close(fd_out[1]); + if (fd_err[0] >= 0) + close(fd_err[0]); + if (fd_err[1] >= 0) + close(fd_err[1]); + if (pty_master_fd >= 0) + { + close(pty_master_fd); /* not used */ + close(pty_slave_fd); /* duped above */ } if (null_fd >= 0) *************** *** 5296,5302 **** job->jv_status = JOB_STARTED; job->jv_channel = channel; /* ch_refcount was set above */ ! /* child stdin, stdout and stderr */ if (!use_file_for_in && fd_in[0] >= 0) close(fd_in[0]); if (!use_file_for_out && fd_out[1] >= 0) --- 5308,5316 ---- job->jv_status = JOB_STARTED; job->jv_channel = channel; /* ch_refcount was set above */ ! if (pty_master_fd >= 0) ! close(pty_slave_fd); /* duped above */ ! /* close child stdin, stdout and stderr */ if (!use_file_for_in && fd_in[0] >= 0) close(fd_in[0]); if (!use_file_for_out && fd_out[1] >= 0) *************** *** 5306,5317 **** if (channel != NULL) { channel_set_pipes(channel, ! use_file_for_in || use_null_for_in ! ? INVALID_FD : fd_in[1], ! use_file_for_out || use_null_for_out ! ? INVALID_FD : fd_out[0], ! use_out_for_err || use_file_for_err || use_null_for_err ! ? INVALID_FD : fd_err[0]); channel_set_job(channel, job, options); } --- 5320,5331 ---- if (channel != NULL) { channel_set_pipes(channel, ! use_file_for_in || use_null_for_in ! ? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1], ! use_file_for_out || use_null_for_out ! ? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0], ! use_out_for_err || use_file_for_err || use_null_for_err ! ? INVALID_FD : fd_err[0] < 0 ? pty_master_fd : fd_err[0]); channel_set_job(channel, job, options); } *************** *** 5332,5337 **** --- 5346,5355 ---- close(fd_err[0]); if (fd_err[1] >= 0) close(fd_err[1]); + if (pty_master_fd >= 0) + close(pty_master_fd); + if (pty_slave_fd >= 0) + close(pty_slave_fd); } char * *** ../vim-8.0.0743/src/terminal.c 2017-07-22 16:14:39.276915783 +0200 --- src/terminal.c 2017-07-22 17:55:38.433509231 +0200 *************** *** 34,40 **** * TODO: * - When 'termsize' is set and dragging the separator the terminal gets messed * up. - * - Use a pty for I/O with the job. * - set buffer options to be scratch, hidden, nomodifiable, etc. * - set buffer name to command, add (1) to avoid duplicates. * - If [command] is not given the 'shell' option is used. --- 34,39 ---- *************** *** 52,57 **** --- 51,58 ---- * - add test for giving error for invalid 'termsize' value. * - support minimal size when 'termsize' is "rows*cols". * - support minimal size when 'termsize' is empty? + * - implement "term" for job_start(): more job options when starting a + * terminal. * - implement ":buf {term-buf-name}" * - implement term_list() list of buffers with a terminal * - implement term_getsize(buf) *************** *** 673,678 **** --- 674,680 ---- opt->jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT)); opt->jo_io_buf[PART_OUT] = curbuf->b_fnum; opt->jo_io_buf[PART_ERR] = curbuf->b_fnum; + opt->jo_pty = TRUE; opt->jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT)); opt->jo_term_rows = rows; opt->jo_term_cols = cols; *** ../vim-8.0.0743/src/channel.c 2017-07-22 16:14:39.272915812 +0200 --- src/channel.c 2017-07-22 17:50:26.123745598 +0200 *************** *** 1013,1019 **** if (part == PART_SOCK) sock_close(*fd); else ! fd_close(*fd); *fd = INVALID_FD; channel->ch_to_be_closed &= ~(1 << part); --- 1013,1028 ---- if (part == PART_SOCK) sock_close(*fd); else ! { ! /* When using a pty the same FD is set on multiple parts, only ! * close it when the last reference is closed. */ ! if ((part == PART_IN || channel->ch_part[PART_IN].ch_fd != *fd) ! && (part == PART_OUT ! || channel->ch_part[PART_OUT].ch_fd != *fd) ! && (part == PART_ERR ! || channel->ch_part[PART_ERR].ch_fd != *fd)) ! fd_close(*fd); ! } *fd = INVALID_FD; channel->ch_to_be_closed &= ~(1 << part); *************** *** 4280,4285 **** --- 4289,4300 ---- opt->jo_io_name[part] = get_tv_string_buf_chk(item, opt->jo_io_name_buf[part]); } + else if (STRCMP(hi->hi_key, "pty") == 0) + { + if (!(supported & JO_MODE)) + break; + opt->jo_pty = get_tv_number(item); + } else if (STRCMP(hi->hi_key, "in_buf") == 0 || STRCMP(hi->hi_key, "out_buf") == 0 || STRCMP(hi->hi_key, "err_buf") == 0) *************** *** 5074,5083 **** ch_logs(NULL, "Starting job: %s", (char *)ga.ga_data); ga_clear(&ga); } ! mch_start_job(argv, job, &opt); #else ch_logs(NULL, "Starting job: %s", (char *)cmd); ! mch_start_job((char *)cmd, job, &opt); #endif /* If the channel is reading from a buffer, write lines now. */ --- 5089,5098 ---- ch_logs(NULL, "Starting job: %s", (char *)ga.ga_data); ga_clear(&ga); } ! mch_job_start(argv, job, &opt); #else ch_logs(NULL, "Starting job: %s", (char *)cmd); ! mch_job_start((char *)cmd, job, &opt); #endif /* If the channel is reading from a buffer, write lines now. */ *** ../vim-8.0.0743/src/proto/os_unix.pro 2016-10-15 18:36:45.353910276 +0200 --- src/proto/os_unix.pro 2017-07-22 17:51:31.695276052 +0200 *************** *** 57,63 **** void mch_new_shellsize(void); int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc); int mch_call_shell(char_u *cmd, int options); ! void mch_start_job(char **argv, job_T *job, jobopt_T *options); char *mch_job_status(job_T *job); job_T *mch_detect_ended_job(job_T *job_list); int mch_stop_job(job_T *job, char_u *how); --- 57,63 ---- void mch_new_shellsize(void); int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc); int mch_call_shell(char_u *cmd, int options); ! void mch_job_start(char **argv, job_T *job, jobopt_T *options); char *mch_job_status(job_T *job); job_T *mch_detect_ended_job(job_T *job_list); int mch_stop_job(job_T *job, char_u *how); *** ../vim-8.0.0743/src/os_win32.c 2017-03-21 19:29:22.053338817 +0100 --- src/os_win32.c 2017-07-22 17:51:13.007409872 +0200 *************** *** 4964,4970 **** } void ! mch_start_job(char *cmd, job_T *job, jobopt_T *options) { STARTUPINFO si; PROCESS_INFORMATION pi; --- 4964,4970 ---- } void ! mch_job_start(char *cmd, job_T *job, jobopt_T *options) { STARTUPINFO si; PROCESS_INFORMATION pi; *** ../vim-8.0.0743/src/proto/os_win32.pro 2017-02-01 13:14:11.026177020 +0100 --- src/proto/os_win32.pro 2017-07-22 17:51:23.691333367 +0200 *************** *** 41,47 **** void mch_new_shellsize(void); void mch_set_winsize_now(void); int mch_call_shell(char_u *cmd, int options); ! void mch_start_job(char *cmd, job_T *job, jobopt_T *options); char *mch_job_status(job_T *job); job_T *mch_detect_ended_job(job_T *job_list); int mch_stop_job(job_T *job, char_u *how); --- 41,47 ---- void mch_new_shellsize(void); void mch_set_winsize_now(void); int mch_call_shell(char_u *cmd, int options); ! void mch_job_start(char *cmd, job_T *job, jobopt_T *options); char *mch_job_status(job_T *job); job_T *mch_detect_ended_job(job_T *job_list); int mch_stop_job(job_T *job, char_u *how); *** ../vim-8.0.0743/src/version.c 2017-07-22 17:03:57.371802012 +0200 --- src/version.c 2017-07-22 17:55:21.141633051 +0200 *************** *** 771,772 **** --- 771,774 ---- { /* Add new patch number below this line */ + /**/ + 744, /**/ -- hundred-and-one symptoms of being an internet addict: 203. You're an active member of more than 20 newsgroups. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///