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:
198
src/os_unix.c
198
src/os_unix.c
@@ -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)
|
||||
|
Reference in New Issue
Block a user