# HG changeset patch # User Christian Brabandt # Date 1502541904 -7200 # Node ID 407a475c67fda21dfaf4f789f07bd08a27890ddd # Parent 2372e456e82101e471bfa8acb82dce5817d8159a patch 8.0.0912: cannot run a job in a hidden terminal commit https://github.com/vim/vim/commit/8cad930a259a05a95c7d0c527a5881d5f9a59057 Author: Bram Moolenaar Date: Sat Aug 12 14:32:32 2017 +0200 patch 8.0.0912: cannot run a job in a hidden terminal Problem: Cannot run a job in a hidden terminal. Solution: Add option "hidden" and ++hidden. diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -1,4 +1,4 @@ -*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 10 +*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -103,8 +103,17 @@ Syntax ~ ++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. + shows it, a window will be opened. Note that this can be interruptive. + ++curwin Open the terminal in the current + window, do not split the current + window. Fails if the current buffer + cannot be |abandon|ed. + ++hidden Open the terminal in a hidden buffer, + no window will be used. + + If you want to use more options use the |term_start()| + function. When the buffer associated with the terminal is wiped out the job is killed, similar to calling `job_stop(job, "kill")` @@ -114,6 +123,13 @@ So long as the job is running: If the wi hidden. The command will not be stopped. The `:buffer` command can be used to turn the current window into a terminal window. If there are unsaved changes this fails, use ! to force, as usual. + +To have a background job run without a window, and open the window when it's +done, use options like this: > + :term ++hidden ++open make +Note that the window will open at an unexpected moment, this will interrupt +what you are doing. + *E947* So long as the job is running, the buffer is considered modified and Vim cannot be quit easily, see |abandon|. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -4462,6 +4462,13 @@ get_job_options(typval_T *tv, jobopt_T * opt->jo_set |= JO2_CURWIN; opt->jo_curwin = get_tv_number(item); } + else if (STRCMP(hi->hi_key, "hidden") == 0) + { + if (!(supported2 & JO2_HIDDEN)) + break; + opt->jo_set |= JO2_HIDDEN; + opt->jo_hidden = get_tv_number(item); + } #endif else if (STRCMP(hi->hi_key, "env") == 0) { diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -6890,6 +6890,9 @@ buf_check_timestamp( #ifdef FEAT_NETBEANS_INTG || isNetbeansBuffer(buf) #endif +#ifdef FEAT_TERMINAL + || buf->b_term != NULL +#endif ) return 0; diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1692,7 +1692,8 @@ struct channel_S { #define JO2_TERM_COLS 0x0080 /* "term_cols" */ #define JO2_VERTICAL 0x0100 /* "vertical" */ #define JO2_CURWIN 0x0200 /* "curwin" */ -#define JO2_ALL 0x03FF +#define JO2_HIDDEN 0x0400 /* "hidden" */ +#define JO2_ALL 0x07FF #define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE) #define JO_CB_ALL \ @@ -1754,6 +1755,7 @@ typedef struct int jo_term_cols; int jo_vertical; int jo_curwin; + int jo_hidden; char_u *jo_term_name; int jo_term_finish; #endif diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -36,8 +36,6 @@ * that buffer, attributes come from the scrollback buffer tl_scrollback. * * TODO: - * - add option values to the command: - * :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 @@ -249,6 +247,7 @@ term_start(char_u *cmd, jobopt_T *opt, i exarg_T split_ea; win_T *old_curwin = curwin; term_T *term; + buf_T *old_curbuf = NULL; if (check_restricted() || check_secure()) return; @@ -268,11 +267,34 @@ term_start(char_u *cmd, jobopt_T *opt, i if (!can_abandon(curbuf, forceit)) { EMSG(_(e_nowrtmsg)); + vim_free(term); return; } if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE, ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) + { + vim_free(term); return; + } + } + else if (opt->jo_hidden) + { + buf_T *buf; + + /* Create a new buffer without a window. Make it the current buffer for + * a moment to be able to do the initialisations. */ + buf = buflist_new((char_u *)"", NULL, (linenr_T)0, + BLN_NEW | BLN_LISTED); + if (buf == NULL || ml_open(buf) == FAIL) + { + vim_free(term); + return; + } + old_curbuf = curbuf; + --curbuf->b_nwindows; + curbuf = buf; + curwin->w_buffer = buf; + ++curbuf->b_nwindows; } else { @@ -302,11 +324,14 @@ term_start(char_u *cmd, jobopt_T *opt, i term->tl_buffer = curbuf; curbuf->b_term = term; - /* only one size was taken care of with :new, do the other one */ - if (opt->jo_term_rows > 0 && (cmdmod.split & WSP_VERT)) - win_setheight(opt->jo_term_rows); - if (opt->jo_term_cols > 0 && !(cmdmod.split & WSP_VERT)) - win_setwidth(opt->jo_term_cols); + if (!opt->jo_hidden) + { + /* only one size was taken care of with :new, do the other one */ + if (opt->jo_term_rows > 0 && (cmdmod.split & WSP_VERT)) + win_setheight(opt->jo_term_rows); + if (opt->jo_term_cols > 0 && !(cmdmod.split & WSP_VERT)) + win_setwidth(opt->jo_term_cols); + } /* Link the new terminal in the list of active terminals. */ term->tl_next = first_term; @@ -360,14 +385,31 @@ term_start(char_u *cmd, jobopt_T *opt, i /* Get and remember the size we ended up with. Update the pty. */ vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols); term_report_winsize(term, term->tl_rows, term->tl_cols); + + if (old_curbuf != NULL) + { + --curbuf->b_nwindows; + curbuf = old_curbuf; + curwin->w_buffer = curbuf; + ++curbuf->b_nwindows; + } } else { + buf_T *buf = curbuf; + free_terminal(curbuf); + if (old_curbuf != NULL) + { + --curbuf->b_nwindows; + curbuf = old_curbuf; + curwin->w_buffer = curbuf; + ++curbuf->b_nwindows; + } /* Wiping out the buffer will also close the window and call * free_terminal(). */ - do_buffer(DOBUF_WIPE, DOBUF_CURRENT, FORWARD, 0, TRUE); + do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE); } } @@ -395,6 +437,8 @@ ex_terminal(exarg_T *eap) opt.jo_term_finish = 'o'; else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "curwin", 6) == 0) opt.jo_curwin = 1; + else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0) + opt.jo_hidden = 1; else { if (*p) @@ -886,7 +930,7 @@ set_terminal_mode(term_T *term, int norm static void cleanup_vterm(term_T *term) { - if (term->tl_finish == 0) + if (term->tl_finish != 'c') move_terminal_to_buffer(term); term_free_vterm(term); set_terminal_mode(term, FALSE); @@ -1222,7 +1266,7 @@ terminal_loop(void) /* * Called when a job has finished. - * This updates the title and status, but does not close the vter, because + * This updates the title and status, but does not close the vterm, because * there might still be pending output in the channel. */ void @@ -1478,6 +1522,7 @@ term_channel_closed(channel_T *ch) if (term->tl_finish == 'c') { /* ++close or term_finish == "close" */ + ch_log(NULL, "terminal job finished, closing window"); curbuf = term->tl_buffer; do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE); break; @@ -1487,9 +1532,12 @@ term_channel_closed(channel_T *ch) char buf[50]; /* TODO: use term_opencmd */ + ch_log(NULL, "terminal job finished, opening window"); vim_snprintf(buf, sizeof(buf), "botright sbuf %d", fnum); do_cmdline_cmd((char_u *)buf); } + else + ch_log(NULL, "terminal job finished"); } redraw_buf_and_status_later(term->tl_buffer, NOT_VALID); @@ -2380,7 +2428,7 @@ f_term_start(typval_T *argvars, typval_T && get_job_options(&argvars[1], &opt, JO_TIMEOUT_ALL + JO_STOPONEXIT + JO_EXIT_CB + JO_CLOSE_CALLBACK, - JO2_TERM_NAME + JO2_TERM_FINISH + JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN + JO2_CWD + JO2_ENV) == FAIL) return; diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -337,7 +337,6 @@ func Test_finish_close() endif exe 'terminal ++close ' . cmd - let buf = bufnr('') call assert_equal(2, winnr('$')) wincmd p call WaitFor("winnr('$') == 1", waittime) @@ -345,24 +344,32 @@ func Test_finish_close() call term_start(cmd, {'term_finish': 'close'}) call assert_equal(2, winnr('$')) - let buf = bufnr('') wincmd p call WaitFor("winnr('$') == 1", waittime) call assert_equal(1, winnr('$')) exe 'terminal ++open ' . cmd - let buf = bufnr('') close call WaitFor("winnr('$') == 2", waittime) call assert_equal(2, winnr('$')) bwipe call term_start(cmd, {'term_finish': 'open'}) - let buf = bufnr('') close call WaitFor("winnr('$') == 2", waittime) call assert_equal(2, winnr('$')) + bwipe + exe 'terminal ++hidden ++open ' . cmd + call assert_equal(1, winnr('$')) + call WaitFor("winnr('$') == 2", waittime) + call assert_equal(2, winnr('$')) + bwipe + + call term_start(cmd, {'term_finish': 'open', 'hidden': 1}) + call assert_equal(1, winnr('$')) + call WaitFor("winnr('$') == 2", waittime) + call assert_equal(2, winnr('$')) bwipe endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -770,6 +770,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 912, +/**/ 911, /**/ 910,