Skip to content

Commit 74dc0c8

Browse files
committed
Merge remote-tracking branch 'vim/master'
2 parents d3c7694 + 1dd9833 commit 74dc0c8

12 files changed

Lines changed: 478 additions & 170 deletions

File tree

runtime/doc/options.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3966,7 +3966,14 @@ A jump table for the options with a short description can be found at |Q_op|.
39663966
To avoid problems with flags that are added in the future, use the
39673967
"+=" and "-=" feature of ":set" |add-option-flags|.
39683968

3969-
Valid letters are as follows:
3969+
Valid characters are as follows:
3970+
*'go-!'*
3971+
'!' External commands are executed in a terminal window. Without
3972+
this flag the MS-Windows GUI will open a console window to
3973+
execute the command. The Unix GUI will simulate a dumb
3974+
terminal to list the command output.
3975+
The terminal window will be positioned at the bottom, and grow
3976+
upwards as needed.
39703977
*guioptions_a* *'go-a'*
39713978
'a' Autoselect: If present, then whenever VISUAL mode is started,
39723979
or the Visual area extended, Vim tries to become the owner of

runtime/doc/terminal.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ Syntax ~
140140
if [command] is NONE no job is started, the pty of the
141141
terminal can be used by a command like gdb.
142142

143+
If [command] is missing the default behavior is to
144+
close the terminal when the shell exits. This can be
145+
changed with the ++noclose argument.
146+
If [command] is present the default behavior is to
147+
keep the terminal open in Terminal-Normal mode. This
148+
can be changed with the ++close argument.
149+
143150
A new buffer will be created, using [command] or
144151
'shell' as the name, prefixed with a "!". If a buffer
145152
by this name already exists a number is added in
@@ -155,9 +162,14 @@ Syntax ~
155162
Supported [options] are:
156163
++close The terminal window will close
157164
automatically when the job terminates.
165+
++noclose The terminal window will NOT close
166+
automatically when the job terminates.
158167
++open When the job terminates and no window
159168
shows it, a window will be opened.
160169
Note that this can be interruptive.
170+
The last of ++close, ++noclose and ++open
171+
matters and rules out earlier arguments.
172+
161173
++curwin Open the terminal in the current
162174
window, do not split the current
163175
window. Fails if the current buffer

src/channel.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5418,11 +5418,13 @@ job_check_ended(void)
54185418

54195419
/*
54205420
* Create a job and return it. Implements job_start().
5421+
* "argv_arg" is only for Unix.
5422+
* When "argv_arg" is NULL then "argvars" is used.
54215423
* The returned job has a refcount of one.
54225424
* Returns NULL when out of memory.
54235425
*/
54245426
job_T *
5425-
job_start(typval_T *argvars, jobopt_T *opt_arg)
5427+
job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg)
54265428
{
54275429
job_T *job;
54285430
char_u *cmd = NULL;
@@ -5509,6 +5511,13 @@ job_start(typval_T *argvars, jobopt_T *opt_arg)
55095511

55105512
job_set_options(job, &opt);
55115513

5514+
#ifdef USE_ARGV
5515+
if (argv_arg != NULL)
5516+
{
5517+
argv = argv_arg;
5518+
}
5519+
else
5520+
#endif
55125521
if (argvars[0].v_type == VAR_STRING)
55135522
{
55145523
/* Command is a string. */
@@ -5586,7 +5595,8 @@ job_start(typval_T *argvars, jobopt_T *opt_arg)
55865595

55875596
theend:
55885597
#ifdef USE_ARGV
5589-
vim_free(argv);
5598+
if (argv != argv_arg)
5599+
vim_free(argv);
55905600
#else
55915601
vim_free(ga.ga_data);
55925602
#endif

src/evalfunc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7051,7 +7051,7 @@ f_job_start(typval_T *argvars, typval_T *rettv)
70517051
rettv->v_type = VAR_JOB;
70527052
if (check_restricted() || check_secure())
70537053
return;
7054-
rettv->vval.v_job = job_start(argvars, NULL);
7054+
rettv->vval.v_job = job_start(argvars, NULL, NULL);
70557055
}
70567056

70577057
/*

src/option.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@
214214
#define SHM_ALL "rmfixlnwaWtToOsAIcqF" /* all possible flags for 'shm' */
215215

216216
/* characters for p_go: */
217+
#define GO_TERMINAL '!' /* use terminal for system commands */
217218
#define GO_ASEL 'a' /* autoselect */
218219
#define GO_ASELML 'A' /* autoselect modeless selection */
219220
#define GO_BOT 'b' /* use bottom scrollbar */
@@ -236,7 +237,7 @@
236237
#define GO_FOOTER 'F' /* add footer */
237238
#define GO_VERTICAL 'v' /* arrange dialog buttons vertically */
238239
#define GO_KEEPWINSIZE 'k' /* keep GUI window size */
239-
#define GO_ALL "aAbcefFghilmMprtTvk" /* all possible flags for 'go' */
240+
#define GO_ALL "!aAbcefFghilmMprtTvk" /* all possible flags for 'go' */
240241

241242
/* flags for 'comments' option */
242243
#define COM_NEST 'n' /* comments strings nest */

src/os_unix.c

Lines changed: 153 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4160,10 +4160,13 @@ wait4pid(pid_t child, waitstatus *status)
41604160
return wait_pid;
41614161
}
41624162

4163-
#if defined(FEAT_JOB_CHANNEL) || !defined(USE_SYSTEM) || defined(PROTO)
4163+
#if defined(FEAT_JOB_CHANNEL) \
4164+
|| !defined(USE_SYSTEM) \
4165+
|| (defined(FEAT_GUI) && defined(FEAT_TERMINAL)) \
4166+
|| defined(PROTO)
41644167
/*
41654168
* Parse "cmd" and put the white-separated parts in "argv".
4166-
* "argv" is an allocated array with "argc" entries.
4169+
* "argv" is an allocated array with "argc" entries and room for 4 more.
41674170
* Returns FAIL when out of memory.
41684171
*/
41694172
int
@@ -4365,8 +4368,121 @@ may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
43654368
# endif
43664369
}
43674370

4368-
int
4369-
mch_call_shell(
4371+
#if !defined(USE_SYSTEM) || (defined(FEAT_GUI) && defined(FEAT_TERMINAL))
4372+
4373+
static int
4374+
build_argv(
4375+
char_u *cmd,
4376+
char ***argvp,
4377+
char_u **sh_tofree,
4378+
char_u **shcf_tofree)
4379+
{
4380+
char **argv = NULL;
4381+
int argc;
4382+
4383+
*sh_tofree = vim_strsave(p_sh);
4384+
if (*sh_tofree == NULL) /* out of memory */
4385+
return FAIL;
4386+
4387+
if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4388+
return FAIL;
4389+
*argvp = argv;
4390+
4391+
if (cmd != NULL)
4392+
{
4393+
char_u *s;
4394+
char_u *p;
4395+
4396+
if (extra_shell_arg != NULL)
4397+
argv[argc++] = (char *)extra_shell_arg;
4398+
4399+
/* Break 'shellcmdflag' into white separated parts. This doesn't
4400+
* handle quoted strings, they are very unlikely to appear. */
4401+
*shcf_tofree = alloc((unsigned)STRLEN(p_shcf) + 1);
4402+
if (*shcf_tofree == NULL) /* out of memory */
4403+
return FAIL;
4404+
s = *shcf_tofree;
4405+
p = p_shcf;
4406+
while (*p != NUL)
4407+
{
4408+
argv[argc++] = (char *)s;
4409+
while (*p && *p != ' ' && *p != TAB)
4410+
*s++ = *p++;
4411+
*s++ = NUL;
4412+
p = skipwhite(p);
4413+
}
4414+
4415+
argv[argc++] = (char *)cmd;
4416+
}
4417+
argv[argc] = NULL;
4418+
return OK;
4419+
}
4420+
#endif
4421+
4422+
#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4423+
/*
4424+
* Use a terminal window to run a shell command in.
4425+
*/
4426+
static int
4427+
mch_call_shell_terminal(
4428+
char_u *cmd,
4429+
int options UNUSED) /* SHELL_*, see vim.h */
4430+
{
4431+
jobopt_T opt;
4432+
char **argv = NULL;
4433+
char_u *tofree1 = NULL;
4434+
char_u *tofree2 = NULL;
4435+
int retval = -1;
4436+
buf_T *buf;
4437+
aco_save_T aco;
4438+
oparg_T oa; /* operator arguments */
4439+
4440+
if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
4441+
goto theend;
4442+
4443+
init_job_options(&opt);
4444+
ch_log(NULL, "starting terminal for system command '%s'", cmd);
4445+
buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
4446+
4447+
/* Find a window to make "buf" curbuf. */
4448+
aucmd_prepbuf(&aco, buf);
4449+
4450+
clear_oparg(&oa);
4451+
while (term_use_loop())
4452+
{
4453+
if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4454+
{
4455+
/* If terminal_loop() returns OK we got a key that is handled
4456+
* in Normal model. We don't do redrawing anyway. */
4457+
if (terminal_loop(TRUE) == OK)
4458+
normal_cmd(&oa, TRUE);
4459+
}
4460+
else
4461+
normal_cmd(&oa, TRUE);
4462+
}
4463+
retval = 0;
4464+
ch_log(NULL, "system command finished");
4465+
4466+
/* restore curwin/curbuf and a few other things */
4467+
aucmd_restbuf(&aco);
4468+
4469+
wait_return(TRUE);
4470+
do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4471+
4472+
theend:
4473+
vim_free(argv);
4474+
vim_free(tofree1);
4475+
vim_free(tofree2);
4476+
return retval;
4477+
}
4478+
#endif
4479+
4480+
#ifdef USE_SYSTEM
4481+
/*
4482+
* Use system() to start the shell: simple but slow.
4483+
*/
4484+
static int
4485+
mch_call_shell_system(
43704486
char_u *cmd,
43714487
int options) /* SHELL_*, see vim.h */
43724488
{
@@ -4375,7 +4491,6 @@ mch_call_shell(
43754491
char *ofn = NULL;
43764492
#endif
43774493
int tmode = cur_tmode;
4378-
#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
43794494
char_u *newcmd; /* only needed for unix */
43804495
int x;
43814496

@@ -4455,14 +4570,23 @@ mch_call_shell(
44554570
restore_clipboard();
44564571
# endif
44574572
return x;
4573+
}
44584574

4459-
#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
4575+
#else /* USE_SYSTEM */
44604576

44614577
# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
44624578
127, some shells use that already */
44634579
# define OPEN_NULL_FAILED 123 /* Exit code if /dev/null can't be opened */
44644580

4465-
char_u *newcmd;
4581+
/*
4582+
* Don't use system(), use fork()/exec().
4583+
*/
4584+
static int
4585+
mch_call_shell_fork(
4586+
char_u *cmd,
4587+
int options) /* SHELL_*, see vim.h */
4588+
{
4589+
int tmode = cur_tmode;
44664590
pid_t pid;
44674591
pid_t wpid = 0;
44684592
pid_t wait_pid = 0;
@@ -4473,8 +4597,8 @@ mch_call_shell(
44734597
# endif
44744598
int retval = -1;
44754599
char **argv = NULL;
4476-
int argc;
4477-
char_u *p_shcf_copy = NULL;
4600+
char_u *tofree1 = NULL;
4601+
char_u *tofree2 = NULL;
44784602
int i;
44794603
char_u *p;
44804604
int pty_master_fd = -1; /* for pty's */
@@ -4486,10 +4610,6 @@ mch_call_shell(
44864610
int pipe_error = FALSE;
44874611
int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
44884612

4489-
newcmd = vim_strsave(p_sh);
4490-
if (newcmd == NULL) /* out of memory */
4491-
goto error;
4492-
44934613
out_flush();
44944614
#ifdef FEAT_GUI_MACVIM
44954615
/* It is conceivable that the shell command will take a long time to finish
@@ -4500,36 +4620,9 @@ mch_call_shell(
45004620
if (options & SHELL_COOKED)
45014621
settmode(TMODE_COOK); /* set to normal mode */
45024622

4503-
if (mch_parse_cmd(newcmd, TRUE, &argv, &argc) == FAIL)
4623+
if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
45044624
goto error;
45054625

4506-
if (cmd != NULL)
4507-
{
4508-
char_u *s;
4509-
4510-
if (extra_shell_arg != NULL)
4511-
argv[argc++] = (char *)extra_shell_arg;
4512-
4513-
/* Break 'shellcmdflag' into white separated parts. This doesn't
4514-
* handle quoted strings, they are very unlikely to appear. */
4515-
p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4516-
if (p_shcf_copy == NULL) /* out of memory */
4517-
goto error;
4518-
s = p_shcf_copy;
4519-
p = p_shcf;
4520-
while (*p != NUL)
4521-
{
4522-
argv[argc++] = (char *)s;
4523-
while (*p && *p != ' ' && *p != TAB)
4524-
*s++ = *p++;
4525-
*s++ = NUL;
4526-
p = skipwhite(p);
4527-
}
4528-
4529-
argv[argc++] = (char *)cmd;
4530-
}
4531-
argv[argc] = NULL;
4532-
45334626
/*
45344627
* For the GUI, when writing the output into the buffer and when reading
45354628
* input from the buffer: Try using a pseudo-tty to get the stdin/stdout
@@ -5341,8 +5434,6 @@ mch_call_shell(
53415434
MSG_PUTS(_("\nCommand terminated\n"));
53425435
}
53435436
}
5344-
vim_free(argv);
5345-
vim_free(p_shcf_copy);
53465437

53475438
error:
53485439
if (!did_settmode)
@@ -5351,11 +5442,28 @@ mch_call_shell(
53515442
# ifdef FEAT_TITLE
53525443
resettitle();
53535444
# endif
5354-
vim_free(newcmd);
5445+
vim_free(argv);
5446+
vim_free(tofree1);
5447+
vim_free(tofree2);
53555448

53565449
return retval;
5357-
5450+
}
53585451
#endif /* USE_SYSTEM */
5452+
5453+
int
5454+
mch_call_shell(
5455+
char_u *cmd,
5456+
int options) /* SHELL_*, see vim.h */
5457+
{
5458+
#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5459+
if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5460+
return mch_call_shell_terminal(cmd, options);
5461+
#endif
5462+
#ifdef USE_SYSTEM
5463+
return mch_call_shell_system(cmd, options);
5464+
#else
5465+
return mch_call_shell_fork(cmd, options);
5466+
#endif
53595467
}
53605468

53615469
#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)

src/proto/channel.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void job_set_options(job_T *job, jobopt_T *opt);
6767
void job_stop_on_exit(void);
6868
int has_pending_job(void);
6969
void job_check_ended(void);
70-
job_T *job_start(typval_T *argvars, jobopt_T *opt_arg);
70+
job_T *job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg);
7171
char *job_status(job_T *job);
7272
void job_info(job_T *job, dict_T *dict);
7373
int job_stop(job_T *job, typval_T *argvars, char *type);

src/proto/terminal.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/* terminal.c */
2+
void init_job_options(jobopt_T *opt);
3+
buf_T *term_start(typval_T *argvar, char **argv, jobopt_T *opt, int flags);
24
void ex_terminal(exarg_T *eap);
35
int term_write_session(FILE *fd, win_T *wp);
46
int term_should_restore(buf_T *buf);

0 commit comments

Comments
 (0)