0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 8.0.1609: shell commands in the GUI use a dumb terminal

Problem:    Shell commands in the GUI use a dumb terminal.
Solution:   Add the "!" flag to 'guioptions' to execute system commands in a
            special terminal window.  Only for Unix now.
This commit is contained in:
Bram Moolenaar
2018-03-16 20:46:58 +01:00
parent 43cb626214
commit 135682517b
10 changed files with 416 additions and 164 deletions

View File

@@ -4154,10 +4154,13 @@ wait4pid(pid_t child, waitstatus *status)
return wait_pid;
}
#if defined(FEAT_JOB_CHANNEL) || !defined(USE_SYSTEM) || defined(PROTO)
#if defined(FEAT_JOB_CHANNEL) \
|| !defined(USE_SYSTEM) \
|| (defined(FEAT_GUI) && defined(FEAT_TERMINAL)) \
|| defined(PROTO)
/*
* Parse "cmd" and put the white-separated parts in "argv".
* "argv" is an allocated array with "argc" entries.
* "argv" is an allocated array with "argc" entries and room for 4 more.
* Returns FAIL when out of memory.
*/
int
@@ -4359,8 +4362,121 @@ may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
# endif
}
int
mch_call_shell(
#if !defined(USE_SYSTEM) || (defined(FEAT_GUI) && defined(FEAT_TERMINAL))
static int
build_argv(
char_u *cmd,
char ***argvp,
char_u **sh_tofree,
char_u **shcf_tofree)
{
char **argv = NULL;
int argc;
*sh_tofree = vim_strsave(p_sh);
if (*sh_tofree == NULL) /* out of memory */
return FAIL;
if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
return FAIL;
*argvp = argv;
if (cmd != NULL)
{
char_u *s;
char_u *p;
if (extra_shell_arg != NULL)
argv[argc++] = (char *)extra_shell_arg;
/* Break 'shellcmdflag' into white separated parts. This doesn't
* handle quoted strings, they are very unlikely to appear. */
*shcf_tofree = alloc((unsigned)STRLEN(p_shcf) + 1);
if (*shcf_tofree == NULL) /* out of memory */
return FAIL;
s = *shcf_tofree;
p = p_shcf;
while (*p != NUL)
{
argv[argc++] = (char *)s;
while (*p && *p != ' ' && *p != TAB)
*s++ = *p++;
*s++ = NUL;
p = skipwhite(p);
}
argv[argc++] = (char *)cmd;
}
argv[argc] = NULL;
return OK;
}
#endif
#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
/*
* Use a terminal window to run a shell command in.
*/
static int
mch_call_shell_terminal(
char_u *cmd,
int options UNUSED) /* SHELL_*, see vim.h */
{
jobopt_T opt;
char **argv = NULL;
char_u *tofree1 = NULL;
char_u *tofree2 = NULL;
int retval = -1;
buf_T *buf;
aco_save_T aco;
oparg_T oa; /* operator arguments */
if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
goto theend;
init_job_options(&opt);
ch_log(NULL, "starting terminal for system command '%s'", cmd);
buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
/* Find a window to make "buf" curbuf. */
aucmd_prepbuf(&aco, buf);
clear_oparg(&oa);
while (term_use_loop())
{
if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
{
/* If terminal_loop() returns OK we got a key that is handled
* in Normal model. We don't do redrawing anyway. */
if (terminal_loop(TRUE) == OK)
normal_cmd(&oa, TRUE);
}
else
normal_cmd(&oa, TRUE);
}
retval = 0;
ch_log(NULL, "system command finished");
/* restore curwin/curbuf and a few other things */
aucmd_restbuf(&aco);
wait_return(TRUE);
do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
theend:
vim_free(argv);
vim_free(tofree1);
vim_free(tofree2);
return retval;
}
#endif
#ifdef USE_SYSTEM
/*
* Use system() to start the shell: simple but slow.
*/
static int
mch_call_shell_system(
char_u *cmd,
int options) /* SHELL_*, see vim.h */
{
@@ -4369,7 +4485,6 @@ mch_call_shell(
char *ofn = NULL;
#endif
int tmode = cur_tmode;
#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
char_u *newcmd; /* only needed for unix */
int x;
@@ -4443,14 +4558,23 @@ mch_call_shell(
restore_clipboard();
# endif
return x;
}
#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
#else /* USE_SYSTEM */
# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
127, some shells use that already */
# define OPEN_NULL_FAILED 123 /* Exit code if /dev/null can't be opened */
char_u *newcmd;
/*
* Don't use system(), use fork()/exec().
*/
static int
mch_call_shell_fork(
char_u *cmd,
int options) /* SHELL_*, see vim.h */
{
int tmode = cur_tmode;
pid_t pid;
pid_t wpid = 0;
pid_t wait_pid = 0;
@@ -4461,8 +4585,8 @@ mch_call_shell(
# endif
int retval = -1;
char **argv = NULL;
int argc;
char_u *p_shcf_copy = NULL;
char_u *tofree1 = NULL;
char_u *tofree2 = NULL;
int i;
char_u *p;
int pty_master_fd = -1; /* for pty's */
@@ -4474,44 +4598,13 @@ mch_call_shell(
int pipe_error = FALSE;
int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
newcmd = vim_strsave(p_sh);
if (newcmd == NULL) /* out of memory */
goto error;
out_flush();
if (options & SHELL_COOKED)
settmode(TMODE_COOK); /* set to normal mode */
if (mch_parse_cmd(newcmd, TRUE, &argv, &argc) == FAIL)
if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
goto error;
if (cmd != NULL)
{
char_u *s;
if (extra_shell_arg != NULL)
argv[argc++] = (char *)extra_shell_arg;
/* Break 'shellcmdflag' into white separated parts. This doesn't
* handle quoted strings, they are very unlikely to appear. */
p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
if (p_shcf_copy == NULL) /* out of memory */
goto error;
s = p_shcf_copy;
p = p_shcf;
while (*p != NUL)
{
argv[argc++] = (char *)s;
while (*p && *p != ' ' && *p != TAB)
*s++ = *p++;
*s++ = NUL;
p = skipwhite(p);
}
argv[argc++] = (char *)cmd;
}
argv[argc] = NULL;
/*
* For the GUI, when writing the output into the buffer and when reading
* input from the buffer: Try using a pseudo-tty to get the stdin/stdout
@@ -5319,8 +5412,6 @@ finished:
MSG_PUTS(_("\nCommand terminated\n"));
}
}
vim_free(argv);
vim_free(p_shcf_copy);
error:
if (!did_settmode)
@@ -5329,11 +5420,28 @@ error:
# ifdef FEAT_TITLE
resettitle();
# endif
vim_free(newcmd);
vim_free(argv);
vim_free(tofree1);
vim_free(tofree2);
return retval;
}
#endif /* USE_SYSTEM */
int
mch_call_shell(
char_u *cmd,
int options) /* SHELL_*, see vim.h */
{
#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
return mch_call_shell_terminal(cmd, options);
#endif
#ifdef USE_SYSTEM
return mch_call_shell_system(cmd, options);
#else
return mch_call_shell_fork(cmd, options);
#endif
}
#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)