0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

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.
This commit is contained in:
Bram Moolenaar
2017-08-12 14:32:32 +02:00
parent b81bc77ae7
commit 8cad930a25
7 changed files with 103 additions and 18 deletions

View File

@@ -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 VIM REFERENCE MANUAL by Bram Moolenaar
@@ -103,8 +103,17 @@ Syntax ~
++close The terminal window will close ++close The terminal window will close
automatically when the job terminates. automatically when the job terminates.
++open When the job terminates and no window ++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. 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, When the buffer associated with the terminal is wiped out the job is killed,
similar to calling `job_stop(job, "kill")` similar to calling `job_stop(job, "kill")`
@@ -114,6 +123,13 @@ So long as the job is running: If the window is closed the buffer becomes
hidden. The command will not be stopped. The `:buffer` command can be used 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 to turn the current window into a terminal window. If there are unsaved
changes this fails, use ! to force, as usual. 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* *E947*
So long as the job is running, the buffer is considered modified and Vim So long as the job is running, the buffer is considered modified and Vim
cannot be quit easily, see |abandon|. cannot be quit easily, see |abandon|.

View File

@@ -4462,6 +4462,13 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_set |= JO2_CURWIN; opt->jo_set |= JO2_CURWIN;
opt->jo_curwin = get_tv_number(item); 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 #endif
else if (STRCMP(hi->hi_key, "env") == 0) else if (STRCMP(hi->hi_key, "env") == 0)
{ {

View File

@@ -6889,6 +6889,9 @@ buf_check_timestamp(
#endif #endif
#ifdef FEAT_NETBEANS_INTG #ifdef FEAT_NETBEANS_INTG
|| isNetbeansBuffer(buf) || isNetbeansBuffer(buf)
#endif
#ifdef FEAT_TERMINAL
|| buf->b_term != NULL
#endif #endif
) )
return 0; return 0;

View File

@@ -1692,7 +1692,8 @@ struct channel_S {
#define JO2_TERM_COLS 0x0080 /* "term_cols" */ #define JO2_TERM_COLS 0x0080 /* "term_cols" */
#define JO2_VERTICAL 0x0100 /* "vertical" */ #define JO2_VERTICAL 0x0100 /* "vertical" */
#define JO2_CURWIN 0x0200 /* "curwin" */ #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_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
#define JO_CB_ALL \ #define JO_CB_ALL \
@@ -1754,6 +1755,7 @@ typedef struct
int jo_term_cols; int jo_term_cols;
int jo_vertical; int jo_vertical;
int jo_curwin; int jo_curwin;
int jo_hidden;
char_u *jo_term_name; char_u *jo_term_name;
int jo_term_finish; int jo_term_finish;
#endif #endif

View File

@@ -36,8 +36,6 @@
* that buffer, attributes come from the scrollback buffer tl_scrollback. * that buffer, attributes come from the scrollback buffer tl_scrollback.
* *
* TODO: * 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 * - When using term_finish "open" have a way to specify how the window is to
* be opened. E.g. term_opencmd "10split buffer %d". * be opened. E.g. term_opencmd "10split buffer %d".
* - support different cursor shapes, colors and attributes * - support different cursor shapes, colors and attributes
@@ -249,6 +247,7 @@ term_start(char_u *cmd, jobopt_T *opt, int forceit)
exarg_T split_ea; exarg_T split_ea;
win_T *old_curwin = curwin; win_T *old_curwin = curwin;
term_T *term; term_T *term;
buf_T *old_curbuf = NULL;
if (check_restricted() || check_secure()) if (check_restricted() || check_secure())
return; return;
@@ -268,12 +267,35 @@ term_start(char_u *cmd, jobopt_T *opt, int forceit)
if (!can_abandon(curbuf, forceit)) if (!can_abandon(curbuf, forceit))
{ {
EMSG(_(e_nowrtmsg)); EMSG(_(e_nowrtmsg));
vim_free(term);
return; return;
} }
if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE, if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE,
ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
{
vim_free(term);
return; 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 else
{ {
/* Open a new window or tab. */ /* Open a new window or tab. */
@@ -302,11 +324,14 @@ term_start(char_u *cmd, jobopt_T *opt, int forceit)
term->tl_buffer = curbuf; term->tl_buffer = curbuf;
curbuf->b_term = term; curbuf->b_term = term;
if (!opt->jo_hidden)
{
/* only one size was taken care of with :new, do the other one */ /* only one size was taken care of with :new, do the other one */
if (opt->jo_term_rows > 0 && (cmdmod.split & WSP_VERT)) if (opt->jo_term_rows > 0 && (cmdmod.split & WSP_VERT))
win_setheight(opt->jo_term_rows); win_setheight(opt->jo_term_rows);
if (opt->jo_term_cols > 0 && !(cmdmod.split & WSP_VERT)) if (opt->jo_term_cols > 0 && !(cmdmod.split & WSP_VERT))
win_setwidth(opt->jo_term_cols); win_setwidth(opt->jo_term_cols);
}
/* Link the new terminal in the list of active terminals. */ /* Link the new terminal in the list of active terminals. */
term->tl_next = first_term; term->tl_next = first_term;
@@ -360,14 +385,31 @@ term_start(char_u *cmd, jobopt_T *opt, int forceit)
/* Get and remember the size we ended up with. Update the pty. */ /* Get and remember the size we ended up with. Update the pty. */
vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols); vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
term_report_winsize(term, 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 else
{ {
buf_T *buf = curbuf;
free_terminal(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 /* Wiping out the buffer will also close the window and call
* free_terminal(). */ * 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'; opt.jo_term_finish = 'o';
else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "curwin", 6) == 0) else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "curwin", 6) == 0)
opt.jo_curwin = 1; opt.jo_curwin = 1;
else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0)
opt.jo_hidden = 1;
else else
{ {
if (*p) if (*p)
@@ -886,7 +930,7 @@ set_terminal_mode(term_T *term, int normal_mode)
static void static void
cleanup_vterm(term_T *term) cleanup_vterm(term_T *term)
{ {
if (term->tl_finish == 0) if (term->tl_finish != 'c')
move_terminal_to_buffer(term); move_terminal_to_buffer(term);
term_free_vterm(term); term_free_vterm(term);
set_terminal_mode(term, FALSE); set_terminal_mode(term, FALSE);
@@ -1222,7 +1266,7 @@ terminal_loop(void)
/* /*
* Called when a job has finished. * 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. * there might still be pending output in the channel.
*/ */
void void
@@ -1478,6 +1522,7 @@ term_channel_closed(channel_T *ch)
if (term->tl_finish == 'c') if (term->tl_finish == 'c')
{ {
/* ++close or term_finish == "close" */ /* ++close or term_finish == "close" */
ch_log(NULL, "terminal job finished, closing window");
curbuf = term->tl_buffer; curbuf = term->tl_buffer;
do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE); do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
break; break;
@@ -1487,9 +1532,12 @@ term_channel_closed(channel_T *ch)
char buf[50]; char buf[50];
/* TODO: use term_opencmd */ /* TODO: use term_opencmd */
ch_log(NULL, "terminal job finished, opening window");
vim_snprintf(buf, sizeof(buf), "botright sbuf %d", fnum); vim_snprintf(buf, sizeof(buf), "botright sbuf %d", fnum);
do_cmdline_cmd((char_u *)buf); do_cmdline_cmd((char_u *)buf);
} }
else
ch_log(NULL, "terminal job finished");
} }
redraw_buf_and_status_later(term->tl_buffer, NOT_VALID); redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
@@ -2380,7 +2428,7 @@ f_term_start(typval_T *argvars, typval_T *rettv)
&& get_job_options(&argvars[1], &opt, && get_job_options(&argvars[1], &opt,
JO_TIMEOUT_ALL + JO_STOPONEXIT JO_TIMEOUT_ALL + JO_STOPONEXIT
+ JO_EXIT_CB + JO_CLOSE_CALLBACK, + 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_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ JO2_CWD + JO2_ENV) == FAIL) + JO2_CWD + JO2_ENV) == FAIL)
return; return;

View File

@@ -337,7 +337,6 @@ func Test_finish_close()
endif endif
exe 'terminal ++close ' . cmd exe 'terminal ++close ' . cmd
let buf = bufnr('')
call assert_equal(2, winnr('$')) call assert_equal(2, winnr('$'))
wincmd p wincmd p
call WaitFor("winnr('$') == 1", waittime) call WaitFor("winnr('$') == 1", waittime)
@@ -345,24 +344,32 @@ func Test_finish_close()
call term_start(cmd, {'term_finish': 'close'}) call term_start(cmd, {'term_finish': 'close'})
call assert_equal(2, winnr('$')) call assert_equal(2, winnr('$'))
let buf = bufnr('')
wincmd p wincmd p
call WaitFor("winnr('$') == 1", waittime) call WaitFor("winnr('$') == 1", waittime)
call assert_equal(1, winnr('$')) call assert_equal(1, winnr('$'))
exe 'terminal ++open ' . cmd exe 'terminal ++open ' . cmd
let buf = bufnr('')
close close
call WaitFor("winnr('$') == 2", waittime) call WaitFor("winnr('$') == 2", waittime)
call assert_equal(2, winnr('$')) call assert_equal(2, winnr('$'))
bwipe bwipe
call term_start(cmd, {'term_finish': 'open'}) call term_start(cmd, {'term_finish': 'open'})
let buf = bufnr('')
close close
call WaitFor("winnr('$') == 2", waittime) call WaitFor("winnr('$') == 2", waittime)
call assert_equal(2, winnr('$')) 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 bwipe
endfunc endfunc

View File

@@ -769,6 +769,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
912,
/**/ /**/
911, 911,
/**/ /**/