if (!CH_HAS_GUI)
return;
+ /* gets stuck in handling events for a not connected channel */
+ if (channel->ch_keep_open)
+ return;
+
# ifdef FEAT_GUI_X11
/* Tell notifier we are interested in being called
* when there is input on the editor connection socket. */
{
if (channel->CH_SOCK_FD != INVALID_FD)
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);
- 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);
}
/* Reading a disconnection (readlen == 0), or an error. */
if (readlen <= 0)
- ch_close_part_on_error(channel, part, (len < 0), func);
-
+ {
+ if (!channel->ch_keep_open)
+ ch_close_part_on_error(channel, part, (len < 0), func);
+ }
#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
- /* signal the main loop that there is something to read */
- if (CH_HAS_GUI && gtk_main_level() > 0)
+ else if (CH_HAS_GUI && gtk_main_level() > 0)
+ /* signal the main loop that there is something to read */
gtk_main_quit();
#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.
* The data is put in the read queue.
+ * if "only_keep_open" is TRUE only check channels where ch_keep_open is set.
*/
void
-channel_handle_events(void)
+channel_handle_events(int only_keep_open)
{
channel_T *channel;
ch_part_T part;
for (channel = first_channel; channel != NULL; channel = channel->ch_next)
{
+ if (only_keep_open && !channel->ch_keep_open)
+ continue;
+
/* check the socket and pipes */
for (part = PART_SOCK; part < PART_IN; ++part)
{
* in tl_scrollback are no longer used.
*
* TODO:
+ * - ":term NONE" does not work in MS-Windows.
* - better check for blinking - reply from Thomas Dickey Aug 22
* - test for writing lines to terminal job does not work on MS-Windows
* - implement term_setsize()
* - do not set bufhidden to "hide"? works like a buffer with changes.
* document that CTRL-W :hide can be used.
* - 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
* changes to "!shell".
* (justrajdeep, 2017 Aug 22)
* shell writing stderr to a file or buffer
* - For the GUI fill termios with default values, perhaps like pangoterm:
* 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
* mouse in the Terminal window for copy/paste.
* - when 'encoding' is not utf-8, or the job is using another encoding, setup
/*
* Functions with separate implementation for MS-Windows and Unix-like systems.
*/
-static int term_and_job_init(term_T *term, int rows, int cols,
- typval_T *argvar, jobopt_T *opt);
+static int term_and_job_init(term_T *term, 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_free_vterm(term_T *term);
win_T *old_curwin = curwin;
term_T *term;
buf_T *old_curbuf = NULL;
+ int res;
if (check_restricted() || check_secure())
return;
char_u *cmd, *p;
if (argvar->v_type == VAR_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
|| argvar->vval.v_list == NULL
|| argvar->vval.v_list->lv_len < 1)
set_term_and_win_size(term);
setup_job_options(opt, term->tl_rows, term->tl_cols);
- /* System dependent: setup the vterm and start the job in it. */
- if (term_and_job_init(term, term->tl_rows, term->tl_cols, argvar, opt)
- == OK)
+ /* System dependent: setup the vterm and maybe start the job in it. */
+ if (argvar->v_type == VAR_STRING
+ && 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. */
vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
if (term->tl_job != NULL)
{
if (term->tl_job->jv_status != JOB_ENDED
- && term->tl_job->jv_status != JOB_FAILED)
+ && term->tl_job->jv_status != JOB_FINISHED
+ && term->tl_job->jv_status != JOB_FAILED)
job_stop(term->tl_job, NULL, "kill");
job_unref(term->tl_job);
}
* race condition when updating the title. */
return term != 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);
}
/*
ch_log(NULL, "term_wait(): no job to wait for");
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. */
- 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
* closed. */
static int
term_and_job_init(
term_T *term,
- int rows,
- int cols,
typval_T *argvar,
jobopt_T *opt)
{
if (term->tl_winpty_config == NULL)
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);
if (term->tl_winpty == NULL)
goto failed;
winpty_spawn_config_free(spawn_config);
vim_free(cmd_wchar);
- create_vterm(term, rows, cols);
+ create_vterm(term, term->tl_rows, term->tl_cols);
channel_set_job(channel, job, opt);
job_set_options(job, opt);
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".
*/
static int
term_and_job_init(
term_T *term,
- int rows,
- int cols,
typval_T *argvar,
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. */
term->tl_job = job_start(argvar, opt);
&& 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".
*/