Patch 8.0.0797
Problem:    Finished job in terminal window is not handled.
Solution:   Add the scrollback buffer.  Use it to fill the buffer when the job
            has ended.
Files:      src/terminal.c, src/screen.c, src/proto/terminal.pro,
            src/channel.c, src/os_unix.c, src/buffer.c


*** ../vim-8.0.0796/src/terminal.c      2017-07-28 15:11:34.267537205 +0200
--- src/terminal.c      2017-07-28 21:45:01.385884157 +0200
***************
*** 33,54 ****
   * while, if the terminal window is visible, the screen contents is drawn.
   *
   * TODO:
!  * - if 'term' starts witth "xterm" use it for $TERM.
!  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
!  * - include functions from #1871
!  * - do not store terminal buffer in viminfo.  Or prefix term:// ?
!  * - Add a scrollback buffer (contains lines to scroll off the top).
!  *   Can use the buf_T lines, store attributes somewhere else?
   * - When the job ends:
-  *   - Write "-- JOB ENDED --" in the terminal.
-  *   - Put the terminal contents in the scrollback buffer.
-  *   - Free the terminal emulator.
   *   - Display the scrollback buffer (but with attributes).
   *     Make the buffer not modifiable, drop attributes when making changes.
   *   - Need an option or argument to drop the window+buffer right away, to be
   *     used for a shell or Vim.
   * - add a character in :ls output
   * - when closing window and job has not ended, make terminal hidden?
   * - don't allow exiting Vim when a terminal is still running a job
   * - use win_del_lines() to make scroll-up efficient.
   * - add test for giving error for invalid 'termsize' value.
--- 33,51 ----
   * while, if the terminal window is visible, the screen contents is drawn.
   *
   * TODO:
!  * - For the scrollback buffer store lines in the buffer, only attributes in
!  *   tl_scrollback.
   * - When the job ends:
   *   - Display the scrollback buffer (but with attributes).
   *     Make the buffer not modifiable, drop attributes when making changes.
   *   - Need an option or argument to drop the window+buffer right away, to be
   *     used for a shell or Vim.
+  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
+  * - Patch for functions: Yasuhiro Matsumoto, #1871
+  * - do not store terminal buffer in viminfo.  Or prefix term:// ?
   * - add a character in :ls output
   * - when closing window and job has not ended, make terminal hidden?
+  * - when closing window and job has ended, make buffer hidden?
   * - don't allow exiting Vim when a terminal is still running a job
   * - use win_del_lines() to make scroll-up efficient.
   * - add test for giving error for invalid 'termsize' value.
***************
*** 80,85 ****
--- 77,87 ----
  
  #include "libvterm/include/vterm.h"
  
+ typedef struct sb_line_S {
+     int                   sb_cols;    /* can differ per line */
+     VTermScreenCell *sb_cells;        /* allocated */
+ } sb_line_T;
+ 
  /* typedef term_T in structs.h */
  struct terminal_S {
      term_T    *tl_next;
***************
*** 106,111 ****
--- 108,115 ----
      int               tl_dirty_row_start; /* -1 if nothing dirty */
      int               tl_dirty_row_end;   /* row below last one to update */
  
+     garray_T  tl_scrollback;
+ 
      pos_T     tl_cursor;
      int               tl_cursor_visible;
  };
***************
*** 124,130 ****
   */
  static int term_and_job_init(term_T *term, int rows, int cols, char_u *cmd);
  static void term_report_winsize(term_T *term, int rows, int cols);
! static void term_free(term_T *term);
  
  /**************************************
   * 1. Generic code for all systems.
--- 128,134 ----
   */
  static int term_and_job_init(term_T *term, int rows, int cols, char_u *cmd);
  static void term_report_winsize(term_T *term, int rows, int cols);
! static void term_free_vterm(term_T *term);
  
  /**************************************
   * 1. Generic code for all systems.
***************
*** 179,184 ****
--- 183,189 ----
        return;
      term->tl_dirty_row_end = MAX_ROW;
      term->tl_cursor_visible = TRUE;
+     ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
  
      /* Open a new window or tab. */
      vim_memset(&split_ea, 0, sizeof(split_ea));
***************
*** 238,245 ****
      }
      else
      {
!       free_terminal(term);
!       curbuf->b_term = NULL;
  
        /* Wiping out the buffer will also close the window and call
         * free_terminal(). */
--- 243,249 ----
      }
      else
      {
!       free_terminal(curbuf);
  
        /* Wiping out the buffer will also close the window and call
         * free_terminal(). */
***************
*** 255,263 ****
   * Called when wiping out a buffer.
   */
      void
! free_terminal(term_T *term)
  {
      term_T    *tp;
  
      if (term == NULL)
        return;
--- 259,269 ----
   * Called when wiping out a buffer.
   */
      void
! free_terminal(buf_T *buf)
  {
+     term_T    *term = buf->b_term;
      term_T    *tp;
+     int               i;
  
      if (term == NULL)
        return;
***************
*** 279,288 ****
        job_unref(term->tl_job);
      }
  
!     term_free(term);
      vim_free(term->tl_title);
      vim_free(term->tl_status_text);
      vim_free(term);
  }
  
  /*
--- 285,299 ----
        job_unref(term->tl_job);
      }
  
!     for (i = 0; i < term->tl_scrollback.ga_len; ++i)
!       vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i) ->sb_cells);
!     ga_clear(&term->tl_scrollback);
! 
!     term_free_vterm(term);
      vim_free(term->tl_title);
      vim_free(term->tl_status_text);
      vim_free(term);
+     buf->b_term = NULL;
  }
  
  /*
***************
*** 344,349 ****
--- 355,365 ----
      size_t    len = STRLEN(msg);
      term_T    *term = buffer->b_term;
  
+     if (term->tl_vterm == NULL)
+     {
+       ch_logn(channel, "NOT writing %d bytes to terminal", (int)len);
+       return;
+     }
      ch_logn(channel, "writing %d bytes to terminal", (int)len);
      term_write_job_output(term, msg, len);
  
***************
*** 459,464 ****
--- 475,489 ----
  }
  
  /*
+  * Return TRUE if the job for "buf" is still running.
+  */
+     static int
+ term_job_running(term_T *term)
+ {
+     return term->tl_job != NULL && term->tl_job->jv_status == JOB_STARTED;
+ }
+ 
+ /*
   * Get a key from the user without mapping.
   * TODO: use terminal mode mappings.
   */
***************
*** 480,487 ****
   * 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.
   */
!     void
  terminal_loop(void)
  {
      char      buf[KEY_BUF_LEN];
--- 505,514 ----
   * 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.
+  * Returns OK if a typed character is to be handled in Normal mode, FAIL if
+  * the terminal was closed.
   */
!     int
  terminal_loop(void)
  {
      char      buf[KEY_BUF_LEN];
***************
*** 491,496 ****
--- 518,527 ----
      int               dragging_outside = FALSE;
      int               termkey = 0;
  
+     if (curbuf->b_term->tl_vterm == NULL || !term_job_running(curbuf->b_term))
+       /* job finished */
+       return OK;
+ 
      if (*curwin->w_p_tk != NUL)
        termkey = string_to_key(curwin->w_p_tk, TRUE);
  
***************
*** 500,505 ****
--- 531,540 ----
        update_screen(0);
        update_cursor(curbuf->b_term, FALSE);
        c = term_vgetc();
+       if (curbuf->b_term->tl_vterm == NULL
+                                         || !term_job_running(curbuf->b_term))
+           /* job finished while waiting for a character */
+           break;
  
        if (c == (termkey == 0 ? Ctrl_W : termkey))
        {
***************
*** 511,516 ****
--- 546,555 ----
  #ifdef FEAT_CMDL_INFO
            clear_showcmd();
  #endif
+           if (curbuf->b_term->tl_vterm == NULL
+                                         || !term_job_running(curbuf->b_term))
+               /* job finished while waiting for a character */
+               break;
  
            if (termkey == 0 && c == '.')
                /* "CTRL-W .": send CTRL-W to the job */
***************
*** 519,525 ****
            {
                stuffcharReadbuff(Ctrl_W);
                stuffcharReadbuff(c);
!               return;
            }
        }
  
--- 558,564 ----
            {
                stuffcharReadbuff(Ctrl_W);
                stuffcharReadbuff(c);
!               return OK;
            }
        }
  
***************
*** 529,535 ****
            case NUL:
            case K_ZERO:
                stuffcharReadbuff(c);
!               return;
  
            case K_IGNORE: continue;
  
--- 568,574 ----
            case NUL:
            case K_ZERO:
                stuffcharReadbuff(c);
!               return OK;
  
            case K_IGNORE: continue;
  
***************
*** 561,567 ****
                    /* click outside the current window */
                    stuffcharReadbuff(c);
                    mouse_was_outside = TRUE;
!                   return;
                }
        }
        mouse_was_outside = FALSE;
--- 600,606 ----
                    /* click outside the current window */
                    stuffcharReadbuff(c);
                    mouse_was_outside = TRUE;
!                   return OK;
                }
        }
        mouse_was_outside = FALSE;
***************
*** 571,616 ****
        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);
!     }
! }
! 
! /*
!  * 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);
      }
! }
! 
! /*
!  * Return TRUE if the job for "buf" is still running.
!  */
!     static int
! term_job_running(term_T *term)
! {
!     return term->tl_job != NULL && term->tl_job->jv_status == JOB_STARTED;
  }
  
      static void
--- 610,618 ----
        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
***************
*** 740,745 ****
--- 742,889 ----
      return 1;
  }
  
+ /*
+  * Handle a line that is pushed off the top of the screen.
+  */
+     static int
+ handle_pushline(int cols, const VTermScreenCell *cells, void *user)
+ {
+     term_T    *term = (term_T *)user;
+ 
+     /* TODO: Limit the number of lines that are stored. */
+     /* TODO: put the text in the buffer. */
+     if (ga_grow(&term->tl_scrollback, 1) == OK)
+     {
+       VTermScreenCell *p;
+       int len;
+       int i;
+ 
+       /* do not store empty cells at the end */
+       for (i = 0; i < cols; ++i)
+           if (cells[i].chars[0] != 0)
+               len = i + 1;
+ 
+       p = (VTermScreenCell *)alloc((int)sizeof(VTermScreenCell) * len);
+       if (p != NULL)
+       {
+           sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+                                                 + term->tl_scrollback.ga_len;
+ 
+           mch_memmove(p, cells, sizeof(VTermScreenCell) * len);
+           line->sb_cols = len;
+           line->sb_cells = p;
+           ++term->tl_scrollback.ga_len;
+       }
+     }
+     return 0; /* ignored */
+ }
+ 
+ /*
+  * Fill the buffer with the scrollback lines and current lines of the 
terminal.
+  * Called after the job has ended.
+  */
+     static void
+ move_scrollback_to_buffer(term_T *term)
+ {
+     linenr_T      lnum;
+     garray_T      ga;
+     int                   c;
+     int                   col;
+     int                   i;
+     win_T         *wp;
+     int                   len;
+     int                   lines_skipped = 0;
+     VTermPos      pos;
+     VTermScreenCell cell;
+     VTermScreenCell *p;
+     VTermScreen           *screen = vterm_obtain_screen(term->tl_vterm);
+ 
+     /* Append the the visible lines to the scrollback. */
+     for (pos.row = 0; pos.row < term->tl_rows; ++pos.row)
+     {
+       len = 0;
+       for (pos.col = 0; pos.col < term->tl_cols; ++pos.col)
+           if (vterm_screen_get_cell(screen, pos, &cell) != 0
+                                                      && cell.chars[0] != NUL)
+               len = pos.col + 1;
+ 
+       if (len > 0)
+       {
+           while (lines_skipped > 0)
+           {
+               /* Line was skipped, add an empty line. */
+               --lines_skipped;
+               if (ga_grow(&term->tl_scrollback, 1) == OK)
+               {
+                   sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+                                                 + term->tl_scrollback.ga_len;
+ 
+                   line->sb_cols = 0;
+                   line->sb_cells = NULL;
+                   ++term->tl_scrollback.ga_len;
+               }
+           }
+ 
+           p = (VTermScreenCell *)alloc((int)sizeof(VTermScreenCell) * len);
+           if (p != NULL && ga_grow(&term->tl_scrollback, 1) == OK)
+           {
+               sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+                                                 + term->tl_scrollback.ga_len;
+ 
+               for (pos.col = 0; pos.col < len; ++pos.col)
+               {
+                   if (vterm_screen_get_cell(screen, pos, &cell) == 0)
+                       vim_memset(p + pos.col, 0, sizeof(cell));
+                   else
+                       p[pos.col] = cell;
+               }
+               line->sb_cols = len;
+               line->sb_cells = p;
+               ++term->tl_scrollback.ga_len;
+           }
+           else
+               vim_free(p);
+       }
+     }
+ 
+     /* Add the text to the buffer. */
+     ga_init2(&ga, 1, 100);
+     for (lnum = 0; lnum < term->tl_scrollback.ga_len; ++lnum)
+     {
+       sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data + lnum;
+ 
+       ga.ga_len = 0;
+       for (col = 0; col < line->sb_cols; ++col)
+           for (i = 0; (c = line->sb_cells[col].chars[i]) != 0 || i == 0; ++i)
+           {
+               if (ga_grow(&ga, MB_MAXBYTES) == FAIL)
+                   goto failed;
+               ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c,
+                                            (char_u *)ga.ga_data + ga.ga_len);
+           }
+       *((char_u *)ga.ga_data + ga.ga_len) = NUL;
+       ml_append_buf(term->tl_buffer, lnum, ga.ga_data, ga.ga_len + 1, FALSE);
+     }
+ 
+     /* Delete the empty line that was in the empty buffer. */
+     curbuf = term->tl_buffer;
+     ml_delete(lnum + 1, FALSE);
+     curbuf = curwin->w_buffer;
+ 
+ failed:
+     ga_clear(&ga);
+ 
+     FOR_ALL_WINDOWS(wp)
+     {
+       if (wp->w_buffer == term->tl_buffer)
+       {
+           wp->w_cursor.lnum = term->tl_buffer->b_ml.ml_line_count;
+           wp->w_cursor.col = 0;
+           wp->w_valid = 0;
+       }
+     }
+ }
+ 
  static VTermScreenCallbacks screen_callbacks = {
    handle_damage,      /* damage */
    handle_moverect,    /* moverect */
***************
*** 747,757 ****
    handle_settermprop, /* settermprop */
    NULL,                       /* bell */
    handle_resize,      /* resize */
!   NULL,                       /* sb_pushline */
    NULL                        /* sb_popline */
  };
  
  /*
   * Reverse engineer the RGB value into a cterm color index.
   * First color is 1.  Return 0 if no match found.
   */
--- 891,941 ----
    handle_settermprop, /* settermprop */
    NULL,                       /* bell */
    handle_resize,      /* resize */
!   handle_pushline,    /* sb_pushline */
    NULL                        /* sb_popline */
  };
  
  /*
+  * Called when a channel has been closed.
+  */
+     void
+ term_channel_closed(channel_T *ch)
+ {
+     term_T *term;
+     int           did_one = FALSE;
+ 
+     for (term = first_term; term != NULL; term = term->tl_next)
+       if (term->tl_job == ch->ch_job)
+       {
+           vim_free(term->tl_title);
+           term->tl_title = NULL;
+           vim_free(term->tl_status_text);
+           term->tl_status_text = NULL;
+ 
+           /* move the lines into the buffer and free the vterm */
+           move_scrollback_to_buffer(term);
+           term_free_vterm(term);
+ 
+           redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
+           did_one = TRUE;
+       }
+     if (did_one)
+     {
+       redraw_statuslines();
+ 
+       /* Need to break out of vgetc(). */
+       ins_char_typebuf(K_IGNORE);
+ 
+       if (curbuf->b_term != NULL)
+       {
+           if (curbuf->b_term->tl_job == ch->ch_job)
+               maketitle();
+           update_cursor(curbuf->b_term, TRUE);
+       }
+     }
+ }
+ 
+ /*
   * Reverse engineer the RGB value into a cterm color index.
   * First color is 1.  Return 0 if no match found.
   */
***************
*** 911,927 ****
  }
  
  /*
!  * Called to update the window that contains the terminal.
   */
!     void
  term_update_window(win_T *wp)
  {
      term_T    *term = wp->w_buffer->b_term;
!     VTerm     *vterm = term->tl_vterm;
!     VTermScreen *screen = vterm_obtain_screen(vterm);
!     VTermState        *state = vterm_obtain_state(vterm);
      VTermPos  pos;
  
      /*
       * If the window was resized a redraw will be triggered and we get here.
       * Adjust the size of the vterm unless 'termsize' specifies a fixed size.
--- 1095,1118 ----
  }
  
  /*
!  * Called to update the window that contains a terminal.
!  * Returns FAIL when there is no terminal running in this window.
   */
!     int
  term_update_window(win_T *wp)
  {
      term_T    *term = wp->w_buffer->b_term;
!     VTerm     *vterm;
!     VTermScreen *screen;
!     VTermState        *state;
      VTermPos  pos;
  
+     if (term == NULL || term->tl_vterm == NULL)
+       return FAIL;
+     vterm = term->tl_vterm;
+     screen = vterm_obtain_screen(vterm);
+     state = vterm_obtain_state(vterm);
+ 
      /*
       * If the window was resized a redraw will be triggered and we get here.
       * Adjust the size of the vterm unless 'termsize' specifies a fixed size.
***************
*** 1022,1027 ****
--- 1213,1220 ----
        screen_line(wp->w_winrow + pos.row, wp->w_wincol,
                                                  pos.col, wp->w_width, FALSE);
      }
+ 
+     return OK;
  }
  
  /*
***************
*** 1351,1364 ****
   * Free the terminal emulator part of "term".
   */
      static void
! term_free(term_T *term)
  {
      if (term->tl_winpty != NULL)
        winpty_free(term->tl_winpty);
      if (term->tl_winpty_config != NULL)
        winpty_config_free(term->tl_winpty_config);
      if (term->tl_vterm != NULL)
        vterm_free(term->tl_vterm);
  }
  
  /*
--- 1544,1560 ----
   * Free the terminal emulator part of "term".
   */
      static void
! term_free_vterm(term_T *term)
  {
      if (term->tl_winpty != NULL)
        winpty_free(term->tl_winpty);
+     term->tl_winpty = NULL;
      if (term->tl_winpty_config != NULL)
        winpty_config_free(term->tl_winpty_config);
+     term->tl_winpty_config = NULL;
      if (term->tl_vterm != NULL)
        vterm_free(term->tl_vterm);
+     term->tl_vterm = NULL
  }
  
  /*
***************
*** 1406,1415 ****
   * Free the terminal emulator part of "term".
   */
      static void
! term_free(term_T *term)
  {
      if (term->tl_vterm != NULL)
        vterm_free(term->tl_vterm);
  }
  
  /*
--- 1602,1612 ----
   * Free the terminal emulator part of "term".
   */
      static void
! term_free_vterm(term_T *term)
  {
      if (term->tl_vterm != NULL)
        vterm_free(term->tl_vterm);
+     term->tl_vterm = NULL;
  }
  
  /*
*** ../vim-8.0.0796/src/screen.c        2017-07-19 12:51:48.018228639 +0200
--- src/screen.c        2017-07-28 18:38:03.302769617 +0200
***************
*** 1200,1210 ****
  #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;
      }
--- 1200,1209 ----
  #endif
  
  #ifdef FEAT_TERMINAL
!     /* If this window contains a terminal, redraw works completely 
differently.
!      */
!     if (term_update_window(wp) == OK)
      {
        wp->w_redr_type = 0;
        return;
      }
***************
*** 6849,6862 ****
        p = NameBuff;
        len = (int)STRLEN(p);
  
!       if (wp->w_buffer->b_help
  #ifdef FEAT_QUICKFIX
                || wp->w_p_pvw
  #endif
                || bufIsChanged(wp->w_buffer)
                || wp->w_buffer->b_p_ro)
            *(p + len++) = ' ';
!       if (wp->w_buffer->b_help)
        {
            STRCPY(p + len, _("[Help]"));
            len += (int)STRLEN(p + len);
--- 6848,6861 ----
        p = NameBuff;
        len = (int)STRLEN(p);
  
!       if (bt_help(wp->w_buffer)
  #ifdef FEAT_QUICKFIX
                || wp->w_p_pvw
  #endif
                || bufIsChanged(wp->w_buffer)
                || wp->w_buffer->b_p_ro)
            *(p + len++) = ' ';
!       if (bt_help(wp->w_buffer))
        {
            STRCPY(p + len, _("[Help]"));
            len += (int)STRLEN(p + len);
*** ../vim-8.0.0796/src/proto/terminal.pro      2017-07-27 22:14:55.305968217 
+0200
--- src/proto/terminal.pro      2017-07-28 21:39:43.975980817 +0200
***************
*** 1,10 ****
  /* terminal.c */
  void ex_terminal(exarg_T *eap);
! void free_terminal(term_T *term);
  void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
! void terminal_loop(void);
! void term_job_ended(job_T *job);
! void term_update_window(win_T *wp);
  char_u *term_get_status_text(term_T *term);
  int set_ref_in_term(int copyID);
  /* vim: set ft=c : */
--- 1,10 ----
  /* terminal.c */
  void ex_terminal(exarg_T *eap);
! 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_channel_closed(channel_T *ch);
! int term_update_window(win_T *wp);
  char_u *term_get_status_text(term_T *term);
  int set_ref_in_term(int copyID);
  /* vim: set ft=c : */
*** ../vim-8.0.0796/src/channel.c       2017-07-23 19:50:39.036922744 +0200
--- src/channel.c       2017-07-28 20:24:44.785952120 +0200
***************
*** 2921,2926 ****
--- 2921,2930 ----
      }
  
      channel->ch_nb_close_cb = NULL;
+ 
+ #ifdef FEAT_TERMINAL
+     term_channel_closed(channel);
+ #endif
  }
  
  /*
***************
*** 4696,4705 ****
         * not use "job" after this! */
        job_free(job);
      }
- 
- #ifdef FEAT_TERMINAL
-     term_job_ended(job);
- #endif
  }
  
  /*
--- 4700,4705 ----
*** ../vim-8.0.0796/src/os_unix.c       2017-07-28 15:55:28.572158705 +0200
--- src/os_unix.c       2017-07-28 21:13:01.302365432 +0200
***************
*** 412,417 ****
--- 412,420 ----
  
  #ifdef MESSAGE_QUEUE
        parse_queued_messages();
+       /* If input was put directly in typeahead buffer bail out here. */
+       if (typebuf_changed(tb_change_cnt))
+           return 0;
  #endif
        if (wtime < 0 && did_start_blocking)
            /* blocking and already waited for p_ut */
*** ../vim-8.0.0796/src/buffer.c        2017-07-27 22:03:45.546703088 +0200
--- src/buffer.c        2017-07-28 21:39:51.959928375 +0200
***************
*** 858,864 ****
      channel_buffer_free(buf);
  #endif
  #ifdef FEAT_TERMINAL
!     free_terminal(buf->b_term);
  #endif
  
      buf_hashtab_remove(buf);
--- 858,864 ----
      channel_buffer_free(buf);
  #endif
  #ifdef FEAT_TERMINAL
!     free_terminal(buf);
  #endif
  
      buf_hashtab_remove(buf);
*** ../vim-8.0.0796/src/version.c       2017-07-28 18:01:54.042023391 +0200
--- src/version.c       2017-07-28 21:48:23.908535689 +0200
***************
*** 771,772 ****
--- 771,774 ----
  {   /* Add new patch number below this line */
+ /**/
+     797,
  /**/

-- 
Facepalm statement #4: "3000 year old graves?  That's not possible, it's only
2014!"

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