Patch 8.0.1641
Problem:Job in terminal can't communicate with Vim.
Solution: Add the terminal API.
Files: src/terminal.c, src/buffer.c, src/testdir/test_terminal.vim,
src/testdir/screendump.vim, runtime/doc/terminal.txt
*** ../vim-8.0.1640/src/terminal.c 2018-03-23 22:10:26.164804315 +0100
--- src/terminal.c 2018-03-25 18:18:57.005331832 +0200
***
*** 38,49
* in tl_scrollback are no longer used.
*
* TODO:
! * - Win32: In the GUI use a terminal emulator for :!cmd.
* - Add a way to set the 16 ANSI colors, to be used for 'termguicolors' and
in
* the GUI.
! * - Some way for the job running in the terminal to send a :drop command back
! * to the Vim running the terminal. Should be usable by a simple shell or
! * python script.
* - implement term_setsize()
* - Copy text in the vterm to the Vim buffer once in a while, so that
* completion works.
--- 38,48
* in tl_scrollback are no longer used.
*
* TODO:
! * - For the "drop" command accept another argument for options.
* - Add a way to set the 16 ANSI colors, to be used for 'termguicolors' and
in
* the GUI.
! * - Win32: Make terminal used for :!cmd in the GUI work better. Allow for
! * redirection.
* - implement term_setsize()
* - Copy text in the vterm to the Vim buffer once in a while, so that
* completion works.
***
*** 3146,3151
--- 3145,3284
}
/*
+ * Handles a "drop" command from the job in the terminal.
+ * "item" is the file name, "item->li_next" may have options.
+ */
+ static void
+ handle_drop_command(listitem_T *item)
+ {
+ char_u*fname = get_tv_string(>li_tv);
+ int bufnr;
+ win_T *wp;
+ tabpage_T *tp;
+ exarg_T ea;
+
+ bufnr = buflist_add(fname, BLN_LISTED | BLN_NOOPT);
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ if (wp->w_buffer->b_fnum == bufnr)
+ {
+ /* buffer is in a window already, go there */
+ goto_tabpage_win(tp, wp);
+ return;
+ }
+ }
+
+ /* open in new window, like ":sbuffer N" */
+ vim_memset(, 0, sizeof(ea));
+ ea.cmd = (char_u *)"sbuffer";
+ goto_buffer(, DOBUF_FIRST, FORWARD, bufnr);
+ }
+
+ /*
+ * Handles a function call from the job running in a terminal.
+ * "item" is the function name, "item->li_next" has the arguments.
+ */
+ static void
+ handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
+ {
+ char_u*func;
+ typval_T argvars[2];
+ typval_T rettv;
+ int doesrange;
+
+ if (item->li_next == NULL)
+ {
+ ch_log(channel, "Missing function arguments for call");
+ return;
+ }
+ func = get_tv_string(>li_tv);
+
+ if (!ASCII_ISUPPER(*func))
+ {
+ ch_log(channel, "Invalid function name: %s", func);
+ return;
+ }
+
+ argvars[0].v_type = VAR_NUMBER;
+ argvars[0].vval.v_number = term->tl_buffer->b_fnum;
+ argvars[1] = item->li_next->li_tv;
+ if (call_func(func, STRLEN(func), ,
+ 2, argvars, /* argv_func */ NULL,
+ /* firstline */ 1, /* lastline */ 1,
+ , /* evaluate */ TRUE,
+ /* partial */ NULL, /* selfdict */ NULL) == OK)
+ {
+ clear_tv();
+ ch_log(channel, "Function %s called", func);
+ }
+ else
+ ch_log(channel, "Calling function %s failed", func);
+ }
+
+ /*
+ * Called by libvterm when it cannot recognize an OSC sequence.
+ * We recognize a terminal API command.
+ */
+ static int
+ parse_osc(const char *command, size_t cmdlen, void *user)
+ {
+ term_T*term = (term_T *)user;
+ js_read_T reader;
+ typval_T tv;
+ channel_T *channel = term->tl_job == NULL ? NULL
+ : term->tl_job->jv_channel;
+
+ /* We recognize only OSC 5 1 ; {command} */
+ if (cmdlen < 3 || STRNCMP(command, "51;", 3) != 0)
+ return 0; /* not handled */
+
+ reader.js_buf = vim_strnsave((char_u *)command + 3, cmdlen - 3);
+ if (reader.js_buf == NULL)
+ return 1;
+ reader.js_fill = NULL;
+ reader.js_used = 0;
+ if (json_decode(, , 0) == OK
+ && tv.v_type == VAR_LIST
+ && tv.vval.v_list != NULL)
+ {
+ listitem_T *item = tv.vval.v_list->lv_first;
+
+ if (item == NULL)
+ ch_log(channel, "Missing command");
+ else
+ {
+ char_u *cmd = get_tv_string(>li_tv);
+
+ item = item->li_next;
+ if (item == NULL)
+ ch_log(channel, "Missing argument for %s", cmd);
+ else if (STRCMP(cmd, "drop") == 0)
+ handle_drop_comma