Patch 8.0.0718
Problem:    Output of job in terminal is not displayed.
Solution:   Connect the job output to the terminal.
Files:      src/channel.c, src/proto/channel.pro, src/terminal.c,
            src/proto/terminal.pro, src/channel.c, src/proto/channel.pro,
            src/evalfunc.c, src/screen.c, src/proto/screen.pro


*** ../vim-8.0.0717/src/channel.c       2017-07-15 17:01:50.350726204 +0200
--- src/channel.c       2017-07-15 22:18:35.029671290 +0200
***************
*** 171,177 ****
      }
  }
  
!     static void
  ch_logn(channel_T *ch, char *msg, int nr)
  {
      if (log_fd != NULL)
--- 171,177 ----
      }
  }
  
!     void
  ch_logn(channel_T *ch, char *msg, int nr)
  {
      if (log_fd != NULL)
***************
*** 2656,2662 ****
                /* JSON or JS mode: re-encode the message. */
                msg = json_encode(listtv, ch_mode);
            if (msg != NULL)
!               append_to_buffer(buffer, msg, channel, part);
        }
  
        if (callback != NULL)
--- 2656,2667 ----
                /* JSON or JS mode: re-encode the message. */
                msg = json_encode(listtv, ch_mode);
            if (msg != NULL)
!           {
!               if (buffer->b_term != NULL)
!                   write_to_term(buffer, msg, channel);
!               else
!                   append_to_buffer(buffer, msg, channel, part);
!           }
        }
  
        if (callback != NULL)
***************
*** 4889,4895 ****
   * "job_start()" function
   */
      job_T *
! job_start(typval_T *argvars)
  {
      job_T     *job;
      char_u    *cmd = NULL;
--- 4894,4900 ----
   * "job_start()" function
   */
      job_T *
! job_start(typval_T *argvars, jobopt_T *opt_arg)
  {
      job_T     *job;
      char_u    *cmd = NULL;
***************
*** 4912,4924 ****
      ga_init2(&ga, (int)sizeof(char*), 20);
  #endif
  
!     /* Default mode is NL. */
!     clear_job_options(&opt);
!     opt.jo_mode = MODE_NL;
!     if (get_job_options(&argvars[1], &opt,
            JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
                           + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL)
        goto theend;
  
      /* Check that when io is "file" that there is a file name. */
      for (part = PART_OUT; part < PART_COUNT; ++part)
--- 4917,4934 ----
      ga_init2(&ga, (int)sizeof(char*), 20);
  #endif
  
!     if (opt_arg != NULL)
!       opt = *opt_arg;
!     else
!     {
!       /* Default mode is NL. */
!       clear_job_options(&opt);
!       opt.jo_mode = MODE_NL;
!       if (get_job_options(&argvars[1], &opt,
            JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
                           + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL)
        goto theend;
+     }
  
      /* Check that when io is "file" that there is a file name. */
      for (part = PART_OUT; part < PART_COUNT; ++part)
*** ../vim-8.0.0717/src/proto/channel.pro       2016-12-01 15:34:04.087413921 
+0100
--- src/proto/channel.pro       2017-07-15 20:41:05.457918326 +0200
***************
*** 2,7 ****
--- 2,8 ----
  void ch_logfile(char_u *fname, char_u *opt);
  int ch_log_active(void);
  void ch_log(channel_T *ch, char *msg);
+ void ch_logn(channel_T *ch, char *msg, int nr);
  void ch_logs(channel_T *ch, char *msg, char *name);
  channel_T *add_channel(void);
  int has_any_channel(void);
***************
*** 63,69 ****
  void job_stop_on_exit(void);
  int has_pending_job(void);
  void job_check_ended(void);
! job_T *job_start(typval_T *argvars);
  char *job_status(job_T *job);
  void job_info(job_T *job, dict_T *dict);
  int job_stop(job_T *job, typval_T *argvars);
--- 64,70 ----
  void job_stop_on_exit(void);
  int has_pending_job(void);
  void job_check_ended(void);
! job_T *job_start(typval_T *argvars, jobopt_T *opt_arg);
  char *job_status(job_T *job);
  void job_info(job_T *job, dict_T *dict);
  int job_stop(job_T *job, typval_T *argvars);
*** ../vim-8.0.0717/src/terminal.c      2017-07-15 20:05:50.802053721 +0200
--- src/terminal.c      2017-07-15 22:53:26.785858885 +0200
***************
*** 28,33 ****
--- 28,35 ----
   * - remove term from first_term list when closing terminal.
   * - set buffer options to be scratch, hidden, nomodifiable, etc.
   * - set buffer name to command, add (1) to avoid duplicates.
+  * - if buffer is wiped, cleanup terminal, may stop job.
+  * - if the job ends, write "-- JOB ENDED --" in the terminal
   * - command line completion (command name)
   * - support fixed size when 'termsize' is "rowsXcols".
   * - support minimal size when 'termsize' is "rows*cols".
***************
*** 40,45 ****
--- 42,48 ----
   * - implement term_scrape()          inspect terminal screen
   * - implement term_open()            open terminal window
   * - implement term_getjob()
+  * - implement 'termkey'
   */
  
  #include "vim.h"
***************
*** 54,59 ****
--- 57,63 ----
  
      VTerm     *tl_vterm;
      job_T     *tl_job;
+     buf_T     *tl_buffer;
  
      /* Range of screen rows to update.  Zero based. */
      int               tl_dirty_row_start; /* -1 if nothing dirty */
***************
*** 99,104 ****
--- 103,109 ----
      term_T    *term;
      VTerm     *vterm;
      VTermScreen *screen;
+     jobopt_T  opt;
  
      if (check_restricted() || check_secure())
        return;
***************
*** 120,125 ****
--- 125,131 ----
        vim_free(term);
        return;
      }
+     term->tl_buffer = curbuf;
  
      curbuf->b_term = term;
      term->tl_next = first_term;
***************
*** 145,160 ****
      term->tl_vterm = vterm;
      screen = vterm_obtain_screen(vterm);
      vterm_screen_set_callbacks(screen, &screen_callbacks, term);
  
      argvars[0].v_type = VAR_STRING;
      argvars[0].vval.v_string = eap->arg;
-     argvars[1].v_type = VAR_UNKNOWN;
-     term->tl_job = job_start(argvars);
  
!     /* TODO: setup channels to/from job */
      /* Setup pty, see mch_call_shell(). */
  }
  
      static int
  handle_damage(VTermRect rect, void *user)
  {
--- 151,246 ----
      term->tl_vterm = vterm;
      screen = vterm_obtain_screen(vterm);
      vterm_screen_set_callbacks(screen, &screen_callbacks, term);
+     /* TODO: depends on 'encoding'. */
+     vterm_set_utf8(vterm, 1);
+     /* Required to initialize most things. */
+     vterm_screen_reset(screen, 1 /* hard */);
+ 
+     /* By default NL means CR-NL. */
+     vterm_input_write(vterm, "\x1b[20h", 5);
  
      argvars[0].v_type = VAR_STRING;
      argvars[0].vval.v_string = eap->arg;
  
!     clear_job_options(&opt);
!     opt.jo_mode = MODE_RAW;
!     opt.jo_out_mode = MODE_RAW;
!     opt.jo_err_mode = MODE_RAW;
!     opt.jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE;
!     opt.jo_io[PART_OUT] = JIO_BUFFER;
!     opt.jo_io[PART_ERR] = JIO_BUFFER;
!     opt.jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT));
!     opt.jo_io_buf[PART_OUT] = curbuf->b_fnum;
!     opt.jo_io_buf[PART_ERR] = curbuf->b_fnum;
!     opt.jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT));
! 
!     term->tl_job = job_start(argvars, &opt);
! 
!     /* TODO: setup channel to job */
      /* Setup pty, see mch_call_shell(). */
  }
  
+ /*
+  * Invoked when "msg" output from a job was received.  Write it to the 
terminal
+  * of "buffer".
+  */
+     void
+ write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
+ {
+     size_t    len = STRLEN(msg);
+     VTerm     *vterm = buffer->b_term->tl_vterm;
+ 
+     ch_logn(channel, "writing %d bytes to terminal", (int)len);
+     vterm_input_write(vterm, (char *)msg, len);
+     vterm_screen_flush_damage(vterm_obtain_screen(vterm));
+ 
+     /* TODO: only update once in a while. */
+     update_screen(0);
+     setcursor();
+     out_flush();
+ }
+ 
+ /*
+  * Called to update the window that contains the terminal.
+  */
+     void
+ term_update_window(win_T *wp)
+ {
+     int vterm_rows;
+     int vterm_cols;
+     VTerm *vterm = wp->w_buffer->b_term->tl_vterm;
+     VTermScreen *screen = vterm_obtain_screen(vterm);
+     VTermPos pos;
+ 
+     vterm_get_size(vterm, &vterm_rows, &vterm_cols);
+ 
+     /* TODO: Only redraw what changed. */
+     for (pos.row = 0; pos.row < wp->w_height; ++pos.row)
+     {
+       int off = screen_get_current_line_off();
+ 
+       if (pos.row < vterm_rows)
+           for (pos.col = 0; pos.col < wp->w_width && pos.col < vterm_cols;
+                                                                    ++pos.col)
+           {
+               VTermScreenCell cell;
+               int c;
+ 
+               vterm_screen_get_cell(screen, pos, &cell);
+               /* TODO: use cell.attrs and colors */
+               /* TODO: use cell.width */
+               /* TODO: multi-byte chars */
+               c = cell.chars[0];
+               ScreenLines[off] = c == NUL ? ' ' : c;
+               ScreenAttrs[off] = 0;
+               ++off;
+           }
+ 
+       screen_line(wp->w_winrow + pos.row, wp->w_wincol, pos.col, wp->w_width,
+                                                                       FALSE);
+     }
+ }
+ 
      static int
  handle_damage(VTermRect rect, void *user)
  {
***************
*** 162,188 ****
  
      term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row);
      term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row);
      return 1;
  }
  
      static int
  handle_moverect(VTermRect dest, VTermRect src, void *user)
  {
      /* TODO */
      return 1;
  }
  
    static int
  handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
  {
!     /* TODO: handle moving the cursor. */
      return 1;
  }
  
      static int
  handle_resize(int rows, int cols, void *user)
  {
      /* TODO: handle terminal resize. */
      return 1;
  }
  
--- 248,302 ----
  
      term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row);
      term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row);
+     redraw_buf_later(term->tl_buffer, NOT_VALID);
      return 1;
  }
  
      static int
  handle_moverect(VTermRect dest, VTermRect src, void *user)
  {
+     term_T    *term = (term_T *)user;
+ 
      /* TODO */
+     redraw_buf_later(term->tl_buffer, NOT_VALID);
      return 1;
  }
  
    static int
  handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
  {
!     term_T    *term = (term_T *)user;
!     win_T     *wp;
!     int               is_current = FALSE;
! 
!     FOR_ALL_WINDOWS(wp)
!     {
!       if (wp->w_buffer == term->tl_buffer)
!       {
!           /* TODO: limit to window size? */
!           wp->w_wrow = pos.row;
!           wp->w_wcol = pos.col;
!           if (wp == curwin)
!               is_current = TRUE;
!       }
!     }
! 
!     if (is_current)
!     {
!       setcursor();
!       out_flush();
!     }
! 
      return 1;
  }
  
      static int
  handle_resize(int rows, int cols, void *user)
  {
+     term_T    *term = (term_T *)user;
+ 
      /* TODO: handle terminal resize. */
+     redraw_buf_later(term->tl_buffer, NOT_VALID);
      return 1;
  }
  
***************
*** 201,210 ****
   * - Write output to channel.
   */
  
- /* TODO: function to read job output from the channel.
-  * write to vterm: vterm_input_write()
-  * This will invoke screen callbacks.
-  * call vterm_screen_flush_damage()
-  */
- 
  #endif /* FEAT_TERMINAL */
--- 315,318 ----
*** ../vim-8.0.0717/src/proto/terminal.pro      2017-07-07 11:53:29.515876528 
+0200
--- src/proto/terminal.pro      2017-07-15 21:37:51.732076242 +0200
***************
*** 1,3 ****
--- 1,5 ----
  /* terminal.c */
  void ex_terminal(exarg_T *eap);
+ void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
+ void term_update_window(win_T *wp);
  /* vim: set ft=c : */
*** ../vim-8.0.0717/src/channel.c       2017-07-15 17:01:50.350726204 +0200
--- src/channel.c       2017-07-15 22:18:35.029671290 +0200
***************
*** 171,177 ****
      }
  }
  
!     static void
  ch_logn(channel_T *ch, char *msg, int nr)
  {
      if (log_fd != NULL)
--- 171,177 ----
      }
  }
  
!     void
  ch_logn(channel_T *ch, char *msg, int nr)
  {
      if (log_fd != NULL)
***************
*** 2656,2662 ****
                /* JSON or JS mode: re-encode the message. */
                msg = json_encode(listtv, ch_mode);
            if (msg != NULL)
!               append_to_buffer(buffer, msg, channel, part);
        }
  
        if (callback != NULL)
--- 2656,2667 ----
                /* JSON or JS mode: re-encode the message. */
                msg = json_encode(listtv, ch_mode);
            if (msg != NULL)
!           {
!               if (buffer->b_term != NULL)
!                   write_to_term(buffer, msg, channel);
!               else
!                   append_to_buffer(buffer, msg, channel, part);
!           }
        }
  
        if (callback != NULL)
***************
*** 4889,4895 ****
   * "job_start()" function
   */
      job_T *
! job_start(typval_T *argvars)
  {
      job_T     *job;
      char_u    *cmd = NULL;
--- 4894,4900 ----
   * "job_start()" function
   */
      job_T *
! job_start(typval_T *argvars, jobopt_T *opt_arg)
  {
      job_T     *job;
      char_u    *cmd = NULL;
***************
*** 4912,4924 ****
      ga_init2(&ga, (int)sizeof(char*), 20);
  #endif
  
!     /* Default mode is NL. */
!     clear_job_options(&opt);
!     opt.jo_mode = MODE_NL;
!     if (get_job_options(&argvars[1], &opt,
            JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
                           + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL)
        goto theend;
  
      /* Check that when io is "file" that there is a file name. */
      for (part = PART_OUT; part < PART_COUNT; ++part)
--- 4917,4934 ----
      ga_init2(&ga, (int)sizeof(char*), 20);
  #endif
  
!     if (opt_arg != NULL)
!       opt = *opt_arg;
!     else
!     {
!       /* Default mode is NL. */
!       clear_job_options(&opt);
!       opt.jo_mode = MODE_NL;
!       if (get_job_options(&argvars[1], &opt,
            JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
                           + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL)
        goto theend;
+     }
  
      /* Check that when io is "file" that there is a file name. */
      for (part = PART_OUT; part < PART_COUNT; ++part)
*** ../vim-8.0.0717/src/proto/channel.pro       2016-12-01 15:34:04.087413921 
+0100
--- src/proto/channel.pro       2017-07-15 20:41:05.457918326 +0200
***************
*** 2,7 ****
--- 2,8 ----
  void ch_logfile(char_u *fname, char_u *opt);
  int ch_log_active(void);
  void ch_log(channel_T *ch, char *msg);
+ void ch_logn(channel_T *ch, char *msg, int nr);
  void ch_logs(channel_T *ch, char *msg, char *name);
  channel_T *add_channel(void);
  int has_any_channel(void);
***************
*** 63,69 ****
  void job_stop_on_exit(void);
  int has_pending_job(void);
  void job_check_ended(void);
! job_T *job_start(typval_T *argvars);
  char *job_status(job_T *job);
  void job_info(job_T *job, dict_T *dict);
  int job_stop(job_T *job, typval_T *argvars);
--- 64,70 ----
  void job_stop_on_exit(void);
  int has_pending_job(void);
  void job_check_ended(void);
! job_T *job_start(typval_T *argvars, jobopt_T *opt_arg);
  char *job_status(job_T *job);
  void job_info(job_T *job, dict_T *dict);
  int job_stop(job_T *job, typval_T *argvars);
*** ../vim-8.0.0717/src/evalfunc.c      2017-07-11 22:34:47.523932120 +0200
--- src/evalfunc.c      2017-07-15 20:46:46.739331963 +0200
***************
*** 6745,6751 ****
      rettv->v_type = VAR_JOB;
      if (check_restricted() || check_secure())
        return;
!     rettv->vval.v_job = job_start(argvars);
  }
  
  /*
--- 6745,6751 ----
      rettv->v_type = VAR_JOB;
      if (check_restricted() || check_secure())
        return;
!     rettv->vval.v_job = job_start(argvars, NULL);
  }
  
  /*
*** ../vim-8.0.0717/src/screen.c        2017-07-12 21:12:38.336024915 +0200
--- src/screen.c        2017-07-15 22:40:33.279714955 +0200
***************
*** 126,138 ****
  #endif
  static int win_line(win_T *, linenr_T, int, int, int nochange, proftime_T 
*syntax_tm);
  static int char_needs_redraw(int off_from, int off_to, int cols);
- #ifdef FEAT_RIGHTLEFT
- static void screen_line(int row, int coloff, int endcol, int clear_width, int 
rlflag);
- # define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c), (rl))
- #else
- static void screen_line(int row, int coloff, int endcol, int clear_width);
- # define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c))
- #endif
  #ifdef FEAT_WINDOWS
  static void draw_vsep_win(win_T *wp, int row);
  #endif
--- 126,131 ----
***************
*** 411,417 ****
                                screenline2 + r * cols,
                                (size_t)cols * sizeof(schar_T));
  #endif
!               SCREEN_LINE(cmdline_row + r, 0, cols, cols, FALSE);
            }
            ret = 4;
        }
--- 404,410 ----
                                screenline2 + r * cols,
                                (size_t)cols * sizeof(schar_T));
  #endif
!               screen_line(cmdline_row + r, 0, cols, cols, FALSE);
            }
            ret = 4;
        }
***************
*** 1192,1197 ****
--- 1185,1201 ----
      }
  #endif
  
+ #ifdef FEAT_TERMINAL
+     if (wp->w_buffer->b_term != NULL)
+     {
+       /* This window contains a terminal, redraw works completely
+        * differently. */
+       term_update_window(wp);
+       wp->w_redr_type = 0;
+       return;
+     }
+ #endif
+ 
  #ifdef FEAT_SEARCH_EXTRA
      init_search_hl(wp);
  #endif
***************
*** 2886,2892 ****
      }
  #endif
  
!     SCREEN_LINE(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp),
                                                     (int)W_WIDTH(wp), FALSE);
  
      /*
--- 2890,2896 ----
      }
  #endif
  
!     screen_line(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp),
                                                     (int)W_WIDTH(wp), FALSE);
  
      /*
***************
*** 3996,4002 ****
  #endif
                )
        {
!           SCREEN_LINE(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp),
                                                                  wp->w_p_rl);
            /* Pretend we have finished updating the window.  Except when
             * 'cursorcolumn' is set. */
--- 4000,4006 ----
  #endif
                )
        {
!           screen_line(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp),
                                                                  wp->w_p_rl);
            /* Pretend we have finished updating the window.  Except when
             * 'cursorcolumn' is set. */
***************
*** 5443,5449 ****
            }
  #endif
  
!           SCREEN_LINE(screen_row, W_WINCOL(wp), col,
                                                (int)W_WIDTH(wp), wp->w_p_rl);
            row++;
  
--- 5447,5453 ----
            }
  #endif
  
!           screen_line(screen_row, W_WINCOL(wp), col,
                                                (int)W_WIDTH(wp), wp->w_p_rl);
            row++;
  
***************
*** 5749,5759 ****
                )
        {
  #ifdef FEAT_CONCEAL
!           SCREEN_LINE(screen_row, W_WINCOL(wp), col - boguscols,
                                                (int)W_WIDTH(wp), wp->w_p_rl);
            boguscols = 0;
  #else
!           SCREEN_LINE(screen_row, W_WINCOL(wp), col,
                                                (int)W_WIDTH(wp), wp->w_p_rl);
  #endif
            ++row;
--- 5753,5763 ----
                )
        {
  #ifdef FEAT_CONCEAL
!           screen_line(screen_row, W_WINCOL(wp), col - boguscols,
                                                (int)W_WIDTH(wp), wp->w_p_rl);
            boguscols = 0;
  #else
!           screen_line(screen_row, W_WINCOL(wp), col,
                                                (int)W_WIDTH(wp), wp->w_p_rl);
  #endif
            ++row;
***************
*** 5959,5964 ****
--- 5963,5979 ----
      return FALSE;
  }
  
+ #if defined(FEAT_TERMINAL) || defined(PROTO)
+ /*
+  * Return the index in ScreenLines[] for the current screen line.
+  */
+     int
+ screen_get_current_line_off()
+ {
+     return (int)(current_ScreenLine - ScreenLines);
+ }
+ #endif
+ 
  /*
   * Move one "cooked" screen line to the screen, but only the characters that
   * have actually changed.  Handle insert/delete character.
***************
*** 5970,5985 ****
   *    When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
   *    When FALSE and "clear_width" > 0, clear columns "endcol" to 
"clear_width"
   */
!     static void
  screen_line(
      int           row,
      int           coloff,
      int           endcol,
!     int           clear_width
! #ifdef FEAT_RIGHTLEFT
!     , int   rlflag
! #endif
!     )
  {
      unsigned      off_from;
      unsigned      off_to;
--- 5985,5997 ----
   *    When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
   *    When FALSE and "clear_width" > 0, clear columns "endcol" to 
"clear_width"
   */
!     void
  screen_line(
      int           row,
      int           coloff,
      int           endcol,
!     int           clear_width,
!     int           rlflag UNUSED)
  {
      unsigned      off_from;
      unsigned      off_to;
*** ../vim-8.0.0717/src/proto/screen.pro        2017-04-30 19:39:32.650857838 
+0200
--- src/proto/screen.pro        2017-07-15 21:37:38.948173764 +0200
***************
*** 16,21 ****
--- 16,23 ----
  void update_single_line(win_T *wp, linenr_T lnum);
  void update_debug_sign(buf_T *buf, linenr_T lnum);
  void updateWindow(win_T *wp);
+ int screen_get_current_line_off(void);
+ void screen_line(int row, int coloff, int endcol, int clear_width, int 
rlflag);
  void rl_mirror(char_u *str);
  void status_redraw_all(void);
  void status_redraw_curbuf(void);
*** ../vim-8.0.0717/src/version.c       2017-07-15 20:05:50.802053721 +0200
--- src/version.c       2017-07-15 22:57:06.592204161 +0200
***************
*** 771,772 ****
--- 771,774 ----
  {   /* Add new patch number below this line */
+ /**/
+     718,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
163. You go outside for the fresh air (at -30 degrees) but open the
     window first to hear new mail arrive.

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