]> granicus.if.org Git - vim/commitdiff
patch 8.0.0896: cannot close a terminal window when the job ends v8.0.0896
authorBram Moolenaar <Bram@vim.org>
Thu, 10 Aug 2017 21:15:19 +0000 (23:15 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 10 Aug 2017 21:15:19 +0000 (23:15 +0200)
Problem:    Cannot automaticlaly close a terminal window when the job ends.
Solution:   Add the ++close argument to :term.  Add the term_finish option to
            term_start(). (Yasuhiro  Matsumoto, closes #1950)  Also add
            ++open.

runtime/doc/eval.txt
runtime/doc/terminal.txt
src/channel.c
src/structs.h
src/terminal.c
src/testdir/test_terminal.vim
src/version.c

index 5c10562c5a82d5e21cafe90d406585dadf435207..a98958b15ce2fd84148643889b0a0d14d806357c 100644 (file)
@@ -8054,9 +8054,14 @@ term_start({cmd}, {options})                             *term_start()*
                connected to the terminal.  When I/O is connected to the
                terminal then the callback function for that part is not used.
 
-               There is one extra option:
-                  "term_name"   name to use for the buffer name, instead of
-                                the command name.
+               There are two extra options:
+                  "term_name"       name to use for the buffer name, instead
+                                    of the command name.
+                  "term_finish"     What todo when the job is finished:
+                                       "close": close any windows
+                                       "open": open window if needed
+                                    Note that "open" can be interruptive.
+                                    See |term++close| and |term++open|.
                {only available when compiled with the |+terminal| feature}
 
 term_wait({buf} [, {time}])                                    *term_wait()*
index 6a1285f1b81197933f46707f7ba6f2818dac014f..14dab9d272a9786fb75d2ef12c4c00804d7cdd95 100644 (file)
@@ -1,4 +1,4 @@
-*terminal.txt* For Vim version 8.0.  Last change: 2017 Aug 05
+*terminal.txt* For Vim version 8.0.  Last change: 2017 Aug 10
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -36,7 +36,7 @@ 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
+When the keyboard focus is in the terminal window, typed keys will be sent to
 the job.  This uses a pty when possible.  You can click outside of the
 terminal window to move keyboard focus elsewhere.
 
@@ -47,7 +47,8 @@ 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|
+       CTRL-W N        go to Terminal-Normal mode, see |Terminal-mode|
+       CTRL-\ CTRL-N   go to Terminal-Normal mode, see |Terminal-mode|
        CTRL-W " {reg}  paste register {reg}            *CTRL-W_quote*
                        Also works with the = register to insert the result of
                        evaluating an expression.
@@ -62,10 +63,8 @@ the job.  For example:
        'termkey' N         go to terminal Normal mode, see below
        'termkey' CTRL-N    same as CTRL-W N
                                                        *t_CTRL-\_CTRL-N*
-The special key combination CTRL-\ CTRL-N can be used to prefix one Normal
-mode command.  This is especially useful for remote commands, when you don't
-know whether Vim currently has focus in a terminal window.  Note that only one
-Normal mode command can be used.
+The special key combination CTRL-\ CTRL-N can be used to switch to Normal
+mode, just like this works in any other mode.
 
 
 Size ~
@@ -76,7 +75,7 @@ See option 'termsize' for controlling the size of the terminal window.
 
 Syntax ~
 
-:ter[minal] [command]                          *:ter* *:terminal*
+:[range]ter[minal] [options] [command]                 *:ter* *:terminal*
                        Open a new terminal window.
 
                        If [command] is provided run it as a job and connect
@@ -86,9 +85,27 @@ Syntax ~
                        A new buffer will be created, using [command] or
                        'shell' as the name, prefixed with a "!".  If a buffer
                        by this name already exists a number is added in
-                       parenthesis.  E.g. if "gdb" exists the second terminal
+                       parentheses.  E.g. if "gdb" exists the second terminal
                        buffer will use "!gdb (1)".
 
+                       If [range] is given it is used for the terminal size.
+                       One number specifies the number of rows.  Unless the
+                       "vertical" modifier is used, then it is the number of
+                       columns.
+
+                       Two comma separated numbers are used as "rows,cols".
+                       E.g. `:24,80gdb` opens a terminal with 24 rows and 80
+                       columns.  However, if the terminal window spans the
+                       Vim window with, there is no vertical split, the Vim
+                       window width is used.
+                                               *term++close* *term++open*
+                       Supported [options] are:
+                       ++close         The terminal window will close
+                                       automatically when the job terminates.
+                       ++open          When the job terminates and no window
+                                       show it, a window will be opened.
+                                       Note that this can be interruptive.
+
 When the buffer associated with the terminal is wiped out the job is killed,
 similar to calling `job_stop(job, "kill")`
 
@@ -133,23 +150,26 @@ terminal.  |term_setsize()| can be used only when in the first or second mode,
 not when 'termsize' is "rowsXcols".
 
 
-Terminal Normal mode ~
+Terminal-Job and 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.
+job.  That includes the cursor position.  Typed keys are sent to the job.
+The terminal contents can change at any time.  This is called Terminal-Job
+mode.
 
-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.
+Use CTRL-W N (or 'termkey' N) to switch to Terminal-Normal mode.  Now the
+contents of the terminal window is under control of Vim, the job output is
+suspended.  CTRL-\ CTRL-N does the same.
                                                        *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)".
+In Terminal-Normal 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 to Terminal-Job mode.  The window will be updated to show
+the contents of the terminal.
+
+In Terminal-Normal mode the statusline and window title show "(Terminal)".  If
+the job ends while in Terminal-Normal mode this changes to
+"(Terminal-finished)".
 
 
 Unix ~
index a4f1cc7b70e8b6a51fe369ce680104c2071f8a00..4e1458c5bc01f253f010ef9a554be667a688bcf8 100644 (file)
@@ -4419,6 +4419,19 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
                    return FAIL;
                }
            }
+           else if (STRCMP(hi->hi_key, "term_finish") == 0)
+           {
+               if (!(supported & JO2_TERM_FINISH))
+                   break;
+               val = get_tv_string(item);
+               if (STRCMP(val, "open") != 0 && STRCMP(val, "close") != 0)
+               {
+                   EMSG2(_(e_invarg2), "drop");
+                   return FAIL;
+               }
+               opt->jo_set2 |= JO2_TERM_FINISH;
+               opt->jo_term_finish = *val;
+           }
 #endif
            else if (STRCMP(hi->hi_key, "waittime") == 0)
            {
index 83c55a932455bb67c5d56fa1f56f398d1836f292..618cabfe755916ae209811f28ebaf61d9234dc8c 100644 (file)
@@ -1685,7 +1685,8 @@ struct channel_S {
 #define JO2_OUT_MSG        0x0001      /* "out_msg" */
 #define JO2_ERR_MSG        0x0002      /* "err_msg" (JO_OUT_ << 1) */
 #define JO2_TERM_NAME      0x0004      /* "term_name" */
-#define JO2_ALL                    0x0007
+#define JO2_TERM_FINISH            0x0008      /* "term_finish" */
+#define JO2_ALL                    0x000F
 
 #define JO_MODE_ALL    (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
 #define JO_CB_ALL \
@@ -1743,6 +1744,7 @@ typedef struct
     int                jo_term_rows;
     int                jo_term_cols;
     char_u     *jo_term_name;
+    int                jo_term_finish;
 #endif
 } jobopt_T;
 
index 36d5cf15d14a35633cf7b65d5fd719ba80556b8b..b1cb61fc09bf7b79b6c29b49fb8c81aa74146ae2 100644 (file)
  * that buffer, attributes come from the scrollback buffer tl_scrollback.
  *
  * TODO:
- * - When the job ends:
- *   - Need an option or argument to drop the window+buffer right away, to be
- *     used for a shell or Vim. 'termfinish'; "close", "open" (open window when
- *     job finishes).
- *     patch by Yasuhiro: #1950
  * - add option values to the command:
- *      :term <24x80> <close> vim notes.txt
- *   or use:
  *      :term ++24x80 ++close vim notes.txt
+ * - When using term_finish "open" have a way to specify how the window is to
+ *   be opened.  E.g. term_opencmd "10split buffer %d".
  * - support different cursor shapes, colors and attributes
  * - make term_getcursor() return type (none/block/bar/underline) and
  *   attributes (color, blink, etc.)
+ * - Make argument list work on MS-Windows. #1954
  * - MS-Windows: no redraw for 'updatetime'  #1915
  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
  *   For the GUI fill termios with default values, perhaps like pangoterm:
@@ -124,6 +120,7 @@ struct terminal_S {
 
     int                tl_normal_mode; /* TRUE: Terminal-Normal mode */
     int                tl_channel_closed;
+    int                tl_finish;      /* 'c' for ++close, 'o' for ++open */
 
 #ifdef WIN3264
     void       *tl_winpty_config;
@@ -257,6 +254,7 @@ term_start(char_u *cmd, jobopt_T *opt)
        return;
     term->tl_dirty_row_end = MAX_ROW;
     term->tl_cursor_visible = TRUE;
+    term->tl_finish = opt->jo_term_finish;
     ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
 
     /* Open a new window or tab. */
@@ -360,10 +358,32 @@ term_start(char_u *cmd, jobopt_T *opt)
     void
 ex_terminal(exarg_T *eap)
 {
-    jobopt_T opt;
+    jobopt_T   opt;
+    char_u     *cmd;
 
     init_job_options(&opt);
 
+    cmd = eap->arg;
+    while (*cmd && *cmd == '+' && *(cmd + 1) == '+')
+    {
+       char_u  *p;
+
+       cmd += 2;
+       p = skiptowhite(cmd);
+       if ((int)(p - cmd) == 5 && STRNICMP(cmd, "close", 5) == 0)
+           opt.jo_term_finish = 'c';
+       else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "open", 4) == 0)
+           opt.jo_term_finish = 'o';
+       else
+       {
+           if (*p)
+               *p = NUL;
+           EMSG2(_("E181: Invalid attribute: %s"), cmd);
+           return;
+       }
+       cmd = skipwhite(p);
+    }
+
     if (eap->addr_count == 2)
     {
        opt.jo_term_rows = eap->line1;
@@ -378,7 +398,7 @@ ex_terminal(exarg_T *eap)
     }
     /* TODO: get more options from before the command */
 
-    term_start(eap->arg, &opt);
+    term_start(cmd, &opt);
 }
 
 /*
@@ -846,7 +866,8 @@ set_terminal_mode(term_T *term, int normal_mode)
     static void
 cleanup_vterm(term_T *term)
 {
-    move_terminal_to_buffer(term);
+    if (term->tl_finish == 0)
+       move_terminal_to_buffer(term);
     term_free_vterm(term);
     set_terminal_mode(term, FALSE);
 }
@@ -1415,6 +1436,7 @@ term_channel_closed(channel_T *ch)
        if (term->tl_job == ch->ch_job)
        {
            term->tl_channel_closed = TRUE;
+           did_one = TRUE;
 
            vim_free(term->tl_title);
            term->tl_title = NULL;
@@ -1423,10 +1445,29 @@ term_channel_closed(channel_T *ch)
 
            /* Unless in Terminal-Normal mode: clear the vterm. */
            if (!term->tl_normal_mode)
+           {
+               int     fnum = term->tl_buffer->b_fnum;
+
                cleanup_vterm(term);
 
+               if (term->tl_finish == 'c')
+               {
+                   /* ++close or term_finish == "close" */
+                   curbuf = term->tl_buffer;
+                   do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
+                   break;
+               }
+               if (term->tl_finish == 'o' && term->tl_buffer->b_nwindows == 0)
+               {
+                   char buf[50];
+
+                   /* TODO: use term_opencmd */
+                   vim_snprintf(buf, sizeof(buf), "botright sbuf %d", fnum);
+                   do_cmdline_cmd((char_u *)buf);
+               }
+           }
+
            redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
-           did_one = TRUE;
        }
     if (did_one)
     {
@@ -2298,7 +2339,7 @@ f_term_start(typval_T *argvars, typval_T *rettv)
            && get_job_options(&argvars[1], &opt,
                JO_TIMEOUT_ALL + JO_STOPONEXIT
                + JO_EXIT_CB + JO_CLOSE_CALLBACK
-               + JO2_TERM_NAME) == FAIL)
+               + JO2_TERM_NAME + JO2_TERM_FINISH) == FAIL)
        return;
 
     term_start(cmd, &opt);
index cd884e132bbd3e33a5504825ced4ae05e29f67be..89a784b340c49213e7817986965f9f6e59949c5e 100644 (file)
@@ -264,3 +264,43 @@ func Test_terminal_size()
   bwipe!
   call assert_equal([6, 20], size)
 endfunc
+
+func Test_finish_close()
+  call assert_equal(1, winnr('$'))
+
+  " TODO: use something that takes much less than a whole second
+  if has('win32')
+    let cmd = $windir . '\system32\timeout.exe 1'
+  else
+    let cmd = 'sleep 1'
+  endif
+  exe 'terminal ++close ' . cmd
+  let buf = bufnr('')
+  call assert_equal(2, winnr('$'))
+
+  wincmd p
+  sleep 1200 msec
+  call assert_equal(1, winnr('$'))
+
+  call term_start(cmd, {'term_finish': 'close'})
+  call assert_equal(2, winnr('$'))
+  let buf = bufnr('')
+  wincmd p
+  sleep 1200 msec
+  call assert_equal(1, winnr('$'))
+
+  exe 'terminal ++open ' . cmd
+  let buf = bufnr('')
+  close
+  sleep 1200 msec
+  call assert_equal(2, winnr('$'))
+  bwipe
+
+  call term_start(cmd, {'term_finish': 'open'})
+  let buf = bufnr('')
+  close
+  sleep 1200 msec
+  call assert_equal(2, winnr('$'))
+
+  bwipe
+endfunc
index cb64bde4e575dbe95ad328c3de8e43f4679dbaab..5459482d630ceb9d7b3f0a7f3b80fb2fc038e2f8 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    896,
 /**/
     895,
 /**/