Patch 8.0.1000
Problem: Cannot open a terminal without running a job in it.
Solution: Make ":terminal NONE" open a terminal with a pty.
Files: src/terminal.c, src/os_unix.c, src/proto/os_unix.pro,
src/channel.c, src/proto/channel.pro, src/structs.h,
src/testdir/test_terminal.vim, src/misc2.c, src/gui_gtk_x11.c
*** ../vim-8.0.0999/src/terminal.c 2017-08-24 21:48:22.536643534 +0200
--- src/terminal.c 2017-08-26 20:35:19.554845869 +0200
***************
*** 38,43 ****
--- 38,44 ----
* 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()
***************
*** 47,52 ****
--- 48,54 ----
* - 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)
***************
*** 62,69 ****
* 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
--- 64,69 ----
***************
*** 163,170 ****
/*
* 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 void term_report_winsize(term_T *term, int rows, int cols);
static void term_free_vterm(term_T *term);
--- 163,170 ----
/*
* Functions with separate implementation for MS-Windows and Unix-like
systems.
*/
! 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);
***************
*** 256,261 ****
--- 256,262 ----
win_T *old_curwin = curwin;
term_T *term;
buf_T *old_curbuf = NULL;
+ int res;
if (check_restricted() || check_secure())
return;
***************
*** 355,361 ****
--- 356,368 ----
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)
***************
*** 400,408 ****
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)
{
/* Get and remember the size we ended up with. Update the pty. */
vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
--- 407,421 ----
set_term_and_win_size(term);
setup_job_options(opt, term->tl_rows, term->tl_cols);
! /* 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);
***************
*** 553,559 ****
if (term->tl_job != NULL)
{
if (term->tl_job->jv_status != JOB_ENDED
! && term->tl_job->jv_status != JOB_FAILED)
job_stop(term->tl_job, NULL, "kill");
job_unref(term->tl_job);
}
--- 566,573 ----
if (term->tl_job != NULL)
{
if (term->tl_job->jv_status != JOB_ENDED
! && 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);
}
***************
*** 839,846 ****
* 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);
}
/*
--- 853,861 ----
* race condition when updating the title. */
return term != NULL
&& term->tl_job != NULL
! && channel_is_open(term->tl_job->jv_channel)
! && (term->tl_job->jv_status == JOB_STARTED
! || term->tl_job->jv_channel->ch_keep_open);
}
/*
***************
*** 2842,2850 ****
ch_log(NULL, "term_wait(): no job to wait for");
return;
}
/* Get the job status, this will detect a job that finished. */
! if (STRCMP(job_status(buf->b_term->tl_job), "dead") == 0)
{
/* The job is dead, keep reading channel I/O until the channel is
* closed. */
--- 2857,2870 ----
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 ((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. */
***************
*** 2976,2983 ****
static int
term_and_job_init(
term_T *term,
- int rows,
- int cols,
typval_T *argvar,
jobopt_T *opt)
{
--- 2996,3001 ----
***************
*** 3023,3029 ****
if (term->tl_winpty_config == NULL)
goto failed;
! winpty_config_set_initial_size(term->tl_winpty_config, cols, rows);
term->tl_winpty = winpty_open(term->tl_winpty_config, &winpty_err);
if (term->tl_winpty == NULL)
goto failed;
--- 3041,3048 ----
if (term->tl_winpty_config == NULL)
goto failed;
! 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;
***************
*** 3085,3091 ****
winpty_spawn_config_free(spawn_config);
vim_free(cmd_wchar);
! create_vterm(term, rows, cols);
channel_set_job(channel, job, opt);
job_set_options(job, opt);
--- 3104,3110 ----
winpty_spawn_config_free(spawn_config);
vim_free(cmd_wchar);
! create_vterm(term, term->tl_rows, term->tl_cols);
channel_set_job(channel, job, opt);
job_set_options(job, opt);
***************
*** 3137,3142 ****
--- 3156,3168 ----
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".
*/
***************
*** 3185,3196 ****
static int
term_and_job_init(
term_T *term,
- int rows,
- int cols,
typval_T *argvar,
jobopt_T *opt)
{
! create_vterm(term, rows, cols);
/* TODO: if the command is "NONE" only create a pty. */
term->tl_job = job_start(argvar, opt);
--- 3211,3220 ----
static int
term_and_job_init(
term_T *term,
typval_T *argvar,
jobopt_T *opt)
{
! 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);
***************
*** 3202,3207 ****
--- 3226,3251 ----
&& 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".
*/
*** ../vim-8.0.0999/src/os_unix.c 2017-08-21 21:07:24.478671491 +0200
--- src/os_unix.c 2017-08-26 19:57:33.001144732 +0200
***************
*** 5466,5472 ****
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]);
--- 5466,5472 ----
job->jv_channel = channel; /* ch_refcount was set above */
if (pty_master_fd >= 0)
! close(pty_slave_fd); /* not used in the parent */
/* close child stdin, stdout and stderr */
if (!use_file_for_in && fd_in[0] >= 0)
close(fd_in[0]);
***************
*** 5669,5674 ****
--- 5669,5697 ----
}
#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.
* In cooked mode we should get SIGINT, no need to check.
*** ../vim-8.0.0999/src/proto/os_unix.pro 2017-08-13 20:06:14.963846989
+0200
--- src/proto/os_unix.pro 2017-08-26 18:08:40.619342952 +0200
***************
*** 66,71 ****
--- 66,72 ----
job_T *mch_detect_ended_job(job_T *job_list);
int mch_signal_job(job_T *job, char_u *how);
void mch_clear_job(job_T *job);
+ int mch_create_pty_channel(job_T *job, jobopt_T *options);
void mch_breakcheck(int force);
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);
*** ../vim-8.0.0999/src/channel.c 2017-08-19 21:26:40.081756056 +0200
--- src/channel.c 2017-08-26 22:00:19.042412608 +0200
***************
*** 503,508 ****
--- 503,512 ----
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. */
***************
*** 548,556 ****
{
if (channel->CH_SOCK_FD != INVALID_FD)
channel_gui_register_one(channel, PART_SOCK);
! if (channel->CH_OUT_FD != INVALID_FD)
channel_gui_register_one(channel, PART_OUT);
! if (channel->CH_ERR_FD != INVALID_FD)
channel_gui_register_one(channel, PART_ERR);
}
--- 552,563 ----
{
if (channel->CH_SOCK_FD != INVALID_FD)
channel_gui_register_one(channel, PART_SOCK);
! 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
! && channel->CH_ERR_FD != channel->CH_SOCK_FD
! && channel->CH_ERR_FD != channel->CH_OUT_FD)
channel_gui_register_one(channel, PART_ERR);
}
***************
*** 3247,3257 ****
/* Reading a disconnection (readlen == 0), or an error. */
if (readlen <= 0)
! 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)
gtk_main_quit();
#endif
}
--- 3254,3266 ----
/* Reading a disconnection (readlen == 0), or an error. */
if (readlen <= 0)
! {
! if (!channel->ch_keep_open)
! ch_close_part_on_error(channel, part, (len < 0), func);
! }
#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 */
gtk_main_quit();
#endif
}
***************
*** 3509,3521 ****
}
# endif
! # if defined(WIN32) || defined(PROTO)
/*
* Check the channels for anything that is ready to be read.
* The data is put in the read queue.
*/
void
! channel_handle_events(void)
{
channel_T *channel;
ch_part_T part;
--- 3518,3531 ----
}
# endif
! # 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(int only_keep_open)
{
channel_T *channel;
ch_part_T part;
***************
*** 3523,3528 ****
--- 3533,3541 ----
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)
{
*** ../vim-8.0.0999/src/proto/channel.pro 2017-08-18 20:50:26.441516959
+0200
--- src/proto/channel.pro 2017-08-26 20:29:32.725031621 +0200
***************
*** 34,42 ****
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);
channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
! void channel_handle_events(void);
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);
void ch_expr_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);
--- 34,42 ----
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);
channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
! void channel_handle_events(int only_keep_open);
void channel_set_nonblock(channel_T *channel, ch_part_T part);
! 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_raw_common(typval_T *argvars, typval_T *rettv, int eval);
int channel_poll_setup(int nfd_in, void *fds_in);
*** ../vim-8.0.0999/src/structs.h 2017-08-18 20:50:26.441516959 +0200
--- src/structs.h 2017-08-26 18:27:54.471843502 +0200
***************
*** 1656,1661 ****
--- 1656,1662 ----
char_u *ch_close_cb; /* call when channel is closed */
partial_T *ch_close_partial;
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
* count as a reference to avoid a circular
*** ../vim-8.0.0999/src/testdir/test_terminal.vim 2017-08-25
23:22:01.689645666 +0200
--- src/testdir/test_terminal.vim 2017-08-26 20:03:16.958970560 +0200
***************
*** 505,507 ****
--- 505,527 ----
bwipe!
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
*** ../vim-8.0.0999/src/misc2.c 2017-08-19 15:05:16.048003367 +0200
--- src/misc2.c 2017-08-26 20:30:31.316662527 +0200
***************
*** 6321,6327 ****
{
/* For Win32 mch_breakcheck() does not check for input, do it here. */
# if defined(WIN32) && defined(FEAT_JOB_CHANNEL)
! channel_handle_events();
# endif
# ifdef FEAT_NETBEANS_INTG
--- 6321,6327 ----
{
/* For Win32 mch_breakcheck() does not check for input, do it here. */
# if defined(WIN32) && defined(FEAT_JOB_CHANNEL)
! channel_handle_events(FALSE);
# endif
# ifdef FEAT_NETBEANS_INTG
*** ../vim-8.0.0999/src/gui_gtk_x11.c 2017-07-23 16:45:05.669761183 +0200
--- src/gui_gtk_x11.c 2017-08-26 20:32:13.764017011 +0200
***************
*** 6643,6648 ****
--- 6643,6654 ----
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 FEAT_TIMERS
did_add_timer = FALSE;
*** ../vim-8.0.0999/src/version.c 2017-08-26 17:48:57.582995164 +0200
--- src/version.c 2017-08-26 18:43:27.801784838 +0200
***************
*** 771,772 ****
--- 771,774 ----
{ /* Add new patch number below this line */
+ /**/
+ 1000,
/**/
--
I have a drinking problem -- I don't have a drink!
/// Bram Moolenaar -- [email protected] -- 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 ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.