Patch 8.0.1074
Problem:    ":term NONE" does not work on MS-Windows.
Solution:   Make it work.  Split "pty" into "pty_in" and "pty_out". (Yasuhiro
            Matsumoto, closes #2058, closes #2045)
Files:      runtime/doc/eval.txt, src/channel.c, src/evalfunc.c,
            src/os_unix.c, src/structs.h, src/terminal.c,
            src/testdir/test_terminal.vim


*** ../vim-8.0.1073/runtime/doc/eval.txt        2017-09-03 15:48:07.903554584 
+0200
--- runtime/doc/eval.txt        2017-09-08 14:17:47.490506202 +0200
***************
*** 2401,2407 ****
  term_getsize({buf})           List    get the size of a terminal
  term_getstatus({buf})         String  get the status of a terminal
  term_gettitle({buf})          String  get the title of a terminal
! term_gettty({buf})            String  get the tty name 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
--- 2401,2407 ----
  term_getsize({buf})           List    get the size of a terminal
  term_getstatus({buf})         String  get the status of a terminal
  term_gettitle({buf})          String  get the title of a terminal
! term_getttty({buf}, [{input}])        String  get the tty name 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
***************
*** 5245,5251 ****
                   "status"     what |job_status()| returns
                   "channel"    what |job_getchannel()| returns
                   "process"    process ID
!                  "tty"        controlling terminal name, empty when none
                   "exitval"    only valid when "status" is "dead"
                   "exit_cb"    function to be called on exit
                   "stoponexit" |job-stoponexit|
--- 5245,5252 ----
                   "status"     what |job_status()| returns
                   "channel"    what |job_getchannel()| returns
                   "process"    process ID
!                  "tty_in"     terminal input name, empty when none
!                  "tty_out"    terminal output name, empty when none
                   "exitval"    only valid when "status" is "dead"
                   "exit_cb"    function to be called on exit
                   "stoponexit" |job-stoponexit|
***************
*** 5258,5263 ****
--- 5259,5265 ----
  job_start({command} [, {options}])                    *job_start()*
                Start a job and return a Job object.  Unlike |system()| and
                |:!cmd| this does not wait for the job to finish.
+               To start a job in a terminal window see |term_start()|.
  
                {command} can be a String.  This works best on MS-Windows.  On
                Unix it is split up in white-separated parts to be passed to
***************
*** 5996,6002 ****
                a non-empty String (|non-zero-arg|), then the full mode is
                returned, otherwise only the first letter is returned.
  
!                       n       Normal
                        no      Operator-pending
                        v       Visual by character
                        V       Visual by line
--- 5998,6004 ----
                a non-empty String (|non-zero-arg|), then the full mode is
                returned, otherwise only the first letter is returned.
  
!                       n       Normal, Terminal-Normal
                        no      Operator-pending
                        v       Visual by character
                        V       Visual by line
***************
*** 6018,6023 ****
--- 6020,6026 ----
                        rm      The -- more -- prompt
                        r?      A |:confirm| query of some sort
                        !       Shell or external command is executing
+                       t       Terminal-Job mode: keys go to the job
                This is useful in the 'statusline' option or when used
                with |remote_expr()| In most other places it always returns
                "c" or "n".
***************
*** 8090,8099 ****
                string is returned.
                {only available when compiled with the |+terminal| feature}
  
! term_gettty({buf})                                    *term_gettty()*
                Get the name of the controlling terminal associated with
!               terminal window {buf}.
!               {buf} is used as with |term_getsize()|.
                {only available when compiled with the |+terminal| feature}
  
  term_list()                                           *term_list()*
--- 8094,8106 ----
                string is returned.
                {only available when compiled with the |+terminal| feature}
  
! term_gettty({buf} [, {input}])                                *term_gettty()*
                Get the name of the controlling terminal associated with
!               terminal window {buf}.  {buf} is used as with |term_getsize()|.
! 
!               When {input} is omitted or 0, return the name for writing
!               (stdout). When {input} is 1 return the name for reading
!               (stdin). On UNIX, both return same name.
                {only available when compiled with the |+terminal| feature}
  
  term_list()                                           *term_list()*
***************
*** 8171,8180 ****
                                     specified "botright sbuf %d" is used
                   "eof_chars"       Text to send after all buffer lines were
                                     written to the terminal.  When not set
!                                    CTRL-D is used. For Python use CTRL-Z or
!                                    "exit()". For a shell use "exit".  A CR
!                                    is always added.
!                                    {only on MS-Windows}
  
                {only available when compiled with the |+terminal| feature}
  
--- 8178,8186 ----
                                     specified "botright sbuf %d" is used
                   "eof_chars"       Text to send after all buffer lines were
                                     written to the terminal.  When not set
!                                    CTRL-D is used on MS-Windows. For Python
!                                    use CTRL-Z or "exit()". For a shell use
!                                    "exit".  A CR is always added.
  
                {only available when compiled with the |+terminal| feature}
  
*** ../vim-8.0.1073/src/channel.c       2017-09-02 17:18:31.226946592 +0200
--- src/channel.c       2017-09-08 14:20:45.521339375 +0200
***************
*** 969,975 ****
--- 969,981 ----
            if ((part == PART_IN || channel->CH_IN_FD != *fd)
                    && (part == PART_OUT || channel->CH_OUT_FD != *fd)
                    && (part == PART_ERR || channel->CH_ERR_FD != *fd))
+           {
+ #ifdef WIN32
+               if (channel->ch_named_pipe)
+                   DisconnectNamedPipe((HANDLE)fd);
+ #endif
                fd_close(*fd);
+           }
        }
        *fd = INVALID_FD;
  
***************
*** 3086,3092 ****
            if (r && nread > 0)
                return CW_READY;
            if (r == 0)
!               return CW_ERROR;
  
            /* perhaps write some buffer lines */
            channel_write_any_lines();
--- 3092,3111 ----
            if (r && nread > 0)
                return CW_READY;
            if (r == 0)
!           {
!               DWORD err = GetLastError();
! 
!               if (err != ERROR_BAD_PIPE && err != ERROR_BROKEN_PIPE)
!                   return CW_ERROR;
! 
!               if (channel->ch_named_pipe)
!               {
!                   DisconnectNamedPipe((HANDLE)fd);
!                   ConnectNamedPipe((HANDLE)fd, NULL);
!               }
!               else
!                   return CW_ERROR;
!           }
  
            /* perhaps write some buffer lines */
            channel_write_any_lines();
***************
*** 3670,3676 ****
--- 3689,3708 ----
        if (part == PART_SOCK)
            res = sock_write(fd, (char *)buf, len);
        else
+       {
            res = fd_write(fd, (char *)buf, len);
+ #ifdef WIN32
+           if (channel->ch_named_pipe)
+           {
+               if (res < 0)
+               {
+                   DisconnectNamedPipe((HANDLE)fd);
+                   ConnectNamedPipe((HANDLE)fd, NULL);
+               }
+           }
+ #endif
+ 
+       }
        if (res < 0 && (errno == EWOULDBLOCK
  #ifdef EAGAIN
                        || errno == EAGAIN
***************
*** 4849,4855 ****
      }
      mch_clear_job(job);
  
!     vim_free(job->jv_tty_name);
      vim_free(job->jv_stoponexit);
      free_callback(job->jv_exit_cb, job->jv_exit_partial);
  }
--- 4881,4888 ----
      }
      mch_clear_job(job);
  
!     vim_free(job->jv_tty_in);
!     vim_free(job->jv_tty_out);
      vim_free(job->jv_stoponexit);
      free_callback(job->jv_exit_cb, job->jv_exit_partial);
  }
***************
*** 5503,5510 ****
      nr = job->jv_proc_info.dwProcessId;
  #endif
      dict_add_nr_str(dict, "process", nr, NULL);
!     dict_add_nr_str(dict, "tty", 0L,
!                  job->jv_tty_name != NULL ? job->jv_tty_name : (char_u *)"");
  
      dict_add_nr_str(dict, "exitval", job->jv_exitval, NULL);
      dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);
--- 5536,5545 ----
      nr = job->jv_proc_info.dwProcessId;
  #endif
      dict_add_nr_str(dict, "process", nr, NULL);
!     dict_add_nr_str(dict, "tty_in", 0L,
!                  job->jv_tty_in != NULL ? job->jv_tty_in : (char_u *)"");
!     dict_add_nr_str(dict, "tty_out", 0L,
!                  job->jv_tty_out != NULL ? job->jv_tty_out : (char_u *)"");
  
      dict_add_nr_str(dict, "exitval", job->jv_exitval, NULL);
      dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);
*** ../vim-8.0.1073/src/evalfunc.c      2017-09-04 20:34:15.126492821 +0200
--- src/evalfunc.c      2017-09-08 14:11:56.264810129 +0200
***************
*** 843,849 ****
      {"term_getsize",  1, 1, f_term_getsize},
      {"term_getstatus",        1, 1, f_term_getstatus},
      {"term_gettitle", 1, 1, f_term_gettitle},
!     {"term_gettty",   1, 1, f_term_gettty},
      {"term_list",     0, 0, f_term_list},
      {"term_scrape",   2, 2, f_term_scrape},
      {"term_sendkeys", 2, 2, f_term_sendkeys},
--- 843,849 ----
      {"term_getsize",  1, 1, f_term_getsize},
      {"term_getstatus",        1, 1, f_term_getstatus},
      {"term_gettitle", 1, 1, f_term_gettitle},
!     {"term_gettty",   1, 2, f_term_gettty},
      {"term_list",     0, 0, f_term_list},
      {"term_scrape",   2, 2, f_term_scrape},
      {"term_sendkeys", 2, 2, f_term_sendkeys},
*** ../vim-8.0.1073/src/os_unix.c       2017-09-05 23:32:33.595883323 +0200
--- src/os_unix.c       2017-09-08 14:11:56.264810129 +0200
***************
*** 5263,5269 ****
            && (!(use_file_for_in || use_null_for_in)
                || !(use_file_for_in || use_null_for_out)
                || !(use_out_for_err || use_file_for_err || use_null_for_err)))
!       open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
  
      /* TODO: without the channel feature connect the child to /dev/null? */
      /* Open pipes for stdin, stdout, stderr. */
--- 5263,5273 ----
            && (!(use_file_for_in || use_null_for_in)
                || !(use_file_for_in || use_null_for_out)
                || !(use_out_for_err || use_file_for_err || use_null_for_err)))
!     {
!       open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
!       if (job->jv_tty_out != NULL)
!           job->jv_tty_in = vim_strsave(job->jv_tty_out);
!     }
  
      /* TODO: without the channel feature connect the child to /dev/null? */
      /* Open pipes for stdin, stdout, stderr. */
***************
*** 5687,5693 ****
      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();
--- 5691,5699 ----
      int               pty_slave_fd = -1;
      channel_T *channel;
  
!     open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
!     if (job->jv_tty_out != NULL)
!       job->jv_tty_in = vim_strsave(job->jv_tty_out);
      close(pty_slave_fd);
  
      channel = add_channel();
*** ../vim-8.0.1073/src/structs.h       2017-09-02 17:18:31.230946566 +0200
--- src/structs.h       2017-09-08 14:20:53.785285992 +0200
***************
*** 1487,1493 ****
      PROCESS_INFORMATION       jv_proc_info;
      HANDLE            jv_job_object;
  #endif
!     char_u    *jv_tty_name;   /* controlling tty, allocated */
      jobstatus_T       jv_status;
      char_u    *jv_stoponexit; /* allocated */
      int               jv_exitval;
--- 1487,1494 ----
      PROCESS_INFORMATION       jv_proc_info;
      HANDLE            jv_job_object;
  #endif
!     char_u    *jv_tty_in;     /* controlling tty input, allocated */
!     char_u    *jv_tty_out;    /* controlling tty output, allocated */
      jobstatus_T       jv_status;
      char_u    *jv_stoponexit; /* allocated */
      int               jv_exitval;
***************
*** 1652,1657 ****
--- 1653,1661 ----
                                /* callback for Netbeans when channel is
                                 * closed */
  
+ #ifdef WIN32
+     int               ch_named_pipe;  /* using named pipe instead of pty */
+ #endif
      char_u    *ch_callback;   /* call when any msg is not handled */
      partial_T *ch_partial;
      char_u    *ch_close_cb;   /* call when channel is closed */
*** ../vim-8.0.1073/src/terminal.c      2017-09-05 23:30:57.764519090 +0200
--- src/terminal.c      2017-09-08 14:37:17.934926887 +0200
***************
*** 38,45 ****
   * in tl_scrollback are no longer used.
   *
   * TODO:
!  * - ":term NONE" does not work on MS-Windows.
!  *   https://github.com/vim/vim/pull/2056
   * - Redirecting output does not work on MS-Windows.
   * - implement term_setsize()
   * - add test for giving error for invalid 'termsize' value.
--- 38,44 ----
   * in tl_scrollback are no longer used.
   *
   * TODO:
!  * - patch to use GUI or cterm colors for vterm. Yasuhiro, #2067
   * - Redirecting output does not work on MS-Windows.
   * - implement term_setsize()
   * - add test for giving error for invalid 'termsize' value.
***************
*** 97,103 ****
  
      /* used when tl_job is NULL and only a pty was created */
      int               tl_tty_fd;
!     char_u    *tl_tty_name;
  
      int               tl_normal_mode; /* TRUE: Terminal-Normal mode */
      int               tl_channel_closed;
--- 96,103 ----
  
      /* used when tl_job is NULL and only a pty was created */
      int               tl_tty_fd;
!     char_u    *tl_tty_in;
!     char_u    *tl_tty_out;
  
      int               tl_normal_mode; /* TRUE: Terminal-Normal mode */
      int               tl_channel_closed;
***************
*** 2666,2679 ****
  {
      buf_T     *buf = term_get_buf(argvars);
      char_u    *p;
  
      rettv->v_type = VAR_STRING;
      if (buf == NULL)
        return;
!     if (buf->b_term->tl_job != NULL)
!       p = buf->b_term->tl_job->jv_tty_name;
!     else
!       p = buf->b_term->tl_tty_name;
      if (p != NULL)
        rettv->vval.v_string = vim_strsave(p);
  }
--- 2666,2697 ----
  {
      buf_T     *buf = term_get_buf(argvars);
      char_u    *p;
+     int               num = 0;
  
      rettv->v_type = VAR_STRING;
      if (buf == NULL)
        return;
!     if (argvars[1].v_type != VAR_UNKNOWN)
!       num = get_tv_number(&argvars[1]);
! 
!     switch (num)
!     {
!       case 0:
!           if (buf->b_term->tl_job != NULL)
!               p = buf->b_term->tl_job->jv_tty_out;
!           else
!               p = buf->b_term->tl_tty_out;
!           break;
!       case 1:
!           if (buf->b_term->tl_job != NULL)
!               p = buf->b_term->tl_job->jv_tty_in;
!           else
!               p = buf->b_term->tl_tty_in;
!           break;
!       default:
!           EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
!           return;
!     }
      if (p != NULL)
        rettv->vval.v_string = vim_strsave(p);
  }
***************
*** 3055,3061 ****
      HANDLE        child_thread_handle;
      void          *winpty_err;
      void          *spawn_config = NULL;
-     char          buf[MAX_PATH];
      garray_T      ga;
      char_u        *cmd;
  
--- 3073,3078 ----
***************
*** 3094,3100 ****
      if (term->tl_winpty == NULL)
        goto failed;
  
-     /* TODO: if the command is "NONE" only create a pty. */
      spawn_config = winpty_spawn_config_new(
            WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN |
                WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN,
--- 3111,3116 ----
***************
*** 3162,3170 ****
      job->jv_proc_info.dwProcessId = GetProcessId(child_process_handle);
      job->jv_job_object = jo;
      job->jv_status = JOB_STARTED;
!     sprintf(buf, "winpty://%lu",
!           GetProcessId(winpty_agent_process(term->tl_winpty)));
!     job->jv_tty_name = vim_strsave((char_u*)buf);
      ++job->jv_refcount;
      term->tl_job = job;
  
--- 3178,3187 ----
      job->jv_proc_info.dwProcessId = GetProcessId(child_process_handle);
      job->jv_job_object = jo;
      job->jv_status = JOB_STARTED;
!     job->jv_tty_in = utf16_to_enc(
!           (short_u*)winpty_conin_name(term->tl_winpty), NULL);
!     job->jv_tty_out = utf16_to_enc(
!           (short_u*)winpty_conout_name(term->tl_winpty), NULL);
      ++job->jv_refcount;
      term->tl_job = job;
  
***************
*** 3205,3213 ****
  }
  
      static int
! create_pty_only(term_T *term, jobopt_T *opt)
  {
!     /* TODO: implement this */
      return FAIL;
  }
  
--- 3222,3289 ----
  }
  
      static int
! create_pty_only(term_T *term, jobopt_T *options)
  {
!     HANDLE        hPipeIn = INVALID_HANDLE_VALUE;
!     HANDLE        hPipeOut = INVALID_HANDLE_VALUE;
!     char          in_name[80], out_name[80];
!     channel_T     *channel = NULL;
! 
!     create_vterm(term, term->tl_rows, term->tl_cols);
! 
!     vim_snprintf(in_name, sizeof(in_name), "\\\\.\\pipe\\vim-%d-in-%d",
!           GetCurrentProcessId(),
!           curbuf->b_fnum);
!     hPipeIn = CreateNamedPipe(in_name, PIPE_ACCESS_OUTBOUND,
!           PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
!           PIPE_UNLIMITED_INSTANCES,
!           0, 0, NMPWAIT_NOWAIT, NULL);
!     if (hPipeIn == INVALID_HANDLE_VALUE)
!       goto failed;
! 
!     vim_snprintf(out_name, sizeof(out_name), "\\\\.\\pipe\\vim-%d-out-%d",
!           GetCurrentProcessId(),
!           curbuf->b_fnum);
!     hPipeOut = CreateNamedPipe(out_name, PIPE_ACCESS_INBOUND,
!           PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
!           PIPE_UNLIMITED_INSTANCES,
!           0, 0, 0, NULL);
!     if (hPipeOut == INVALID_HANDLE_VALUE)
!       goto failed;
! 
!     ConnectNamedPipe(hPipeIn, NULL);
!     ConnectNamedPipe(hPipeOut, NULL);
! 
!     term->tl_job = job_alloc();
!     if (term->tl_job == NULL)
!       goto failed;
!     ++term->tl_job->jv_refcount;
! 
!     /* behave like the job is already finished */
!     term->tl_job->jv_status = JOB_FINISHED;
! 
!     channel = add_channel();
!     if (channel == NULL)
!       goto failed;
!     term->tl_job->jv_channel = channel;
!     channel->ch_keep_open = TRUE;
!     channel->ch_named_pipe = TRUE;
! 
!     channel_set_pipes(channel,
!       (sock_T)hPipeIn,
!       (sock_T)hPipeOut,
!       (sock_T)hPipeOut);
!     channel_set_job(channel, term->tl_job, options);
!     term->tl_job->jv_tty_in = vim_strsave((char_u*)in_name);
!     term->tl_job->jv_tty_out = vim_strsave((char_u*)out_name);
! 
!     return OK;
! 
! failed:
!     if (hPipeIn != NULL)
!       CloseHandle(hPipeIn);
!     if (hPipeOut != NULL)
!       CloseHandle(hPipeOut);
      return FAIL;
  }
  
***************
*** 3234,3240 ****
      static void
  term_report_winsize(term_T *term, int rows, int cols)
  {
!     winpty_set_size(term->tl_winpty, cols, rows, NULL);
  }
  
      int
--- 3310,3317 ----
      static void
  term_report_winsize(term_T *term, int rows, int cols)
  {
!     if (term->tl_winpty)
!       winpty_set_size(term->tl_winpty, cols, rows, NULL);
  }
  
      int
*** ../vim-8.0.1073/src/testdir/test_terminal.vim       2017-09-05 
20:29:20.664205036 +0200
--- src/testdir/test_terminal.vim       2017-09-08 14:11:56.268810103 +0200
***************
*** 36,46 ****
  func Test_terminal_basic()
    let buf = Run_shell_in_terminal({})
    if has("unix")
!     call assert_match("^/dev/", job_info(g:job).tty)
!     call assert_match("^/dev/", term_gettty(''))
    else
!     call assert_match("^winpty://", job_info(g:job).tty)
!     call assert_match("^winpty://", term_gettty(''))
    endif
    call assert_equal('t', mode())
    call assert_match('%aR[^\n]*running]', execute('ls'))
--- 36,46 ----
  func Test_terminal_basic()
    let buf = Run_shell_in_terminal({})
    if has("unix")
!     call assert_match('^/dev/', job_info(g:job).tty_out)
!     call assert_match('^/dev/', term_gettty(''))
    else
!     call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out)
!     call assert_match('^\\\\.\\pipe\\', term_gettty(''))
    endif
    call assert_equal('t', mode())
    call assert_match('%aR[^\n]*running]', execute('ls'))
***************
*** 539,548 ****
  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
--- 539,544 ----
***************
*** 550,560 ****
    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
  
--- 546,565 ----
    let buf = term_start('NONE', {})
    call assert_notequal(0, buf)
  
!   let pty = job_info(term_getjob(buf))['tty_out']
    call assert_notequal('', pty)
!   if has('win32')
!     silent exe '!cmd /c "echo look here > ' . pty . '"'
!   else
!     call system('echo "look here" > ' . pty)
!   endif
    call term_wait(buf)
! 
!   let result = term_getline(buf, 1)
!   if has('win32')
!     let result = substitute(result, '\s\+$', '', '')
!   endif
!   call assert_equal('look here', result)
    bwipe!
  endfunc
  
***************
*** 600,605 ****
--- 605,611 ----
      call WaitFor('len(readfile("Xfile")) > 0')
      call assert_match('123', readfile('Xfile')[0])
      call delete('Xfile')
+     bwipe
    endif
  
    if has('unix')
***************
*** 608,613 ****
--- 614,620 ----
      call WaitFor('len(readfile("Xfile")) > 0')
      call assert_match('executing job failed', readfile('Xfile')[0])
      call delete('Xfile')
+     bwipe
  
      call writefile(['one line'], 'Xfile')
      let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
*** ../vim-8.0.1073/src/version.c       2017-09-08 13:59:16.761754116 +0200
--- src/version.c       2017-09-08 14:14:33.307779650 +0200
***************
*** 771,772 ****
--- 771,774 ----
  {   /* Add new patch number below this line */
+ /**/
+     1074,
  /**/

-- 
% cat /usr/include/life.h
void life(void);

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