]> granicus.if.org Git - vim/commitdiff
patch 8.0.0744: terminal window does not use a pty v8.0.0744
authorBram Moolenaar <Bram@vim.org>
Sat, 22 Jul 2017 16:04:08 +0000 (18:04 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 22 Jul 2017 16:04:08 +0000 (18:04 +0200)
Problem:    A terminal window uses pipes instead of a pty.
Solution:   Add pty support.

src/channel.c
src/os_unix.c
src/os_win32.c
src/proto/os_unix.pro
src/proto/os_win32.pro
src/structs.h
src/terminal.c
src/version.c

index 141bc5f37073bec3a1318e765aea67ea0e47b672..7af19b0412eac758b3d7a0bc0d17f4d34a521d0c 100644 (file)
@@ -1013,7 +1013,16 @@ ch_close_part(channel_T *channel, ch_part_T part)
        if (part == PART_SOCK)
            sock_close(*fd);
        else
-           fd_close(*fd);
+       {
+           /* 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,6 +4289,12 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
                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,10 +5089,10 @@ job_start(typval_T *argvars, jobopt_T *opt_arg)
        ch_logs(NULL, "Starting job: %s", (char *)ga.ga_data);
        ga_clear(&ga);
     }
-    mch_start_job(argv, job, &opt);
+    mch_job_start(argv, job, &opt);
 #else
     ch_logs(NULL, "Starting job: %s", (char *)cmd);
-    mch_start_job((char *)cmd, job, &opt);
+    mch_job_start((char *)cmd, job, &opt);
 #endif
 
     /* If the channel is reading from a buffer, write lines now. */
index ad70465b03a607d963252f80a88985f4239a8418..156168fcc369854f59a5e5943d17ad962975f5e0 100644 (file)
@@ -4096,6 +4096,32 @@ set_default_child_environment(void)
 {
     set_child_environment(Rows, Columns, "dumb");
 }
+#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
@@ -4206,7 +4232,6 @@ mch_call_shell(
     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];
@@ -4269,25 +4294,7 @@ mch_call_shell(
         * 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;
-               }
-           }
-       }
+           open_pty(&pty_master_fd, &pty_slave_fd);
        /*
         * If not opening a pty or it didn't work, try using pipes.
         */
@@ -5100,12 +5107,14 @@ error:
 
 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
     void
-mch_start_job(char **argv, job_T *job, jobopt_T *options)
+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,6 +5137,9 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
     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,7 +5153,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
            goto failed;
        }
     }
-    else if (!use_null_for_in && pipe(fd_in) < 0)
+    else if (!use_null_for_in && pty_master_fd < 0 && pipe(fd_in) < 0)
        goto failed;
 
     if (use_file_for_out)
@@ -5155,7 +5167,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
            goto failed;
        }
     }
-    else if (!use_null_for_out && pipe(fd_out) < 0)
+    else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
        goto failed;
 
     if (use_file_for_err)
@@ -5169,7 +5181,8 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
            goto failed;
        }
     }
-    else if (!use_out_for_err && !use_null_for_err && pipe(fd_err) < 0)
+    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,54 +5237,53 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
            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)
-       {
-           close(0);
            ignored = dup(null_fd);
-       }
+       else if (fd_in[0] < 0)
+           ignored = dup(pty_slave_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 */
+       close(2);
        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 (fd_err[1] < 0)
+           ignored = dup(pty_slave_fd);
        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 */
+       close(1);
        if (use_null_for_out && null_fd >= 0)
-       {
-           close(1);
            ignored = dup(null_fd);
-       }
+       else if (fd_out[1] < 0)
+           ignored = dup(pty_slave_fd);
        else
-       {
-           if (!use_file_for_out)
-               close(fd_out[0]);
-           close(1);
            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,7 +5308,9 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
     job->jv_status = JOB_STARTED;
     job->jv_channel = channel;  /* ch_refcount was set above */
 
-    /* child stdin, stdout and stderr */
+    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,12 +5320,12 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
     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]);
+               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,6 +5346,10 @@ failed:
        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 *
index f2fd808e929867b7671099dcbdb24c9bf6f82da2..8a38bcc56c28e576e8abd44dd8e1dcd131a153b5 100644 (file)
@@ -4964,7 +4964,7 @@ job_io_file_open(
 }
 
     void
-mch_start_job(char *cmd, job_T *job, jobopt_T *options)
+mch_job_start(char *cmd, job_T *job, jobopt_T *options)
 {
     STARTUPINFO                si;
     PROCESS_INFORMATION        pi;
index 700b69ef2e56f30bc8dae78a9e153069dfde010a..11191c95b66f26e3e1addd8ae4ce962b3e62c9da 100644 (file)
@@ -57,7 +57,7 @@ void mch_set_shellsize(void);
 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);
+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);
index ca671464b99b87b7348001e6b40151637afbaf33..6c5dc4fc01ef71af78ef53528c0add736d794175 100644 (file)
@@ -41,7 +41,7 @@ void mch_set_shellsize(void);
 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);
+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);
index 5a7f28b797f28f11bb3248f56e2b24b1ceaaeab9..44df3562969920aa74a01721ab4fe36a07ab25e0 100644 (file)
@@ -1705,6 +1705,7 @@ typedef struct
     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;
index df40866ba5f5a4d4067807f8850d43eb1cfbee49..0d974eddbe4551d4c1295f00ddd267814497fe07 100644 (file)
@@ -34,7 +34,6 @@
  * 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.
@@ -52,6 +51,8 @@
  * - 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,6 +674,7 @@ setup_job_options(jobopt_T *opt, int rows, int cols)
     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;
index da56b9a313f5a32a421c32d25240ddd81f0c93c9..31dc8d6822b153270b022fa3633dcada659c9af4 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    744,
 /**/
     743,
 /**/