]> granicus.if.org Git - vim/commitdiff
patch 8.0.0813: cannot use a terminal window while the job is running v8.0.0813
authorBram Moolenaar <Bram@vim.org>
Sun, 30 Jul 2017 14:52:24 +0000 (16:52 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 30 Jul 2017 14:52:24 +0000 (16:52 +0200)
Problem:    Cannot use Vim commands in a terminal window while the job is
            running.
Solution:   Implement Terminal Normal mode.

runtime/doc/terminal.txt
src/main.c
src/normal.c
src/option.c
src/proto/terminal.pro
src/screen.c
src/terminal.c
src/version.c

index 89689463ac483771879139bc88a9526041895af5..1054037838c7c8579806a9e1e76c24df2bd27d8f 100644 (file)
@@ -1,4 +1,4 @@
-*terminal.txt* For Vim version 8.0.  Last change: 2017 Jul 28
+*terminal.txt* For Vim version 8.0.  Last change: 2017 Jul 30
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -33,24 +33,39 @@ Or to run a debugger: >
 The job runs asynchronously from Vim, the window will be updated to show
 output from the job, also  while editing in any other window.
 
+
 Typing ~
 
 When the keyboard focus is in the terminal window, typed keys will be send to
 the job.  This uses a pty when possible.  You can click outside of the
 terminal window to move keyboard focus elsewhere.
 
-Navigate between windows with CTRL-W commands.  E.g. CTRL-W CTRL-W moves focus
-to the next window.  Use "CTRL-W :" to edit an Ex command.  Use "CTRL-W ." to
-send a CTRL-W to the job in the terminal.
+CTRL-W can be used to navigate between windows and other CTRL-W commands, e.g.:
+       CTRL-W CTRL-W   move focus to the next window
+       CTRL-W :        enter an Ex command
+See |CTRL-W| for more commands.
+
+Special in the terminal window:                        *CTRL-W_.*  *CTRL-W_N* 
+       CTRL-W .        send a CTRL-W to the job in the terminal
+       CTRL-W N        go to Terminal Normal mode, see |Terminal-mode|
+
+See option 'termkey' for specifying another key instead of CTRL-W that
+will work like CTRL-W.  However, typing 'termkey' twice sends 'termkey' to
+the job.  For example:
+       'termkey' CTRL-W    move focus to the next window
+       'termkey' :         enter an Ex command
+       'termkey' 'termkey' send 'termkey' to the job in the terminal
+       'termkey' .         send a CTRL-W to the job in the terminal
+       'termkey' N         go to terminal Normal mode, see below
+       'termkey' CTRL-N    same as CTRL-W N
 
-See option 'termkey' for specifying another key that precedes a Vim command.
-Typing 'termkey' twice sends 'termkey' to the job.
 
 Size ~
 
 See option 'termsize' for controlling the size of the terminal window.
 (TODO: scrolling when the terminal is larger than the window)
 
+
 Syntax ~
 
 :ter[minal] [command]                          *:ter* *:terminal*
@@ -99,6 +114,25 @@ terminal.  |term_setsize()| can be used only when in the first or second mode,
 not when 'termsize' is "rowsXcols".
 
 
+Terminal Normal mode ~
+                                                       *Terminal-mode*
+When the job is running the contents of the terminal is under control of the
+job.  That includes the cursor position.  The terminal contents can change at
+any time.
+
+Use CTRL-W N (or 'termkey' N) to go to Terminal Normal mode.  Now the contents
+of the terminal window is under control of Vim, the job output is suspended.
+                                                       *E946*
+In this mode you can move the cursor around with the usual Vim commands,
+Visually mark text, yank text, etc.  But you cannot change the contents of the
+buffer.  The commands that would start insert mode, such as 'i' and 'a',
+return control of the window to the job.  Any pending output will now be
+displayed.
+
+In Terminal mode the statusline and window title show "(Terminal)".  If the
+job ends while in Terminal mode this changes to "(Terminal-finished)".
+
+
 Unix ~
 
 On Unix a pty is used to make it possible to run all kinds of commands.  You
index 268c256270eeee3812826c62464568675297caf1..81eb1a6799391309fe08e0432bd3c3661f8d1618 100644 (file)
@@ -1356,11 +1356,17 @@ main_loop(
        else
        {
 #ifdef FEAT_TERMINAL
-           if (curbuf->b_term != NULL && oa.op_type == OP_NOP
-                                                         && oa.regname == NUL)
-               terminal_loop();
+           if (term_use_loop() && oa.op_type == OP_NOP && oa.regname == NUL)
+           {
+               /* If terminal_loop() returns OK we got a key that is handled
+                * in Normal model.  With FAIL the terminal was closed and the
+                * screen needs to be redrawn. */
+               if (terminal_loop() == OK)
+                   normal_cmd(&oa, TRUE);
+           }
+           else
 #endif
-           normal_cmd(&oa, TRUE);
+               normal_cmd(&oa, TRUE);
        }
     }
 }
index c8e78410d9d8d4a3344680905c5f7f200c80aee4..e8f80f181bc18170e0e782f3f77debf42e6c09a5 100644 (file)
@@ -9037,6 +9037,14 @@ nv_esc(cmdarg_T *cap)
     static void
 nv_edit(cmdarg_T *cap)
 {
+#ifdef FEAT_TERMINAL
+    if (term_in_terminal_mode())
+    {
+       term_leave_terminal_mode();
+       return;
+    }
+#endif
+
     /* <Insert> is equal to "i" */
     if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS)
        cap->cmdchar = 'i';
index ad5892581dd29c008b0b8b2e331d5dd024943fcd..6e4d1a5df67e56e43f35fefd471e1cb706d9073a 100644 (file)
@@ -8222,12 +8222,22 @@ set_bool_option(
     }
 #endif
 
-#ifdef FEAT_TITLE
     /* when 'modifiable' is changed, redraw the window title */
     else if ((int *)varp == &curbuf->b_p_ma)
     {
+# ifdef FEAT_TERMINAL
+       /* Cannot set 'modifiable' when in Terminal mode. */
+       if (term_in_terminal_mode())
+       {
+           curbuf->b_p_ma = FALSE;
+           return (char_u *)N_("E946: Cannot make a terminal with running job modifiable");
+       }
+# endif
+# ifdef FEAT_TITLE
        redraw_titles();
+# endif
     }
+#ifdef FEAT_TITLE
     /* when 'endofline' is changed, redraw the window title */
     else if ((int *)varp == &curbuf->b_p_eol)
     {
index daa7706485a9d870d7e7c92809bd00f22d473c7e..6f5b3ab7074fa17275af1b283ab32f6c7d39dfe3 100644 (file)
@@ -2,11 +2,15 @@
 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 term_in_terminal_mode(void);
+void term_leave_terminal_mode(void);
+int term_use_loop(void);
 int terminal_loop(void);
 void term_job_ended(job_T *job);
 void term_channel_closed(channel_T *ch);
 int term_update_window(win_T *wp);
 int term_is_finished(buf_T *buf);
+int term_show_buffer(buf_T *buf);
 void term_change_in_curbuf(void);
 int term_get_attr(buf_T *buf, linenr_T lnum, int col);
 char_u *term_get_status_text(term_T *term);
@@ -16,8 +20,8 @@ void f_term_getjob(typval_T *argvars, typval_T *rettv);
 void f_term_getline(typval_T *argvars, typval_T *rettv);
 void f_term_getsize(typval_T *argvars, typval_T *rettv);
 void f_term_list(typval_T *argvars, typval_T *rettv);
-void f_term_start(typval_T *argvars, typval_T *rettv);
 void f_term_scrape(typval_T *argvars, typval_T *rettv);
 void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
+void f_term_start(typval_T *argvars, typval_T *rettv);
 void f_term_wait(typval_T *argvars, typval_T *rettv);
 /* vim: set ft=c : */
index a1e8b5fa05167ac9dee181ec177b2825161e8a44..baedea755b64a99f8234001a5b41c0097c551d97 100644 (file)
@@ -3245,7 +3245,7 @@ win_line(
 #endif
 
 #ifdef FEAT_TERMINAL
-    if (term_is_finished(wp->w_buffer))
+    if (term_show_buffer(wp->w_buffer))
     {
        extra_check = TRUE;
        get_term_attr = TRUE;
index 1863b598610e69780a9056859c0ecd9c694a0a76..b0ba8c1902c44cfa40317886db71076b17dd0763 100644 (file)
  * that buffer, attributes come from the scrollback buffer tl_scrollback.
  *
  * TODO:
+ * - Problem with statusline (Zyx, Christian)
+ * - Make CTRL-W "" paste register content to the job?
+ * - in bash mouse clicks are inserting characters.
+ * - mouse scroll: when over other window, scroll that window.
  * - For the scrollback buffer store lines in the buffer, only attributes in
  *   tl_scrollback.
+ * - Add term_status(): "" if not a terminal, "running" if job running,
+ *   "finished" if finished, "running,vim" when job is running and in
+ *   Terminal mode, "running,vim,pending" when job output is pending.
  * - When the job ends:
  *   - Need an option or argument to drop the window+buffer right away, to be
- *     used for a shell or Vim.
+ *     used for a shell or Vim. 'termfinish'; "close", "open" (open window when
+ *     job finishes).
+ * - add option values to the command:
+ *      :term <24x80> <close> vim notes.txt
  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
- * - do not store terminal buffer in viminfo.  Or prefix term:// ?
+ * - do not store terminal window 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?
@@ -53,6 +63,8 @@
  * - support minimal size when 'termsize' is empty?
  * - implement "term" for job_start(): more job options when starting a
  *   terminal.
+ * - if the job in the terminal does not support the mouse, we can use the
+ *   mouse in the Terminal window for copy/paste.
  * - when 'encoding' is not utf-8, or the job is using another encoding, setup
  *   conversions.
  * - In the GUI use a terminal emulator for :!cmd.
@@ -78,13 +90,17 @@ typedef struct sb_line_S {
 struct terminal_S {
     term_T     *tl_next;
 
+    VTerm      *tl_vterm;
+    job_T      *tl_job;
+    buf_T      *tl_buffer;
+
+    int                tl_terminal_mode;
+    int                tl_channel_closed;
+
 #ifdef WIN3264
     void       *tl_winpty_config;
     void       *tl_winpty;
 #endif
-    VTerm      *tl_vterm;
-    job_T      *tl_job;
-    buf_T      *tl_buffer;
 
     /* last known vterm size */
     int                tl_rows;
@@ -552,6 +568,205 @@ term_job_running(term_T *term)
        && channel_is_open(term->tl_job->jv_channel);
 }
 
+/*
+ * Add the last line of the scrollback buffer to the buffer in the window.
+ */
+    static void
+add_scrollback_line_to_buffer(term_T *term)
+{
+    linenr_T       lnum = term->tl_scrollback.ga_len - 1;
+    sb_line_T      *line = (sb_line_T *)term->tl_scrollback.ga_data + lnum;
+    garray_T       ga;
+    int                    c;
+    int                    col;
+    int                    i;
+
+    ga_init2(&ga, 1, 100);
+    for (col = 0; col < line->sb_cols; col += line->sb_cells[col].width)
+    {
+       if (ga_grow(&ga, MB_MAXBYTES) == FAIL)
+           goto failed;
+       for (i = 0; (c = line->sb_cells[col].chars[i]) > 0 || i == 0; ++i)
+           ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c,
+                                        (char_u *)ga.ga_data + ga.ga_len);
+    }
+    if (ga_grow(&ga, 1) == FAIL)
+       goto failed;
+    *((char_u *)ga.ga_data + ga.ga_len) = NUL;
+    ml_append_buf(term->tl_buffer, lnum, ga.ga_data, ga.ga_len + 1, FALSE);
+
+    if (lnum == 0)
+    {
+       /* Delete the empty line that was in the empty buffer. */
+       curbuf = term->tl_buffer;
+       ml_delete(2, FALSE);
+       curbuf = curwin->w_buffer;
+    }
+
+failed:
+    ga_clear(&ga);
+}
+
+/*
+ * Add the current lines of the terminal to scrollback and to the buffer.
+ * Called after the job has ended and when switching to Terminal mode.
+ */
+    static void
+move_terminal_to_buffer(term_T *term)
+{
+    win_T          *wp;
+    int                    len;
+    int                    lines_skipped = 0;
+    VTermPos       pos;
+    VTermScreenCell cell;
+    VTermScreenCell *p;
+    VTermScreen            *screen = vterm_obtain_screen(term->tl_vterm);
+
+    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)
+           ++lines_skipped;
+       else
+       {
+           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;
+
+                   add_scrollback_line_to_buffer(term);
+               }
+           }
+
+           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;
+
+               add_scrollback_line_to_buffer(term);
+           }
+           else
+               vim_free(p);
+       }
+    }
+
+    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;
+           redraw_win_later(wp, NOT_VALID);
+       }
+    }
+}
+
+    static void
+set_terminal_mode(term_T *term, int on)
+{
+    term->tl_terminal_mode = on;
+    vim_free(term->tl_status_text);
+    term->tl_status_text = NULL;
+    if (term->tl_buffer == curbuf)
+       maketitle();
+}
+
+/*
+ * Called after the job if finished and Terminal mode is not active:
+ * Move the vterm contents into the scrollback buffer and free the vterm.
+ */
+    static void
+cleanup_vterm(term_T *term)
+{
+    move_terminal_to_buffer(term);
+    term_free_vterm(term);
+    set_terminal_mode(term, FALSE);
+}
+
+/*
+ * Switch from sending keys to the job to Terminal-Normal mode.
+ * Suspends updating the terminal window.
+ */
+    static void
+term_enter_terminal_mode()
+{
+    term_T *term = curbuf->b_term;
+
+    /* Append the current terminal contents to the buffer. */
+    move_terminal_to_buffer(term);
+
+    set_terminal_mode(term, TRUE);
+}
+
+/*
+ * Returns TRUE if the current window contains a terminal and we are in
+ * Terminal-Normal mode.
+ */
+    int
+term_in_terminal_mode()
+{
+    term_T *term = curbuf->b_term;
+
+    return term != NULL && term->tl_terminal_mode;
+}
+
+/*
+ * Switch from Terminal-Normal mode to sending keys to the job.
+ * Restores updating the terminal window.
+ */
+    void
+term_leave_terminal_mode()
+{
+    term_T     *term = curbuf->b_term;
+    sb_line_T  *line;
+    garray_T   *gap;
+
+    /* Remove the terminal contents from the scrollback and the buffer. */
+    gap = &term->tl_scrollback;
+    while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled)
+    {
+       ml_delete(curbuf->b_ml.ml_line_count, FALSE);
+       line = (sb_line_T *)gap->ga_data + gap->ga_len - 1;
+       vim_free(line->sb_cells);
+       --gap->ga_len;
+       if (gap->ga_len == 0)
+           break;
+    }
+    check_cursor();
+
+    set_terminal_mode(term, FALSE);
+
+    if (term->tl_channel_closed)
+       cleanup_vterm(term);
+    redraw_buf_and_status_later(curbuf, NOT_VALID);
+}
+
 /*
  * Get a key from the user without mapping.
  * TODO: use terminal mode mappings.
@@ -640,6 +855,21 @@ send_keys_to_term(term_T *term, int c, int typed)
     return OK;
 }
 
+/*
+ * Returns TRUE if the current window contains a terminal and we are sending
+ * keys to the job.
+ */
+    int
+term_use_loop()
+{
+    term_T *term = curbuf->b_term;
+
+    return term != NULL
+       && !term->tl_terminal_mode
+       && term->tl_vterm != NULL
+       && term_job_running(term);
+}
+
 /*
  * Wait for input and send it to the job.
  * Return when the start of a CTRL-W command is typed or anything else that
@@ -653,10 +883,6 @@ terminal_loop(void)
     int                c;
     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);
 
@@ -665,6 +891,7 @@ terminal_loop(void)
        /* TODO: skip screen update when handling a sequence of keys. */
        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))
@@ -687,8 +914,15 @@ terminal_loop(void)
                break;
 
            if (termkey == 0 && c == '.')
+           {
                /* "CTRL-W .": send CTRL-W to the job */
                c = Ctrl_W;
+           }
+           else if (termkey == 0 && c == 'N')
+           {
+               term_enter_terminal_mode();
+               return FAIL;
+           }
            else if (termkey == 0 || c != termkey)
            {
                stuffcharReadbuff(Ctrl_W);
@@ -704,6 +938,8 @@ terminal_loop(void)
 
 /*
  * Called when a job has finished.
+ * This updates the title and status, but does not close the vter, because
+ * there might still be pending output in the channel.
  */
     void
 term_job_ended(job_T *job)
@@ -891,118 +1127,10 @@ handle_pushline(int cols, const VTermScreenCell *cells, void *user)
        line->sb_cells = p;
        ++term->tl_scrollback.ga_len;
        ++term->tl_scrollback_scrolled;
-    }
-    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)
-           ++lines_skipped;
-       else
-       {
-           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)
-       {
-           if (ga_grow(&ga, MB_MAXBYTES) == FAIL)
-               goto failed;
-           for (i = 0; (c = line->sb_cells[col].chars[i]) > 0 || i == 0; ++i)
-               ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c,
-                                            (char_u *)ga.ga_data + ga.ga_len);
-       }
-       if (ga_grow(&ga, 1) == FAIL)
-           goto failed;
-       *((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;
-       }
+       add_scrollback_line_to_buffer(term);
     }
+    return 0; /* ignored */
 }
 
 static VTermScreenCallbacks screen_callbacks = {
@@ -1029,14 +1157,16 @@ term_channel_closed(channel_T *ch)
     for (term = first_term; term != NULL; term = term->tl_next)
        if (term->tl_job == ch->ch_job)
        {
+           term->tl_channel_closed = TRUE;
+
            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);
+           /* Unless in Terminal-Normal mode: clear the vterm. */
+           if (!term->tl_terminal_mode)
+               cleanup_vterm(term);
 
            redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
            did_one = TRUE;
@@ -1227,8 +1357,9 @@ term_update_window(win_T *wp)
     VTermState *state;
     VTermPos   pos;
 
-    if (term == NULL || term->tl_vterm == NULL)
+    if (term == NULL || term->tl_vterm == NULL || term->tl_terminal_mode)
        return FAIL;
+
     vterm = term->tl_vterm;
     screen = vterm_obtain_screen(vterm);
     state = vterm_obtain_state(vterm);
@@ -1346,6 +1477,18 @@ term_is_finished(buf_T *buf)
     return buf->b_term != NULL && buf->b_term->tl_vterm == NULL;
 }
 
+/*
+ * Return TRUE if "wp" is a terminal window where the job has finished or we
+ * are in Terminal-Normal mode.
+ */
+    int
+term_show_buffer(buf_T *buf)
+{
+    term_T *term = buf->b_term;
+
+    return term != NULL && (term->tl_vterm == NULL || term->tl_terminal_mode);
+}
+
 /*
  * The current buffer is going to be changed.  If there is terminal
  * highlighting remove it now.
@@ -1450,7 +1593,14 @@ term_get_status_text(term_T *term)
        char_u *txt;
        size_t len;
 
-       if (term->tl_title != NULL)
+       if (term->tl_terminal_mode)
+       {
+           if (term_job_running(term))
+               txt = (char_u *)_("Terminal");
+           else
+               txt = (char_u *)_("Terminal-finished");
+       }
+       else if (term->tl_title != NULL)
            txt = term->tl_title;
        else if (term_job_running(term))
            txt = (char_u *)_("running");
index 7a3e04a174bf9fa4655e9155069fed6c14bf4198..9cc8e1448600affcd8219d03bff6ab23ffa765f0 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    813,
 /**/
     812,
 /**/