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(&item->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(&ea, 0, sizeof(ea));
+     ea.cmd = (char_u *)"sbuffer";
+     goto_buffer(&ea, 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(&item->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), &rettv,
+               2, argvars, /* argv_func */ NULL,
+               /* firstline */ 1, /* lastline */ 1,
+               &doesrange, /* evaluate */ TRUE,
+               /* partial */ NULL, /* selfdict */ NULL) == OK)
+     {
+       clear_tv(&rettv);
+       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(&reader, &tv, 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(&item->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_command(item);
+           else if (STRCMP(cmd, "call") == 0)
+               handle_call_command(term, channel, item);
+           else
+               ch_log(channel, "Invalid command received: %s", cmd);
+       }
+     }
+     else
+       ch_log(channel, "Invalid JSON received");
+ 
+     vim_free(reader.js_buf);
+     clear_tv(&tv);
+     return 1;
+ }
+ 
+ static VTermParserCallbacks parser_fallbacks = {
+   NULL,               /* text */
+   NULL,               /* control */
+   NULL,               /* escape */
+   NULL,               /* csi */
+   parse_osc,  /* osc */
+   NULL,               /* dcs */
+   NULL                /* resize */
+ };
+ 
+ /*
   * Create a new vterm and initialize it.
   */
      static void
***************
*** 3153,3158 ****
--- 3286,3292 ----
  {
      VTerm         *vterm;
      VTermScreen           *screen;
+     VTermState            *state;
      VTermValue            value;
  
      vterm = vterm_new(rows, cols);
***************
*** 3186,3193 ****
  #else
      value.boolean = 0;
  #endif
!     vterm_state_set_termprop(vterm_obtain_state(vterm),
!                                              VTERM_PROP_CURSORBLINK, &value);
  }
  
  /*
--- 3320,3328 ----
  #else
      value.boolean = 0;
  #endif
!     state = vterm_obtain_state(vterm);
!     vterm_state_set_termprop(state, VTERM_PROP_CURSORBLINK, &value);
!     vterm_state_set_unrecognised_fallbacks(state, &parser_fallbacks, term);
  }
  
  /*
*** ../vim-8.0.1640/src/buffer.c        2018-03-23 22:39:27.321233962 +0100
--- src/buffer.c        2018-03-25 17:46:10.476283979 +0200
***************
*** 948,954 ****
      }
  }
  
! #if defined(FEAT_LISTCMDS) || defined(PROTO)
  /*
   * Go to another buffer.  Handles the result of the ATTENTION dialog.
   */
--- 948,954 ----
      }
  }
  
! #if defined(FEAT_LISTCMDS) || defined(FEAT_TERMINAL) || defined(PROTO)
  /*
   * Go to another buffer.  Handles the result of the ATTENTION dialog.
   */
*** ../vim-8.0.1640/src/testdir/test_terminal.vim       2018-03-24 
17:16:29.441976567 +0100
--- src/testdir/test_terminal.vim       2018-03-25 18:02:18.154736269 +0200
***************
*** 1023,1025 ****
--- 1023,1101 ----
  
    set laststatus&
  endfunc
+ 
+ func Test_terminal_api_drop_newwin()
+   if !CanRunVimInTerminal()
+     return
+   endif
+   call assert_equal(1, winnr('$'))
+ 
+   " Use the title termcap entries to output the escape sequence.
+   call writefile([
+       \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
+       \ 'let &titlestring = ''["drop","Xtextfile"]''',
+       \ 'redraw',
+       \ "set t_ts=",
+       \ ], 'Xscript')
+   let buf = RunVimInTerminal('-S Xscript', {})
+   call WaitFor({-> bufnr('Xtextfile') > 0})
+   call assert_equal('Xtextfile', expand('%:t'))
+   call assert_true(winnr('$') >= 3)
+ 
+   call StopVimInTerminal(buf)
+   call delete('Xscript')
+   bwipe Xtextfile
+ endfunc
+ 
+ func Test_terminal_api_drop_oldwin()
+   if !CanRunVimInTerminal()
+     return
+   endif
+   let firstwinid = win_getid()
+   split Xtextfile
+   let textfile_winid = win_getid()
+   call assert_equal(2, winnr('$'))
+   call win_gotoid(firstwinid)
+ 
+   " Use the title termcap entries to output the escape sequence.
+   call writefile([
+       \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
+       \ 'let &titlestring = ''["drop","Xtextfile"]''',
+       \ 'redraw',
+       \ "set t_ts=",
+       \ ], 'Xscript')
+   let buf = RunVimInTerminal('-S Xscript', {})
+   call WaitFor({-> expand('%:t') =='Xtextfile'})
+   call assert_equal(textfile_winid, win_getid())
+ 
+   call StopVimInTerminal(buf)
+   call delete('Xscript')
+   bwipe Xtextfile
+ endfunc
+ 
+ func TryThis(bufnum, arg)
+   let g:called_bufnum = a:bufnum
+   let g:called_arg = a:arg
+ endfunc
+ 
+ func Test_terminal_api_call()
+   if !CanRunVimInTerminal()
+     return
+   endif
+   " Use the title termcap entries to output the escape sequence.
+   call writefile([
+       \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
+       \ 'let &titlestring = ''["call","TryThis",["hello",123]]''',
+       \ 'redraw',
+       \ "set t_ts=",
+       \ ], 'Xscript')
+   let buf = RunVimInTerminal('-S Xscript', {})
+   call WaitFor({-> exists('g:called_bufnum')})
+   call assert_equal(buf, g:called_bufnum)
+   call assert_equal(['hello', 123], g:called_arg)
+ 
+   call StopVimInTerminal(buf)
+   call delete('Xscript')
+   unlet g:called_bufnum
+   unlet g:called_arg
+ endfunc
*** ../vim-8.0.1640/src/testdir/screendump.vim  2018-03-24 17:56:09.201107418 
+0100
--- src/testdir/screendump.vim  2018-03-25 18:05:37.257603139 +0200
***************
*** 38,45 ****
    endif
  
    " Make a horizontal and vertical split, so that we can get exactly the right
!   " size terminal window.  Works only when we currently have one window.
!   call assert_equal(1, winnr('$'))
    split
    vsplit
  
--- 38,45 ----
    endif
  
    " Make a horizontal and vertical split, so that we can get exactly the right
!   " size terminal window.  Works only when the current window is full width.
!   call assert_equal(&columns, winwidth(0))
    split
    vsplit
  
*** ../vim-8.0.1640/runtime/doc/terminal.txt    2018-03-16 22:54:47.342973089 
+0100
--- runtime/doc/terminal.txt    2018-03-25 18:15:13.446494414 +0200
***************
*** 1,4 ****
! *terminal.txt*        For Vim version 8.0.  Last change: 2018 Feb 20
  
  
                  VIM REFERENCE MANUAL    by Bram Moolenaar
--- 1,4 ----
! *terminal.txt*        For Vim version 8.0.  Last change: 2018 Mar 25
  
  
                  VIM REFERENCE MANUAL    by Bram Moolenaar
***************
*** 23,34 ****
        Session                         |terminal-session|
        Unix                            |terminal-unix|
        MS-Windows                      |terminal-ms-windows|
! 2. Remote testing             |terminal-testing|
! 3. Diffing screen dumps               |terminal-diff|
        Writing a screen dump test for Vim  |terminal-dumptest|
        Creating a screen dump            |terminal-screendump|
        Comparing screen dumps            |terminal-diffscreendump|
! 4. Debugging                  |terminal-debug|
        Starting                                |termdebug-starting|
        Example session                 |termdebug-example|
        Stepping through code           |termdebug-stepping|
--- 23,38 ----
        Session                         |terminal-session|
        Unix                            |terminal-unix|
        MS-Windows                      |terminal-ms-windows|
! 2. Terminal communication     |terminal-communication|
!       Vim to job: term_sendkeys()     |terminal-to-job|
!       Job to Vim: JSON API            |terminal-api|
!       Using the client-server feature |terminal-client-server|
! 3. Remote testing             |terminal-testing|
! 4. Diffing screen dumps               |terminal-diff|
        Writing a screen dump test for Vim  |terminal-dumptest|
        Creating a screen dump            |terminal-screendump|
        Comparing screen dumps            |terminal-diffscreendump|
! 5. Debugging                  |terminal-debug|
        Starting                                |termdebug-starting|
        Example session                 |termdebug-example|
        Stepping through code           |termdebug-stepping|
***************
*** 99,107 ****
  
  To change the keys you type use terminal mode mappings, see |:tmap|.
  These are defined like any mapping, but apply only when typing keys that are
! sent to the job running in the terminal.  For example, to make Escape switch
  to Terminal-Normal mode: >
     tnoremap <Esc> <C-W>N
  <                                                     *options-in-terminal*
  After opening the terminal window and setting 'buftype' to "terminal" the
  BufWinEnter autocommand event is triggered.  This makes it possible to set
--- 103,116 ----
  
  To change the keys you type use terminal mode mappings, see |:tmap|.
  These are defined like any mapping, but apply only when typing keys that are
! sent to the job running in the terminal.  For example, to make F1 switch
  to Terminal-Normal mode: >
+    tnoremap <F1> <C-W>N
+ You can use Esc, but you need to make sure it won't cause other keys to
+ break: >
     tnoremap <Esc> <C-W>N
+    set notimeout ttimeout timeoutlen=100
+ 
  <                                                     *options-in-terminal*
  After opening the terminal window and setting 'buftype' to "terminal" the
  BufWinEnter autocommand event is triggered.  This makes it possible to set
***************
*** 350,364 ****
      COLORS            number of colors, 't_Co' (256*256*256 in the GUI)
      VIM_SERVERNAME    v:servername
  
- The |client-server| feature can be used to communicate with the Vim instance
- where the job was started.  This only works when v:servername is not empty.
- If needed you can set it with: >
-       call remote_startserver('vim-server')
- 
- In the job you can then do something like: >
-       vim --servername $VIM_SERVERNAME --remote +123 some_file.c
- This will open the file "some_file.c" and put the cursor on line 123.
- 
  
  MS-Windows ~
                                                        *terminal-ms-windows*
--- 359,364 ----
***************
*** 384,390 ****
      VIM_SERVERNAME    v:servername
  
  ==============================================================================
! 2. Remote testing                                     *terminal-testing*
  
  Most Vim tests execute a script inside Vim.  For some tests this does not
  work, running the test interferes with the code being tested.  To avoid this
--- 384,474 ----
      VIM_SERVERNAME    v:servername
  
  ==============================================================================
! 2. Terminal communication                      *terminal-communication*
! 
! There are several ways to communicate with the job running in a terminal:
! - Use |term_sendkeys()| to send text and escape sequences from Vim to the job.
! - Use the JSON API to send encoded commands from the job to Vim.
! - Use the |client-server| mechanism. This works on machines with an X server
!   and on MS-Windows.
! 
! 
! Vim to job: term_sendkeys() ~
!                                                       *terminal-to-job*
! This allows for remote controlling the job running in the terminal.  It is a
! one-way mechanism.  The job can update the display to signal back to Vim.
! For example, if a shell is running in a terminal, you can do: >
!       call term_sendkeys(buf, "ls *.java\<CR>")
! 
! This requires for the job to be in the right state where it will do the right
! thing when receiving the keys.  For the above example, the shell must be
! waiting for a command to be typed.
! 
! For a job that was written for the purpose, you can use the JSON API escape
! sequence in the other direction.  E.g.: >
!       call term_sendkeys(buf, "\<Esc>]51;["response"]\x07")
! 
! 
! Job to Vim: JSON API ~
!                                                       *terminal-api*
! The job can send JSON to Vim, using a special escape sequence.  The JSON
! encodes a command that Vim understands.  Example of such a message: >
!       <Esc>]51;["drop", "README.md"]<07>
! 
! The body is always a list, making it easy to find the end: ]<07>.
! The <Esc>]51;msg<07> sequence is reserved by xterm for "Emacs shell", which is
! similar to what we are doing here.
! 
! Currently supported commands:
! 
!       call {funcname} {argument}
! 
!               Call a user defined function with [argument].  The function is
!               called with the buffer number of the terminal and the decoded
!               argument.  The user function must sanity check the argument.
!               The function can use |term_sendkeys()| to send back a reply.
!               Example in JSON: >
!                       ["call", "Impression", ["play", 14]]
! <             Calls a function defined like this: >
!                       function Impression(bufnum, arglist)
!                         if len(a:arglist) == 2
!                           echo "impression " . a:arglist[0]
!                           echo "count " . a:arglist[1]
!                         endif
!                       endfunc
! <
!       drop {filename}
! 
!               Let Vim open a file, like the `:drop` command.  If {filename}
!               is already open in a window, switch to that window.  Otherwise
!               open a new window to edit {filename}.
!               Example in JSON: >
!                       ["drop", "path/file.txt", {"ff": "dos"}]
! 
! A trick to have Vim send this escape sequence: >
!       exe "set t_ts=\<Esc>]51; t_fs=\x07"
!       let &titlestring = '["call","TryThis",["hello",123]]'
!       redraw
!       set t_ts& t_fs&
! 
! Rationale: Why not allow for any command or expression?  Because that might
! create a security problem.
! 
! 
! Using the client-server feature ~
!                                               *terminal-client-server*
! This only works when v:servername is not empty.  If needed you can set it,
! before opening the terminal, with: >
!       call remote_startserver('vim-server')
! 
! $VIM_SERVERNAME is set in the terminal to pass on the server name.
! 
! In the job you can then do something like: >
!       vim --servername $VIM_SERVERNAME --remote +123 some_file.c
! This will open the file "some_file.c" and put the cursor on line 123.
! 
! ==============================================================================
! 3. Remote testing                                     *terminal-testing*
  
  Most Vim tests execute a script inside Vim.  For some tests this does not
  work, running the test interferes with the code being tested.  To avoid this
***************
*** 399,405 ****
  
  
  ==============================================================================
! 3. Diffing screen dumps                                       *terminal-diff*
  
  In some cases it can be bothersome to test that Vim displays the right
  characters on the screen.  E.g. with syntax highlighting.  To make this
--- 483,489 ----
  
  
  ==============================================================================
! 4. Diffing screen dumps                                       *terminal-diff*
  
  In some cases it can be bothersome to test that Vim displays the right
  characters on the screen.  E.g. with syntax highlighting.  To make this
***************
*** 408,414 ****
  
  Vim uses the window size, text, color and other attributes as displayed.  The
  Vim screen size, font and other properties do not matter.  Therefore this
! mechanism is portable across systems.  A convential screenshot would reflect
  all differences, including font size and family.
  
  
--- 492,498 ----
  
  Vim uses the window size, text, color and other attributes as displayed.  The
  Vim screen size, font and other properties do not matter.  Therefore this
! mechanism is portable across systems.  A conventional screenshot would reflect
  all differences, including font size and family.
  
  
***************
*** 483,495 ****
  3.  The contents of the second dump
  
  You can usually see what differs in the second part.  Use the 'ruler' to
! relate it to the postion in the first or second dump.
  
! Alternatively, press "s" to swap the first and second dump. Do this everal
  times so that you can spot the difference in the context of the text.
  
  ==============================================================================
! 4. Debugging                                          *terminal-debug*
  
  The Terminal debugging plugin can be used to debug a program with gdb and view
  the source code in a Vim window.  Since this is completely contained inside
--- 567,579 ----
  3.  The contents of the second dump
  
  You can usually see what differs in the second part.  Use the 'ruler' to
! relate it to the position in the first or second dump.
  
! Alternatively, press "s" to swap the first and second dump. Do this several
  times so that you can spot the difference in the context of the text.
  
  ==============================================================================
! 5. Debugging                                          *terminal-debug*
  
  The Terminal debugging plugin can be used to debug a program with gdb and view
  the source code in a Vim window.  Since this is completely contained inside
***************
*** 659,665 ****
        let termdebugger = "mygdb"
  <                                                     *gdb-version*
  Only debuggers fully compatible with gdb will work.  Vim uses the GDB/MI
! interface.  This probably requires gdb version 7.12.  if you get this error:
        Undefined command: "new-ui". Try "help".~
  Then your gdb is too old.
  
--- 743,750 ----
        let termdebugger = "mygdb"
  <                                                     *gdb-version*
  Only debuggers fully compatible with gdb will work.  Vim uses the GDB/MI
! interface.  The "new-ui" command  requires gdb version 7.12 or later.  if you
! get this error:
        Undefined command: "new-ui". Try "help".~
  Then your gdb is too old.
  
*** ../vim-8.0.1640/src/version.c       2018-03-25 17:12:53.927703230 +0200
--- src/version.c       2018-03-25 18:18:15.525550221 +0200
***************
*** 768,769 ****
--- 768,771 ----
  {   /* Add new patch number below this line */
+ /**/
+     1641,
  /**/

-- 
Be thankful to be in a traffic jam, because it means you own a car.

 /// 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.

Raspunde prin e-mail lui