Problem: Cannot get the name of the pty of a job.
Solution: Add the "tty" entry to the job info. (Ozaki Kiichi, closes #1920)
Add the term_gettty() function.
-*eval.txt* For Vim version 8.0. Last change: 2017 Aug 01
+*eval.txt* For Vim version 8.0. Last change: 2017 Aug 03
VIM REFERENCE MANUAL by Bram Moolenaar
term_getsize({buf}) List get the size of a terminal
term_getstatus({buf}) String get the status of a terminal
term_gettitle({buf}) String get the title of a terminal
+term_gettty({buf}) String get the tty name of a terminal
term_list() List get the list of terminal buffers
term_scrape({buf}, {row}) List get row of a terminal screen
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
Returns a Dictionary with information about {job}:
"status" what |job_status()| returns
"channel" what |job_getchannel()| returns
+ "process" process ID
+ "tty" controlling terminal name, empty when none
"exitval" only valid when "status" is "dead"
"exit_cb" function to be called on exit
"stoponexit" |job-stoponexit|
term_getjob({buf}) *term_getjob()*
Get the Job associated with terminal window {buf}.
{buf} is used as with |term_getsize()|.
+ Returns |v:null| when there is no job.
term_getline({buf}, {row}) *term_getline()*
Get a line of text from the terminal window of {buf}.
numbers: [rows, cols]. This is the size of the terminal, not
the window containing the terminal.
- {buf} must be the buffer number of a terminal window. If the
- buffer does not exist or is not a terminal window, an empty
- list is returned.
+ {buf} must be the buffer number of a terminal window. Use an
+ empty string for the current buffer. If the buffer does not
+ exist or is not a terminal window, an empty list is returned.
term_getstatus({buf}) *term_getstatus()*
Get the status of terminal {buf}. This returns a comma
buffer does not exist or is not a terminal window, an empty
string is returned.
+term_gettty({buf}) *term_gettty()*
+ Get the name of the controlling terminal associated with
+ terminal window {buf}.
+ {buf} is used as with |term_getsize()|.
+
term_list() *term_list()*
Return a list with the buffer numbers of all buffers for
terminal windows.
"chars" character(s) at the cell
"fg" foreground color as #rrggbb
"bg" background color as #rrggbb
- "attr" attributes of the cell, use term_getattr()
+ "attr" attributes of the cell, use |term_getattr()|
to get the individual flags
"width" cell width: 1 or 2
{
/* 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))
+ 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))
fd_close(*fd);
}
*fd = INVALID_FD;
}
mch_clear_job(job);
+ vim_free(job->jv_tty_name);
vim_free(job->jv_stoponexit);
free_callback(job->jv_exit_cb, job->jv_exit_partial);
}
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, "exitval", job->jv_exitval, NULL);
dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);
{"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_list", 0, 0, f_term_list},
{"term_scrape", 1, 2, f_term_scrape},
{"term_sendkeys", 2, 2, f_term_sendkeys},
* When successful both file descriptors are stored.
*/
static void
-open_pty(int *pty_master_fd, int *pty_slave_fd)
+open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **namep)
{
char *tty_name;
close(*pty_master_fd);
*pty_master_fd = -1;
}
+ else if (namep != NULL)
+ *namep = vim_strsave((char_u *)tty_name);
}
}
#endif
* 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);
+ open_pty(&pty_master_fd, &pty_slave_fd, NULL);
/*
* If not opening a pty or it didn't work, try using pipes.
*/
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 fd_in[2] = {-1, -1}; /* for stdin */
+ int fd_out[2] = {-1, -1}; /* for stdout */
+ int fd_err[2] = {-1, -1}; /* for stderr */
int pty_master_fd = -1;
int pty_slave_fd = -1;
channel_T *channel = NULL;
/* default is to fail */
job->jv_status = JOB_FAILED;
- fd_in[0] = -1;
- fd_in[1] = -1;
- fd_out[0] = -1;
- fd_out[1] = -1;
- fd_err[0] = -1;
- fd_err[1] = -1;
if (options->jo_pty)
- open_pty(&pty_master_fd, &pty_slave_fd);
+ open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
/* TODO: without the channel feature connect the child to /dev/null? */
/* Open pipes for stdin, stdout, stderr. */
void f_term_getsize(typval_T *argvars, typval_T *rettv);
void f_term_getstatus(typval_T *argvars, typval_T *rettv);
void f_term_gettitle(typval_T *argvars, typval_T *rettv);
+void f_term_gettty(typval_T *argvars, typval_T *rettv);
void f_term_list(typval_T *argvars, typval_T *rettv);
void f_term_scrape(typval_T *argvars, typval_T *rettv);
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
PROCESS_INFORMATION jv_proc_info;
HANDLE jv_job_object;
#endif
+ char_u *jv_tty_name; /* controlling tty, allocated */
jobstatus_T jv_status;
char_u *jv_stoponexit; /* allocated */
int jv_exitval;
JIO_OUT
} job_io_T;
+#define CH_PART_FD(part) ch_part[part].ch_fd
+
/* Ordering matters, it is used in for loops: IN is last, only SOCK/OUT/ERR
* are polled. */
typedef enum {
PART_SOCK = 0,
-#define CH_SOCK_FD ch_part[PART_SOCK].ch_fd
+#define CH_SOCK_FD CH_PART_FD(PART_SOCK)
#ifdef FEAT_JOB_CHANNEL
PART_OUT,
-# define CH_OUT_FD ch_part[PART_OUT].ch_fd
+# define CH_OUT_FD CH_PART_FD(PART_OUT)
PART_ERR,
-# define CH_ERR_FD ch_part[PART_ERR].ch_fd
+# define CH_ERR_FD CH_PART_FD(PART_ERR)
PART_IN,
-# define CH_IN_FD ch_part[PART_IN].ch_fd
+# define CH_IN_FD CH_PART_FD(PART_IN)
#endif
PART_COUNT
} ch_part_T;
* - add 't' to mode()
* - set 'filetype' to "terminal"?
* - use win_del_lines() to make scroll-up efficient.
+ * - Make StatusLineTerm adjust UserN highlighting like StatusLineNC does, see
+ * use of hightlight_stlnc[].
* - implement term_setsize()
* - 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.
+ * - support ":term NONE" to open a terminal with a pty but not running a job
+ * in it. The pty can be passed to gdb to run the executable in.
* - if the job in the terminal does not support the mouse, we can use the
* mouse in the Terminal window for copy/paste.
* - when 'encoding' is not utf-8, or the job is using another encoding, setup
job_T *tl_job;
buf_T *tl_buffer;
+ /* used when tl_job is NULL and only a pty was created */
+ int tl_tty_fd;
+ char_u *tl_tty_name;
+
int tl_terminal_mode;
int tl_channel_closed;
rettv->vval.v_string = vim_strsave(buf->b_term->tl_title);
}
+/*
+ * "term_gettty(buf)" function
+ */
+ void
+f_term_gettty(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars);
+ char_u *p;
+
+ 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 (p != NULL)
+ rettv->vval.v_string = vim_strsave(p);
+}
+
/*
* "term_list()" function
*/
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,
create_vterm(term, rows, cols);
+ /* TODO: if the command is "NONE" only create a pty. */
argvars[0].v_type = VAR_STRING;
argvars[0].vval.v_string = cmd;
setup_job_options(&opt, rows, cols);
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(''))
+ else
+ call assert_equal("", job_info(g:job).tty)
+ endif
call Stop_shell_in_terminal(buf)
call term_wait(buf)
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 846,
/**/
845,
/**/