forked from aniani/vim
patch 8.0.1000: cannot open a terminal without running a job in it
Problem: Cannot open a terminal without running a job in it. Solution: Make ":terminal NONE" open a terminal with a pty.
This commit is contained in:
@@ -503,6 +503,10 @@ channel_gui_register_one(channel_T *channel, ch_part_T part)
|
|||||||
if (!CH_HAS_GUI)
|
if (!CH_HAS_GUI)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* gets stuck in handling events for a not connected channel */
|
||||||
|
if (channel->ch_keep_open)
|
||||||
|
return;
|
||||||
|
|
||||||
# ifdef FEAT_GUI_X11
|
# ifdef FEAT_GUI_X11
|
||||||
/* Tell notifier we are interested in being called
|
/* Tell notifier we are interested in being called
|
||||||
* when there is input on the editor connection socket. */
|
* when there is input on the editor connection socket. */
|
||||||
@@ -548,9 +552,12 @@ channel_gui_register(channel_T *channel)
|
|||||||
{
|
{
|
||||||
if (channel->CH_SOCK_FD != INVALID_FD)
|
if (channel->CH_SOCK_FD != INVALID_FD)
|
||||||
channel_gui_register_one(channel, PART_SOCK);
|
channel_gui_register_one(channel, PART_SOCK);
|
||||||
if (channel->CH_OUT_FD != INVALID_FD)
|
if (channel->CH_OUT_FD != INVALID_FD
|
||||||
|
&& channel->CH_OUT_FD != channel->CH_SOCK_FD)
|
||||||
channel_gui_register_one(channel, PART_OUT);
|
channel_gui_register_one(channel, PART_OUT);
|
||||||
if (channel->CH_ERR_FD != INVALID_FD)
|
if (channel->CH_ERR_FD != INVALID_FD
|
||||||
|
&& channel->CH_ERR_FD != channel->CH_SOCK_FD
|
||||||
|
&& channel->CH_ERR_FD != channel->CH_OUT_FD)
|
||||||
channel_gui_register_one(channel, PART_ERR);
|
channel_gui_register_one(channel, PART_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3247,11 +3254,13 @@ channel_read(channel_T *channel, ch_part_T part, char *func)
|
|||||||
|
|
||||||
/* Reading a disconnection (readlen == 0), or an error. */
|
/* Reading a disconnection (readlen == 0), or an error. */
|
||||||
if (readlen <= 0)
|
if (readlen <= 0)
|
||||||
|
{
|
||||||
|
if (!channel->ch_keep_open)
|
||||||
ch_close_part_on_error(channel, part, (len < 0), func);
|
ch_close_part_on_error(channel, part, (len < 0), func);
|
||||||
|
}
|
||||||
#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
|
#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
|
||||||
|
else if (CH_HAS_GUI && gtk_main_level() > 0)
|
||||||
/* signal the main loop that there is something to read */
|
/* signal the main loop that there is something to read */
|
||||||
if (CH_HAS_GUI && gtk_main_level() > 0)
|
|
||||||
gtk_main_quit();
|
gtk_main_quit();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3509,13 +3518,14 @@ channel_fd2channel(sock_T fd, ch_part_T *partp)
|
|||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(WIN32) || defined(PROTO)
|
# if defined(WIN32) || defined(FEAT_GUI) || defined(PROTO)
|
||||||
/*
|
/*
|
||||||
* Check the channels for anything that is ready to be read.
|
* Check the channels for anything that is ready to be read.
|
||||||
* The data is put in the read queue.
|
* The data is put in the read queue.
|
||||||
|
* if "only_keep_open" is TRUE only check channels where ch_keep_open is set.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
channel_handle_events(void)
|
channel_handle_events(int only_keep_open)
|
||||||
{
|
{
|
||||||
channel_T *channel;
|
channel_T *channel;
|
||||||
ch_part_T part;
|
ch_part_T part;
|
||||||
@@ -3523,6 +3533,9 @@ channel_handle_events(void)
|
|||||||
|
|
||||||
for (channel = first_channel; channel != NULL; channel = channel->ch_next)
|
for (channel = first_channel; channel != NULL; channel = channel->ch_next)
|
||||||
{
|
{
|
||||||
|
if (only_keep_open && !channel->ch_keep_open)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* check the socket and pipes */
|
/* check the socket and pipes */
|
||||||
for (part = PART_SOCK; part < PART_IN; ++part)
|
for (part = PART_SOCK; part < PART_IN; ++part)
|
||||||
{
|
{
|
||||||
|
@@ -6643,6 +6643,12 @@ gui_mch_wait_for_chars(long wtime)
|
|||||||
focus = gui.in_focus;
|
focus = gui.in_focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# if defined(FEAT_JOB_CHANNEL)
|
||||||
|
/* Using an event handler for a channel that may be disconnected does
|
||||||
|
* not work, it hangs. Instead poll for messages. */
|
||||||
|
channel_handle_events(TRUE);
|
||||||
|
# endif
|
||||||
|
|
||||||
#ifdef MESSAGE_QUEUE
|
#ifdef MESSAGE_QUEUE
|
||||||
# ifdef FEAT_TIMERS
|
# ifdef FEAT_TIMERS
|
||||||
did_add_timer = FALSE;
|
did_add_timer = FALSE;
|
||||||
|
@@ -6321,7 +6321,7 @@ parse_queued_messages(void)
|
|||||||
{
|
{
|
||||||
/* For Win32 mch_breakcheck() does not check for input, do it here. */
|
/* For Win32 mch_breakcheck() does not check for input, do it here. */
|
||||||
# if defined(WIN32) && defined(FEAT_JOB_CHANNEL)
|
# if defined(WIN32) && defined(FEAT_JOB_CHANNEL)
|
||||||
channel_handle_events();
|
channel_handle_events(FALSE);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef FEAT_NETBEANS_INTG
|
# ifdef FEAT_NETBEANS_INTG
|
||||||
|
@@ -5466,7 +5466,7 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
|
|||||||
job->jv_channel = channel; /* ch_refcount was set above */
|
job->jv_channel = channel; /* ch_refcount was set above */
|
||||||
|
|
||||||
if (pty_master_fd >= 0)
|
if (pty_master_fd >= 0)
|
||||||
close(pty_slave_fd); /* duped above */
|
close(pty_slave_fd); /* not used in the parent */
|
||||||
/* close child stdin, stdout and stderr */
|
/* close child stdin, stdout and stderr */
|
||||||
if (!use_file_for_in && fd_in[0] >= 0)
|
if (!use_file_for_in && fd_in[0] >= 0)
|
||||||
close(fd_in[0]);
|
close(fd_in[0]);
|
||||||
@@ -5669,6 +5669,29 @@ mch_clear_job(job_T *job)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(FEAT_TERMINAL) || defined(PROTO)
|
||||||
|
int
|
||||||
|
mch_create_pty_channel(job_T *job, jobopt_T *options)
|
||||||
|
{
|
||||||
|
int pty_master_fd = -1;
|
||||||
|
int pty_slave_fd = -1;
|
||||||
|
channel_T *channel;
|
||||||
|
|
||||||
|
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
|
||||||
|
close(pty_slave_fd);
|
||||||
|
|
||||||
|
channel = add_channel();
|
||||||
|
if (channel == NULL)
|
||||||
|
return FAIL;
|
||||||
|
job->jv_channel = channel; /* ch_refcount was set by add_channel() */
|
||||||
|
channel->ch_keep_open = TRUE;
|
||||||
|
|
||||||
|
channel_set_pipes(channel, pty_master_fd, pty_master_fd, pty_master_fd);
|
||||||
|
channel_set_job(channel, job, options);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for CTRL-C typed by reading all available characters.
|
* Check for CTRL-C typed by reading all available characters.
|
||||||
* In cooked mode we should get SIGINT, no need to check.
|
* In cooked mode we should get SIGINT, no need to check.
|
||||||
|
@@ -34,9 +34,9 @@ void channel_free_all(void);
|
|||||||
char_u *channel_read_block(channel_T *channel, ch_part_T part, int timeout);
|
char_u *channel_read_block(channel_T *channel, ch_part_T part, int timeout);
|
||||||
void common_channel_read(typval_T *argvars, typval_T *rettv, int raw);
|
void common_channel_read(typval_T *argvars, typval_T *rettv, int raw);
|
||||||
channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
|
channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
|
||||||
void channel_handle_events(void);
|
void channel_handle_events(int only_keep_open);
|
||||||
void channel_set_nonblock(channel_T *channel, ch_part_T part);
|
void channel_set_nonblock(channel_T *channel, ch_part_T part);
|
||||||
int channel_send(channel_T *channel, ch_part_T part, char_u *buf, int len, char *fun);
|
int channel_send(channel_T *channel, ch_part_T part, char_u *buf_arg, int len_arg, char *fun);
|
||||||
void ch_expr_common(typval_T *argvars, typval_T *rettv, int eval);
|
void ch_expr_common(typval_T *argvars, typval_T *rettv, int eval);
|
||||||
void ch_raw_common(typval_T *argvars, typval_T *rettv, int eval);
|
void ch_raw_common(typval_T *argvars, typval_T *rettv, int eval);
|
||||||
int channel_poll_setup(int nfd_in, void *fds_in);
|
int channel_poll_setup(int nfd_in, void *fds_in);
|
||||||
|
@@ -66,6 +66,7 @@ char *mch_job_status(job_T *job);
|
|||||||
job_T *mch_detect_ended_job(job_T *job_list);
|
job_T *mch_detect_ended_job(job_T *job_list);
|
||||||
int mch_signal_job(job_T *job, char_u *how);
|
int mch_signal_job(job_T *job, char_u *how);
|
||||||
void mch_clear_job(job_T *job);
|
void mch_clear_job(job_T *job);
|
||||||
|
int mch_create_pty_channel(job_T *job, jobopt_T *options);
|
||||||
void mch_breakcheck(int force);
|
void mch_breakcheck(int force);
|
||||||
int mch_expandpath(garray_T *gap, char_u *path, int flags);
|
int mch_expandpath(garray_T *gap, char_u *path, int flags);
|
||||||
int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags);
|
int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags);
|
||||||
|
@@ -1656,6 +1656,7 @@ struct channel_S {
|
|||||||
char_u *ch_close_cb; /* call when channel is closed */
|
char_u *ch_close_cb; /* call when channel is closed */
|
||||||
partial_T *ch_close_partial;
|
partial_T *ch_close_partial;
|
||||||
int ch_drop_never;
|
int ch_drop_never;
|
||||||
|
int ch_keep_open; /* do not close on read error */
|
||||||
|
|
||||||
job_T *ch_job; /* Job that uses this channel; this does not
|
job_T *ch_job; /* Job that uses this channel; this does not
|
||||||
* count as a reference to avoid a circular
|
* count as a reference to avoid a circular
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
* in tl_scrollback are no longer used.
|
* in tl_scrollback are no longer used.
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
|
* - ":term NONE" does not work in MS-Windows.
|
||||||
* - better check for blinking - reply from Thomas Dickey Aug 22
|
* - better check for blinking - reply from Thomas Dickey Aug 22
|
||||||
* - test for writing lines to terminal job does not work on MS-Windows
|
* - test for writing lines to terminal job does not work on MS-Windows
|
||||||
* - implement term_setsize()
|
* - implement term_setsize()
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
* - do not set bufhidden to "hide"? works like a buffer with changes.
|
* - do not set bufhidden to "hide"? works like a buffer with changes.
|
||||||
* document that CTRL-W :hide can be used.
|
* document that CTRL-W :hide can be used.
|
||||||
* - GUI: when using tabs, focus in terminal, click on tab does not work.
|
* - GUI: when using tabs, focus in terminal, click on tab does not work.
|
||||||
|
* - When $HOME was set by Vim (MS-Windows), do not pass it to the job.
|
||||||
* - GUI: when 'confirm' is set and trying to exit Vim, dialog offers to save
|
* - GUI: when 'confirm' is set and trying to exit Vim, dialog offers to save
|
||||||
* changes to "!shell".
|
* changes to "!shell".
|
||||||
* (justrajdeep, 2017 Aug 22)
|
* (justrajdeep, 2017 Aug 22)
|
||||||
@@ -62,8 +64,6 @@
|
|||||||
* shell writing stderr to a file or buffer
|
* shell writing stderr to a file or buffer
|
||||||
* - For the GUI fill termios with default values, perhaps like pangoterm:
|
* - For the GUI fill termios with default values, perhaps like pangoterm:
|
||||||
* http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134
|
* http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134
|
||||||
* - 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
|
* - if the job in the terminal does not support the mouse, we can use the
|
||||||
* mouse in the Terminal window for copy/paste.
|
* mouse in the Terminal window for copy/paste.
|
||||||
* - when 'encoding' is not utf-8, or the job is using another encoding, setup
|
* - when 'encoding' is not utf-8, or the job is using another encoding, setup
|
||||||
@@ -163,8 +163,8 @@ static term_T *in_terminal_loop = NULL;
|
|||||||
/*
|
/*
|
||||||
* Functions with separate implementation for MS-Windows and Unix-like systems.
|
* Functions with separate implementation for MS-Windows and Unix-like systems.
|
||||||
*/
|
*/
|
||||||
static int term_and_job_init(term_T *term, int rows, int cols,
|
static int term_and_job_init(term_T *term, typval_T *argvar, jobopt_T *opt);
|
||||||
typval_T *argvar, jobopt_T *opt);
|
static int create_pty_only(term_T *term, jobopt_T *opt);
|
||||||
static void term_report_winsize(term_T *term, int rows, int cols);
|
static void term_report_winsize(term_T *term, int rows, int cols);
|
||||||
static void term_free_vterm(term_T *term);
|
static void term_free_vterm(term_T *term);
|
||||||
|
|
||||||
@@ -256,6 +256,7 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
|
|||||||
win_T *old_curwin = curwin;
|
win_T *old_curwin = curwin;
|
||||||
term_T *term;
|
term_T *term;
|
||||||
buf_T *old_curbuf = NULL;
|
buf_T *old_curbuf = NULL;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (check_restricted() || check_secure())
|
if (check_restricted() || check_secure())
|
||||||
return;
|
return;
|
||||||
@@ -355,7 +356,13 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
|
|||||||
char_u *cmd, *p;
|
char_u *cmd, *p;
|
||||||
|
|
||||||
if (argvar->v_type == VAR_STRING)
|
if (argvar->v_type == VAR_STRING)
|
||||||
|
{
|
||||||
cmd = argvar->vval.v_string;
|
cmd = argvar->vval.v_string;
|
||||||
|
if (cmd == NULL)
|
||||||
|
cmd = (char_u *)"";
|
||||||
|
else if (STRCMP(cmd, "NONE") == 0)
|
||||||
|
cmd = (char_u *)"pty";
|
||||||
|
}
|
||||||
else if (argvar->v_type != VAR_LIST
|
else if (argvar->v_type != VAR_LIST
|
||||||
|| argvar->vval.v_list == NULL
|
|| argvar->vval.v_list == NULL
|
||||||
|| argvar->vval.v_list->lv_len < 1)
|
|| argvar->vval.v_list->lv_len < 1)
|
||||||
@@ -400,9 +407,15 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
|
|||||||
set_term_and_win_size(term);
|
set_term_and_win_size(term);
|
||||||
setup_job_options(opt, term->tl_rows, term->tl_cols);
|
setup_job_options(opt, term->tl_rows, term->tl_cols);
|
||||||
|
|
||||||
/* System dependent: setup the vterm and start the job in it. */
|
/* System dependent: setup the vterm and maybe start the job in it. */
|
||||||
if (term_and_job_init(term, term->tl_rows, term->tl_cols, argvar, opt)
|
if (argvar->v_type == VAR_STRING
|
||||||
== OK)
|
&& argvar->vval.v_string != NULL
|
||||||
|
&& STRCMP(argvar->vval.v_string, "NONE") == 0)
|
||||||
|
res = create_pty_only(term, opt);
|
||||||
|
else
|
||||||
|
res = term_and_job_init(term, argvar, opt);
|
||||||
|
|
||||||
|
if (res == OK)
|
||||||
{
|
{
|
||||||
/* Get and remember the size we ended up with. Update the pty. */
|
/* Get and remember the size we ended up with. Update the pty. */
|
||||||
vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
|
vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
|
||||||
@@ -553,6 +566,7 @@ free_terminal(buf_T *buf)
|
|||||||
if (term->tl_job != NULL)
|
if (term->tl_job != NULL)
|
||||||
{
|
{
|
||||||
if (term->tl_job->jv_status != JOB_ENDED
|
if (term->tl_job->jv_status != JOB_ENDED
|
||||||
|
&& term->tl_job->jv_status != JOB_FINISHED
|
||||||
&& term->tl_job->jv_status != JOB_FAILED)
|
&& term->tl_job->jv_status != JOB_FAILED)
|
||||||
job_stop(term->tl_job, NULL, "kill");
|
job_stop(term->tl_job, NULL, "kill");
|
||||||
job_unref(term->tl_job);
|
job_unref(term->tl_job);
|
||||||
@@ -839,8 +853,9 @@ term_job_running(term_T *term)
|
|||||||
* race condition when updating the title. */
|
* race condition when updating the title. */
|
||||||
return term != NULL
|
return term != NULL
|
||||||
&& term->tl_job != NULL
|
&& term->tl_job != NULL
|
||||||
&& term->tl_job->jv_status == JOB_STARTED
|
&& channel_is_open(term->tl_job->jv_channel)
|
||||||
&& channel_is_open(term->tl_job->jv_channel);
|
&& (term->tl_job->jv_status == JOB_STARTED
|
||||||
|
|| term->tl_job->jv_channel->ch_keep_open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2842,9 +2857,14 @@ f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
ch_log(NULL, "term_wait(): no job to wait for");
|
ch_log(NULL, "term_wait(): no job to wait for");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (buf->b_term->tl_job->jv_channel == NULL)
|
||||||
|
/* channel is closed, nothing to do */
|
||||||
|
return;
|
||||||
|
|
||||||
/* Get the job status, this will detect a job that finished. */
|
/* Get the job status, this will detect a job that finished. */
|
||||||
if (STRCMP(job_status(buf->b_term->tl_job), "dead") == 0)
|
if ((buf->b_term->tl_job->jv_channel == NULL
|
||||||
|
|| !buf->b_term->tl_job->jv_channel->ch_keep_open)
|
||||||
|
&& STRCMP(job_status(buf->b_term->tl_job), "dead") == 0)
|
||||||
{
|
{
|
||||||
/* The job is dead, keep reading channel I/O until the channel is
|
/* The job is dead, keep reading channel I/O until the channel is
|
||||||
* closed. */
|
* closed. */
|
||||||
@@ -2976,8 +2996,6 @@ dyn_winpty_init(int verbose)
|
|||||||
static int
|
static int
|
||||||
term_and_job_init(
|
term_and_job_init(
|
||||||
term_T *term,
|
term_T *term,
|
||||||
int rows,
|
|
||||||
int cols,
|
|
||||||
typval_T *argvar,
|
typval_T *argvar,
|
||||||
jobopt_T *opt)
|
jobopt_T *opt)
|
||||||
{
|
{
|
||||||
@@ -3023,7 +3041,8 @@ term_and_job_init(
|
|||||||
if (term->tl_winpty_config == NULL)
|
if (term->tl_winpty_config == NULL)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
winpty_config_set_initial_size(term->tl_winpty_config, cols, rows);
|
winpty_config_set_initial_size(term->tl_winpty_config,
|
||||||
|
term->tl_cols, term->tl_rows);
|
||||||
term->tl_winpty = winpty_open(term->tl_winpty_config, &winpty_err);
|
term->tl_winpty = winpty_open(term->tl_winpty_config, &winpty_err);
|
||||||
if (term->tl_winpty == NULL)
|
if (term->tl_winpty == NULL)
|
||||||
goto failed;
|
goto failed;
|
||||||
@@ -3085,7 +3104,7 @@ term_and_job_init(
|
|||||||
winpty_spawn_config_free(spawn_config);
|
winpty_spawn_config_free(spawn_config);
|
||||||
vim_free(cmd_wchar);
|
vim_free(cmd_wchar);
|
||||||
|
|
||||||
create_vterm(term, rows, cols);
|
create_vterm(term, term->tl_rows, term->tl_cols);
|
||||||
|
|
||||||
channel_set_job(channel, job, opt);
|
channel_set_job(channel, job, opt);
|
||||||
job_set_options(job, opt);
|
job_set_options(job, opt);
|
||||||
@@ -3137,6 +3156,13 @@ failed:
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
create_pty_only(term_T *term, jobopt_T *opt)
|
||||||
|
{
|
||||||
|
/* TODO: implement this */
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the terminal emulator part of "term".
|
* Free the terminal emulator part of "term".
|
||||||
*/
|
*/
|
||||||
@@ -3185,12 +3211,10 @@ terminal_enabled(void)
|
|||||||
static int
|
static int
|
||||||
term_and_job_init(
|
term_and_job_init(
|
||||||
term_T *term,
|
term_T *term,
|
||||||
int rows,
|
|
||||||
int cols,
|
|
||||||
typval_T *argvar,
|
typval_T *argvar,
|
||||||
jobopt_T *opt)
|
jobopt_T *opt)
|
||||||
{
|
{
|
||||||
create_vterm(term, rows, cols);
|
create_vterm(term, term->tl_rows, term->tl_cols);
|
||||||
|
|
||||||
/* TODO: if the command is "NONE" only create a pty. */
|
/* TODO: if the command is "NONE" only create a pty. */
|
||||||
term->tl_job = job_start(argvar, opt);
|
term->tl_job = job_start(argvar, opt);
|
||||||
@@ -3202,6 +3226,26 @@ term_and_job_init(
|
|||||||
&& term->tl_job->jv_status != JOB_FAILED ? OK : FAIL;
|
&& term->tl_job->jv_status != JOB_FAILED ? OK : FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
create_pty_only(term_T *term, jobopt_T *opt)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
create_vterm(term, term->tl_rows, term->tl_cols);
|
||||||
|
|
||||||
|
term->tl_job = job_alloc();
|
||||||
|
if (term->tl_job == NULL)
|
||||||
|
return FAIL;
|
||||||
|
++term->tl_job->jv_refcount;
|
||||||
|
|
||||||
|
/* behave like the job is already finished */
|
||||||
|
term->tl_job->jv_status = JOB_FINISHED;
|
||||||
|
|
||||||
|
ret = mch_create_pty_channel(term->tl_job, opt);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the terminal emulator part of "term".
|
* Free the terminal emulator part of "term".
|
||||||
*/
|
*/
|
||||||
|
@@ -505,3 +505,23 @@ func Test_terminal_write_stdin()
|
|||||||
|
|
||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_terminal_no_cmd()
|
||||||
|
" Todo: make this work on all systems.
|
||||||
|
if !has('unix')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
" Todo: make this work in the GUI
|
||||||
|
if !has('gui_running')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let buf = term_start('NONE', {})
|
||||||
|
call assert_notequal(0, buf)
|
||||||
|
|
||||||
|
let pty = job_info(term_getjob(buf))['tty']
|
||||||
|
call assert_notequal('', pty)
|
||||||
|
call system('echo "look here" > ' . pty)
|
||||||
|
call term_wait(buf)
|
||||||
|
call assert_equal('look here', term_getline(buf, 1))
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
@@ -769,6 +769,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1000,
|
||||||
/**/
|
/**/
|
||||||
999,
|
999,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user