Patch 8.0.0803
Problem: Terminal window functions not yet implemented.
Solution: Implement several functions. Add a first test. (Yasuhiro
Matsumoto, closes #1871)
Files: runtime/doc/eval.txt, src/Makefile, src/evalfunc.c,
src/proto/evalfunc.pro, src/proto/terminal.pro, src/terminal.c,
src/testdir/Make_all.mak, src/testdir/test_terminal.vim
*** ../vim-8.0.0802/runtime/doc/eval.txt 2017-07-28 16:46:36.221711738
+0200
--- runtime/doc/eval.txt 2017-07-29 17:46:29.565023838 +0200
***************
*** 2369,2374 ****
--- 2369,2383 ----
tan({expr}) Float tangent of {expr}
tanh({expr}) Float hyperbolic tangent of {expr}
tempname() String name for a temporary file
+ term_getattr({attr}, {what} Number get the value of attribute {what}
+ term_getjob({buf}) Job get the job associated with a terminal
+ term_getline({buf}, {row}) String get a line of text from a terminal
+ term_getsize({buf}) List get the size 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
+ term_start({cmd}, {options}) Job open a terminal window and run a job
+ term_wait({buf}) Number wait for screen to be updated
test_alloc_fail({id}, {countdown}, {repeat})
none make memory allocation fail
test_autochdir() none enable 'autochdir' during startup
***************
*** 7884,7889 ****
--- 7901,7972 ----
For MS-Windows forward slashes are used when the 'shellslash'
option is set or when 'shellcmdflag' starts with '-'.
+ term_getattr({attr}, {what}) *term_getattr()*
+ Given {attr}, a value returned by term_scrape() in the "attr"
+ item, return whether {what} is on. {what} can be one of:
+ bold
+ italic
+ underline
+ strike
+ reverse
+
+ term_getjob({buf}) *term_getjob()*
+ Get the Job associated with terminal window {buf}.
+ {buf} is used as with |term_getsize()|.
+
+ term_getline({buf}, {row}) *term_getline()*
+ Get a line of text from the terminal window of {buf}.
+ {buf} is used as with |term_getsize()|.
+
+ The first line has {row} zero. When {row} is invalid an empty
+ string is returned.
+
+ term_getsize({buf}) *term_getsize()*
+ Get the size of terminal {buf}. Returns a list with two
+ 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.
+
+ term_list(}) *term_list()*
+ Return a list with the buffer numbers of all buffers for
+ terminal windows.
+
+ term_scrape({buf}, {row}) *term_scrape()*
+ Get the contents of {row} of terminal screen of {buf}.
+ For {buf} see |term_getsize()|.
+
+ The first {row} is zero. When {row} is invalid an empty list
+ is returned.
+
+ Return a List containing a Dict for each screen cell:
+ "chars" character(s) at the cell
+ "fg" foreground color as #rrggbb
+ "bg" background color as #rrggbb
+ "attr" attributes of the cell, use term_getattr()
+ to get the individual flags
+ "width" cell width: 1 or 2
+
+ term_sendkeys({buf}, {keys}) *term_sendkeys()*
+ Send keystrokes {keys} to terminal {buf}.
+ {buf} is used as with |term_getsize()|.
+
+ {keys} are translated as key sequences. For example, "\<c-x>"
+ means the character CTRL-X.
+
+ term_start({cmd}, {options}) *term_start()*
+ Open a terminal window and run {cmd} in it.
+
+ Returns the buffer number of the terminal window.
+ When opening the window fails zero is returned.
+
+ {options} are not implemented yet.
+
+ term_wait({buf}) *term_wait()*
+ Wait for pending updates of {buf} to be handled.
+ {buf} is used as with |term_getsize()|.
test_alloc_fail({id}, {countdown}, {repeat}) *test_alloc_fail()*
This is for testing: If the memory allocation with {id} is
*** ../vim-8.0.0802/src/Makefile 2017-07-23 22:01:43.063625375 +0200
--- src/Makefile 2017-07-29 19:59:19.748206500 +0200
***************
*** 2256,2261 ****
--- 2256,2262 ----
test_tagjump \
test_taglist \
test_tcl \
+ test_terminal \
test_textobjects \
test_timers \
test_true_false \
*** ../vim-8.0.0802/src/evalfunc.c 2017-07-28 16:46:36.217711766 +0200
--- src/evalfunc.c 2017-07-29 17:51:30.470869468 +0200
***************
*** 830,835 ****
--- 830,846 ----
{"tanh", 1, 1, f_tanh},
#endif
{"tempname", 0, 0, f_tempname},
+ #ifdef FEAT_TERMINAL
+ {"term_getattr", 2, 2, f_term_getattr},
+ {"term_getjob", 1, 1, f_term_getjob},
+ {"term_getline", 2, 2, f_term_getline},
+ {"term_getsize", 1, 1, f_term_getsize},
+ {"term_list", 0, 0, f_term_list},
+ {"term_scrape", 2, 2, f_term_scrape},
+ {"term_sendkeys", 2, 2, f_term_sendkeys},
+ {"term_start", 1, 2, f_term_start},
+ {"term_wait", 1, 1, f_term_wait},
+ #endif
{"test_alloc_fail", 3, 3, f_test_alloc_fail},
{"test_autochdir", 0, 0, f_test_autochdir},
{"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
***************
*** 1540,1546 ****
/*
* Get buffer by number or pattern.
*/
! static buf_T *
get_buf_tv(typval_T *tv, int curtab_only)
{
char_u *name = tv->vval.v_string;
--- 1551,1557 ----
/*
* Get buffer by number or pattern.
*/
! buf_T *
get_buf_tv(typval_T *tv, int curtab_only)
{
char_u *name = tv->vval.v_string;
*** ../vim-8.0.0802/src/proto/evalfunc.pro 2016-09-12 13:04:01.000000000
+0200
--- src/proto/evalfunc.pro 2017-07-29 16:07:20.211414078 +0200
***************
*** 1,4 ****
--- 1,5 ----
/* evalfunc.c */
+ buf_T* get_buf_tv(typval_T *tv, int curtab_only);
char_u *get_function_name(expand_T *xp, int idx);
char_u *get_expr_name(expand_T *xp, int idx);
int find_internal_func(char_u *name);
*** ../vim-8.0.0802/src/proto/terminal.pro 2017-07-28 22:29:31.587928642
+0200
--- src/proto/terminal.pro 2017-07-29 17:00:08.156900039 +0200
***************
*** 3,8 ****
--- 3,9 ----
void free_terminal(buf_T *buf);
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
int terminal_loop(void);
+ void term_job_ended(job_T *job);
void term_channel_closed(channel_T *ch);
int term_update_window(win_T *wp);
int term_is_finished(buf_T *buf);
***************
*** 10,13 ****
--- 11,23 ----
int term_get_attr(buf_T *buf, linenr_T lnum, int col);
char_u *term_get_status_text(term_T *term);
int set_ref_in_term(int copyID);
+ void f_term_getattr(typval_T *argvars, typval_T *rettv);
+ void f_term_getjob(typval_T *argvars, typval_T *rettv);
+ void f_term_getline(typval_T *argvars, typval_T *rettv);
+ void f_term_getsize(typval_T *argvars, typval_T *rettv);
+ void f_term_list(typval_T *argvars, typval_T *rettv);
+ void f_term_start(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);
+ void f_term_wait(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
*** ../vim-8.0.0802/src/terminal.c 2017-07-29 16:01:49.489748199 +0200
--- src/terminal.c 2017-07-29 19:53:45.682578164 +0200
***************
*** 54,67 ****
* - support minimal size when 'termsize' is empty?
* - implement "term" for job_start(): more job options when starting a
* terminal.
- * - implement term_list() list of buffers with a terminal
- * - implement term_getsize(buf)
- * - implement term_setsize(buf)
- * - implement term_sendkeys(buf, keys) send keystrokes to a
terminal
- * - implement term_wait(buf) wait for screen to be updated
- * - implement term_scrape(buf, row) inspect terminal screen
- * - implement term_open(command, options) open terminal window
- * - implement term_getjob(buf)
* - when 'encoding' is not utf-8, or the job is using another encoding, setup
* conversions.
* - In the GUI use a terminal emulator for :!cmd.
--- 54,59 ----
***************
*** 69,75 ****
#include "vim.h"
! #ifdef FEAT_TERMINAL
#ifdef WIN3264
# define MIN(x,y) (x < y ? x : y)
--- 61,67 ----
#include "vim.h"
! #if defined(FEAT_TERMINAL) || defined(PROTO)
#ifdef WIN3264
# define MIN(x,y) (x < y ? x : y)
***************
*** 110,115 ****
--- 102,108 ----
int tl_dirty_row_end; /* row below last one to update */
garray_T tl_scrollback;
+ int tl_scrollback_scrolled;
pos_T tl_cursor;
int tl_cursor_visible;
***************
*** 384,392 ****
* Return the number of bytes in "buf".
*/
static int
! term_convert_key(int c, char *buf)
{
! VTerm *vterm = curbuf->b_term->tl_vterm;
VTermKey key = VTERM_KEY_NONE;
VTermModifier mod = VTERM_MOD_NONE;
--- 377,385 ----
* Return the number of bytes in "buf".
*/
static int
! term_convert_key(term_T *term, int c, char *buf)
{
! VTerm *vterm = term->tl_vterm;
VTermKey key = VTERM_KEY_NONE;
VTermModifier mod = VTERM_MOD_NONE;
***************
*** 517,522 ****
--- 510,585 ----
}
/*
+ * Send keys to terminal.
+ */
+ static int
+ send_keys_to_term(term_T *term, int c, int typed)
+ {
+ char msg[KEY_BUF_LEN];
+ size_t len;
+ static int mouse_was_outside = FALSE;
+ int dragging_outside = FALSE;
+
+ /* Catch keys that need to be handled as in Normal mode. */
+ switch (c)
+ {
+ case NUL:
+ case K_ZERO:
+ if (typed)
+ stuffcharReadbuff(c);
+ return FAIL;
+
+ case K_IGNORE:
+ return FAIL;
+
+ case K_LEFTDRAG:
+ case K_MIDDLEDRAG:
+ case K_RIGHTDRAG:
+ case K_X1DRAG:
+ case K_X2DRAG:
+ dragging_outside = mouse_was_outside;
+ /* FALLTHROUGH */
+ case K_LEFTMOUSE:
+ case K_LEFTMOUSE_NM:
+ case K_LEFTRELEASE:
+ case K_LEFTRELEASE_NM:
+ case K_MIDDLEMOUSE:
+ case K_MIDDLERELEASE:
+ case K_RIGHTMOUSE:
+ case K_RIGHTRELEASE:
+ case K_X1MOUSE:
+ case K_X1RELEASE:
+ case K_X2MOUSE:
+ case K_X2RELEASE:
+ if (mouse_row < W_WINROW(curwin)
+ || mouse_row >= (W_WINROW(curwin) + curwin->w_height)
+ || mouse_col < W_WINCOL(curwin)
+ || mouse_col >= W_ENDCOL(curwin)
+ || dragging_outside)
+ {
+ /* click outside the current window */
+ if (typed)
+ {
+ stuffcharReadbuff(c);
+ mouse_was_outside = TRUE;
+ }
+ return FAIL;
+ }
+ }
+ if (typed)
+ mouse_was_outside = FALSE;
+
+ /* Convert the typed key to a sequence of bytes for the job. */
+ len = term_convert_key(term, c, msg);
+ if (len > 0)
+ /* TODO: if FAIL is returned, stop? */
+ channel_send(term->tl_job->jv_channel, PART_IN,
+ (char_u *)msg, (int)len, NULL);
+
+ return OK;
+ }
+
+ /*
* Wait for input and send it to the job.
* Return when the start of a CTRL-W command is typed or anything else that
* should be handled as a Normal mode command.
***************
*** 526,536 ****
int
terminal_loop(void)
{
- char buf[KEY_BUF_LEN];
int c;
- size_t len;
- static int mouse_was_outside = FALSE;
- int dragging_outside = FALSE;
int termkey = 0;
if (curbuf->b_term->tl_vterm == NULL || !term_job_running(curbuf->b_term))
--- 589,595 ----
***************
*** 576,633 ****
return OK;
}
}
! /* Catch keys that need to be handled as in Normal mode. */
! switch (c)
! {
! case NUL:
! case K_ZERO:
! stuffcharReadbuff(c);
! return OK;
!
! case K_IGNORE: continue;
! case K_LEFTDRAG:
! case K_MIDDLEDRAG:
! case K_RIGHTDRAG:
! case K_X1DRAG:
! case K_X2DRAG:
! dragging_outside = mouse_was_outside;
! /* FALLTHROUGH */
! case K_LEFTMOUSE:
! case K_LEFTMOUSE_NM:
! case K_LEFTRELEASE:
! case K_LEFTRELEASE_NM:
! case K_MIDDLEMOUSE:
! case K_MIDDLERELEASE:
! case K_RIGHTMOUSE:
! case K_RIGHTRELEASE:
! case K_X1MOUSE:
! case K_X1RELEASE:
! case K_X2MOUSE:
! case K_X2RELEASE:
! if (mouse_row < W_WINROW(curwin)
! || mouse_row >= (W_WINROW(curwin) + curwin->w_height)
! || mouse_col < W_WINCOL(curwin)
! || mouse_col >= W_ENDCOL(curwin)
! || dragging_outside)
! {
! /* click outside the current window */
! stuffcharReadbuff(c);
! mouse_was_outside = TRUE;
! return OK;
! }
}
! mouse_was_outside = FALSE;
!
! /* Convert the typed key to a sequence of bytes for the job. */
! len = term_convert_key(c, buf);
! if (len > 0)
! /* TODO: if FAIL is returned, stop? */
! channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN,
! (char_u *)buf, (int)len, NULL);
}
- return FAIL;
}
static void
--- 635,673 ----
return OK;
}
}
+ if (send_keys_to_term(curbuf->b_term, c, TRUE) != OK)
+ return OK;
+ }
+ return FAIL;
+ }
! /*
! * Called when a job has finished.
! */
! void
! term_job_ended(job_T *job)
! {
! term_T *term;
! int did_one = FALSE;
! for (term = first_term; term != NULL; term = term->tl_next)
! if (term->tl_job == job)
! {
! vim_free(term->tl_title);
! term->tl_title = NULL;
! vim_free(term->tl_status_text);
! term->tl_status_text = NULL;
! redraw_buf_and_status_later(term->tl_buffer, VALID);
! did_one = TRUE;
}
! if (did_one)
! redraw_statuslines();
! if (curbuf->b_term != NULL)
! {
! if (curbuf->b_term->tl_job == job)
! maketitle();
! update_cursor(curbuf->b_term, TRUE);
}
}
static void
***************
*** 789,794 ****
--- 829,835 ----
line->sb_cols = len;
line->sb_cells = p;
++term->tl_scrollback.ga_len;
+ ++term->tl_scrollback_scrolled;
}
return 0; /* ignored */
}
***************
*** 916,921 ****
--- 957,963 ----
/*
* Called when a channel has been closed.
+ * If this was a channel for a terminal window then finish it up.
*/
void
term_channel_closed(channel_T *ch)
***************
*** 1080,1087 ****
attr |= HL_STANDOUT;
if (cell->attrs.reverse)
attr |= HL_INVERSE;
- if (cell->attrs.strike)
- attr |= HL_UNDERLINE;
#ifdef FEAT_GUI
if (gui.in_use)
--- 1122,1127 ----
***************
*** 1384,1391 ****
--- 1424,1738 ----
return abort;
}
+ /*
+ * "term_getattr(attr, name)" function
+ */
+ void
+ f_term_getattr(typval_T *argvars, typval_T *rettv)
+ {
+ int attr;
+ size_t i;
+ char_u *name;
+
+ static struct {
+ char *name;
+ int attr;
+ } attrs[] = {
+ {"bold", HL_BOLD},
+ {"italic", HL_ITALIC},
+ {"underline", HL_UNDERLINE},
+ {"strike", HL_STANDOUT},
+ {"reverse", HL_INVERSE},
+ };
+
+ attr = get_tv_number(&argvars[0]);
+ name = get_tv_string_chk(&argvars[1]);
+ if (name == NULL)
+ return;
+
+ for (i = 0; i < sizeof(attrs)/sizeof(attrs[0]); ++i)
+ if (STRCMP(name, attrs[i].name) == 0)
+ {
+ rettv->vval.v_number = (attr & attrs[i].attr) != 0 ? 1 : 0;
+ break;
+ }
+ }
+
+ /*
+ * Get the buffer from the first argument in "argvars".
+ * Returns NULL when the buffer is not for a terminal window.
+ */
+ static buf_T *
+ term_get_buf(typval_T *argvars)
+ {
+ buf_T *buf;
+
+ (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ buf = get_buf_tv(&argvars[0], FALSE);
+ --emsg_off;
+ if (buf->b_term == NULL)
+ return NULL;
+ return buf;
+ }
+
+ /*
+ * "term_getjob(buf)" function
+ */
+ void
+ f_term_getjob(typval_T *argvars, typval_T *rettv)
+ {
+ buf_T *buf = term_get_buf(argvars);
+
+ rettv->v_type = VAR_JOB;
+ rettv->vval.v_job = NULL;
+ if (buf == NULL)
+ return;
+
+ rettv->vval.v_job = buf->b_term->tl_job;
+ if (rettv->vval.v_job != NULL)
+ ++rettv->vval.v_job->jv_refcount;
+ }
+
+ /*
+ * "term_getline(buf, row)" function
+ */
+ void
+ f_term_getline(typval_T *argvars, typval_T *rettv)
+ {
+ buf_T *buf = term_get_buf(argvars);
+ term_T *term;
+ int row;
+
+ rettv->v_type = VAR_STRING;
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ row = (int)get_tv_number(&argvars[1]);
+
+ if (term->tl_vterm == NULL)
+ {
+ linenr_T lnum = row + term->tl_scrollback_scrolled + 1;
+
+ /* vterm is finished, get the text from the buffer */
+ if (lnum > 0 && lnum <= buf->b_ml.ml_line_count)
+ rettv->vval.v_string = vim_strsave(ml_get_buf(buf, lnum, FALSE));
+ }
+ else
+ {
+ VTermScreen *screen = vterm_obtain_screen(term->tl_vterm);
+ VTermRect rect;
+ int len;
+ char_u *p;
+
+ len = term->tl_cols * MB_MAXBYTES + 1;
+ p = alloc(len);
+ if (p == NULL)
+ return;
+ rettv->vval.v_string = p;
+
+ rect.start_col = 0;
+ rect.end_col = term->tl_cols;
+ rect.start_row = row;
+ rect.end_row = row + 1;
+ p[vterm_screen_get_text(screen, (char *)p, len, rect)] = NUL;
+ }
+ }
+
+ /*
+ * "term_getsize(buf)" function
+ */
+ void
+ f_term_getsize(typval_T *argvars, typval_T *rettv)
+ {
+ buf_T *buf = term_get_buf(argvars);
+ list_T *l;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ if (buf == NULL)
+ return;
+
+ l = rettv->vval.v_list;
+ list_append_number(l, buf->b_term->tl_rows);
+ list_append_number(l, buf->b_term->tl_cols);
+ }
+
+ /*
+ * "term_list()" function
+ */
+ void
+ f_term_list(typval_T *argvars UNUSED, typval_T *rettv)
+ {
+ term_T *tp;
+ list_T *l;
+
+ if (rettv_list_alloc(rettv) == FAIL || first_term == NULL)
+ return;
+
+ l = rettv->vval.v_list;
+ for (tp = first_term; tp != NULL; tp = tp->tl_next)
+ if (tp != NULL && tp->tl_buffer != NULL)
+ if (list_append_number(l,
+ (varnumber_T)tp->tl_buffer->b_fnum) == FAIL)
+ return;
+ }
+
+ /*
+ * "term_scrape(buf, row)" function
+ */
+ void
+ f_term_scrape(typval_T *argvars, typval_T *rettv)
+ {
+ buf_T *buf = term_get_buf(argvars);
+ VTermScreen *screen = NULL;
+ VTermPos pos;
+ list_T *l;
+ term_T *term;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ if (term->tl_vterm != NULL)
+ screen = vterm_obtain_screen(term->tl_vterm);
+
+ l = rettv->vval.v_list;
+ pos.row = (int)get_tv_number(&argvars[1]);
+ for (pos.col = 0; pos.col < term->tl_cols; )
+ {
+ dict_T *dcell;
+ VTermScreenCell cell;
+ char_u rgb[8];
+ char_u mbs[MB_MAXBYTES * VTERM_MAX_CHARS_PER_CELL + 1];
+ int off = 0;
+ int i;
+
+ if (screen == NULL)
+ {
+ linenr_T lnum = pos.row + term->tl_scrollback_scrolled;
+ sb_line_T *line;
+
+ /* vterm has finished, get the cell from scrollback */
+ if (lnum < 0 || lnum >= term->tl_scrollback.ga_len)
+ break;
+ line = (sb_line_T *)term->tl_scrollback.ga_data + lnum;
+ if (pos.col >= line->sb_cols)
+ break;
+ cell = line->sb_cells[pos.col];
+ }
+ else if (vterm_screen_get_cell(screen, pos, &cell) == 0)
+ break;
+ dcell = dict_alloc();
+ list_append_dict(l, dcell);
+
+ for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i)
+ {
+ if (cell.chars[i] == 0)
+ break;
+ off += (*utf_char2bytes)((int)cell.chars[i], mbs + off);
+ }
+ mbs[off] = NUL;
+ dict_add_nr_str(dcell, "chars", 0, mbs);
+
+ vim_snprintf((char *)rgb, 8, "#%02x%02x%02x",
+ cell.fg.red, cell.fg.green, cell.fg.blue);
+ dict_add_nr_str(dcell, "fg", 0, rgb);
+ vim_snprintf((char *)rgb, 8, "#%02x%02x%02x",
+ cell.bg.red, cell.bg.green, cell.bg.blue);
+ dict_add_nr_str(dcell, "bg", 0, rgb);
+
+ dict_add_nr_str(dcell, "attr", cell2attr(&cell), NULL);
+ dict_add_nr_str(dcell, "width", cell.width, NULL);
+
+ ++pos.col;
+ if (cell.width == 2)
+ ++pos.col;
+ }
+ }
+
+ /*
+ * "term_sendkeys(buf, keys)" function
+ */
+ void
+ f_term_sendkeys(typval_T *argvars, typval_T *rettv)
+ {
+ buf_T *buf = term_get_buf(argvars);
+ char_u *msg;
+ term_T *term;
+
+ rettv->v_type = VAR_UNKNOWN;
+ if (buf == NULL)
+ return;
+
+ msg = get_tv_string_chk(&argvars[1]);
+ if (msg == NULL)
+ return;
+ term = buf->b_term;
+ if (term->tl_vterm == NULL)
+ return;
+
+ while (*msg != NUL)
+ {
+ send_keys_to_term(term, PTR2CHAR(msg), FALSE);
+ msg += MB_PTR2LEN(msg);
+ }
+
+ /* TODO: only update once in a while. */
+ update_screen(0);
+ if (buf == curbuf)
+ update_cursor(term, TRUE);
+ }
+
+ /*
+ * "term_start(command, options)" function
+ */
+ void
+ f_term_start(typval_T *argvars, typval_T *rettv)
+ {
+ char_u *cmd = get_tv_string_chk(&argvars[0]);
+ exarg_T ea;
+
+ if (cmd == NULL)
+ return;
+ ea.arg = cmd;
+ ex_terminal(&ea);
+
+ if (curbuf->b_term != NULL)
+ rettv->vval.v_number = curbuf->b_fnum;
+ }
+
+ /*
+ * "term_wait" function
+ */
+ void
+ f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ buf_T *buf = term_get_buf(argvars);
+
+ if (buf == NULL)
+ return;
+
+ /* Get the job status, this will detect a job that finished. */
+ if (buf->b_term->tl_job != NULL)
+ (void)job_status(buf->b_term->tl_job);
+
+ /* Check for any pending channel I/O. */
+ vpeekc_any();
+ ui_delay(10L, FALSE);
+
+ /* Flushing messages on channels is hopefully sufficient.
+ * TODO: is there a better way? */
+ parse_queued_messages();
+ }
+
# ifdef WIN3264
+ /**************************************
+ * 2. MS-Windows implementation.
+ */
+
#define WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN 1ul
#define WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN 2ull
***************
*** 1404,1413 ****
LPCWSTR (*winpty_error_msg)(void*);
BOOL (*winpty_set_size)(void*, int, int, void*);
- /**************************************
- * 2. MS-Windows implementation.
- */
-
#define WINPTY_DLL "winpty.dll"
static HINSTANCE hWinPtyDLL = NULL;
--- 1751,1756 ----
*** ../vim-8.0.0802/src/testdir/Make_all.mak 2017-07-23 22:01:43.063625375
+0200
--- src/testdir/Make_all.mak 2017-07-29 16:19:40.806199178 +0200
***************
*** 197,202 ****
--- 197,203 ----
test_syntax.res \
test_system.res \
test_tcl.res \
+ test_terminal.res \
test_textobjects.res \
test_undo.res \
test_usercommands.res \
*** ../vim-8.0.0802/src/testdir/test_terminal.vim 2017-07-29
20:05:33.993555291 +0200
--- src/testdir/test_terminal.vim 2017-07-29 19:49:09.604538308 +0200
***************
*** 0 ****
--- 1,67 ----
+ " Tests for the terminal window.
+
+ if !exists('*term_start')
+ finish
+ endif
+
+ source shared.vim
+
+ func Test_terminal_basic()
+ let buf = term_start(&shell)
+
+ let termlist = term_list()
+ call assert_equal(1, len(termlist))
+ call assert_equal(buf, termlist[0])
+
+ let g:job = term_getjob(buf)
+ call assert_equal(v:t_job, type(g:job))
+
+ call term_sendkeys(buf, "exit\r")
+ call WaitFor('job_status(g:job) == "dead"')
+ call assert_equal('dead', job_status(g:job))
+
+ exe buf . 'bwipe'
+ unlet g:job
+ endfunc
+
+ func Check_123(buf)
+ let l = term_scrape(a:buf, 0)
+ call assert_true(len(l) > 0)
+ call assert_equal('1', l[0].chars)
+ call assert_equal('2', l[1].chars)
+ call assert_equal('3', l[2].chars)
+ call assert_equal('#00e000', l[0].fg)
+ if &background == 'light'
+ call assert_equal('#ffffff', l[0].bg)
+ else
+ call assert_equal('#000000', l[0].bg)
+ endif
+
+ let l = term_getline(a:buf, 0)
+ call assert_equal('123', l)
+ endfunc
+
+ func Test_terminal_scrape()
+ if has('win32')
+ let cmd = 'cmd /c "cls && color 2 && echo 123"'
+ else
+ call writefile(["\<Esc>[32m123"], 'Xtext')
+ let cmd = "cat Xtext"
+ endif
+ let buf = term_start(cmd)
+
+ let termlist = term_list()
+ call assert_equal(1, len(termlist))
+ call assert_equal(buf, termlist[0])
+
+ call term_wait(buf)
+ call Check_123(buf)
+
+ " Must still work after the job ended.
+ let g:job = term_getjob(buf)
+ call WaitFor('job_status(g:job) == "dead"')
+ call term_wait(buf)
+ call Check_123(buf)
+
+ exe buf . 'bwipe'
+ endfunc
*** ../vim-8.0.0802/src/version.c 2017-07-29 16:01:49.489748199 +0200
--- src/version.c 2017-07-29 16:08:54.822746982 +0200
***************
*** 771,772 ****
--- 771,774 ----
{ /* Add new patch number below this line */
+ /**/
+ 803,
/**/
--
GALAHAD turns back. We see from his POV the lovely ZOOT standing by him
smiling enchantingly and a number of equally delectable GIRLIES draped
around in the seductively poulticed room. They look at him smilingly and
wave.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// 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.