mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge #6497 from justinmk/win-quot
win: system('...'): special-case cmd.exe
This commit is contained in:
commit
dd391bfca1
@ -1524,13 +1524,18 @@ v:errors Errors found by assert functions, such as |assert_true()|.
|
|||||||
list by the assert function.
|
list by the assert function.
|
||||||
|
|
||||||
*v:event* *event-variable*
|
*v:event* *event-variable*
|
||||||
v:event Dictionary of event data for the current |autocommand|. The
|
v:event Dictionary of event data for the current |autocommand|. Valid
|
||||||
available keys differ per event type and are specified at the
|
only during the autocommand lifetime: storing or passing
|
||||||
documentation for each |event|. The possible keys are:
|
`v:event` is invalid. Copy it instead: >
|
||||||
operator The operation performed. Unlike
|
au TextYankPost * let g:foo = deepcopy(v:event)
|
||||||
|v:operator|, it is set also for an Ex
|
< Keys vary by event; see the documentation for the specific
|
||||||
mode command. For instance, |:yank| is
|
event, e.g. |TextYankPost|.
|
||||||
translated to "|y|".
|
KEY DESCRIPTION ~
|
||||||
|
operator The current |operator|. Also set for
|
||||||
|
Ex commands (unlike |v:operator|). For
|
||||||
|
example if |TextYankPost| is triggered
|
||||||
|
by the |:yank| Ex command then
|
||||||
|
`v:event['operator']` is "y".
|
||||||
regcontents Text stored in the register as a
|
regcontents Text stored in the register as a
|
||||||
|readfile()|-style list of lines.
|
|readfile()|-style list of lines.
|
||||||
regname Requested register (e.g "x" for "xyy)
|
regname Requested register (e.g "x" for "xyy)
|
||||||
@ -4847,16 +4852,18 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
|
|||||||
Spawns {cmd} as a job. If {cmd} is a |List| it is run
|
Spawns {cmd} as a job. If {cmd} is a |List| it is run
|
||||||
directly. If {cmd} is a |String| it is processed like this: >
|
directly. If {cmd} is a |String| it is processed like this: >
|
||||||
:call jobstart(split(&shell) + split(&shellcmdflag) + ['{cmd}'])
|
:call jobstart(split(&shell) + split(&shellcmdflag) + ['{cmd}'])
|
||||||
< NOTE: This only shows the idea; see |shell-unquoting| before
|
< (Only shows the idea; see |shell-unquoting| for full details.)
|
||||||
constructing lists with 'shell' or 'shellcmdflag'.
|
|
||||||
|
NOTE: on Windows if {cmd} is a List:
|
||||||
|
- cmd[0] must be an executable (not a "built-in"). If it is
|
||||||
|
in $PATH it can be called by name, without an extension: >
|
||||||
|
:call jobstart(['ping', 'neovim.io'])
|
||||||
|
< If it is a full or partial path, extension is required: >
|
||||||
|
:call jobstart(['System32\ping.exe', 'neovim.io'])
|
||||||
|
< - {cmd} is collapsed to a string of quoted args as expected
|
||||||
|
by CommandLineToArgvW https://msdn.microsoft.com/bb776391
|
||||||
|
unless cmd[0] is some form of "cmd.exe".
|
||||||
|
|
||||||
NOTE: On Windows if {cmd} is a List, cmd[0] must be a valid
|
|
||||||
executable (.exe, .com). If the executable is in $PATH it can
|
|
||||||
be called by name, with or without an extension: >
|
|
||||||
:call jobstart(['ping', 'neovim.io'])
|
|
||||||
< If it is a path (not a name), it must include the extension: >
|
|
||||||
:call jobstart(['System32\ping.exe', 'neovim.io'])
|
|
||||||
<
|
|
||||||
{opts} is a dictionary with these keys:
|
{opts} is a dictionary with these keys:
|
||||||
on_stdout: stdout event handler (function name or |Funcref|)
|
on_stdout: stdout event handler (function name or |Funcref|)
|
||||||
on_stderr: stderr event handler (function name or |Funcref|)
|
on_stderr: stderr event handler (function name or |Funcref|)
|
||||||
|
@ -2765,8 +2765,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
|
|
||||||
*'grepprg'* *'gp'*
|
*'grepprg'* *'gp'*
|
||||||
'grepprg' 'gp' string (default "grep -n ",
|
'grepprg' 'gp' string (default "grep -n ",
|
||||||
Unix: "grep -n $* /dev/null",
|
Unix: "grep -n $* /dev/null")
|
||||||
Win32: "findstr /n" or "grep -n")
|
|
||||||
global or local to buffer |global-local|
|
global or local to buffer |global-local|
|
||||||
Program to use for the |:grep| command. This option may contain '%'
|
Program to use for the |:grep| command. This option may contain '%'
|
||||||
and '#' characters, which are expanded like when used in a command-
|
and '#' characters, which are expanded like when used in a command-
|
||||||
@ -2781,8 +2780,6 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
|:vimgrepadd| and |:lgrepadd| like |:lvimgrepadd|.
|
|:vimgrepadd| and |:lgrepadd| like |:lvimgrepadd|.
|
||||||
See also the section |:make_makeprg|, since most of the comments there
|
See also the section |:make_makeprg|, since most of the comments there
|
||||||
apply equally to 'grepprg'.
|
apply equally to 'grepprg'.
|
||||||
For Win32, the default is "findstr /n" if "findstr.exe" can be found,
|
|
||||||
otherwise it's "grep -n".
|
|
||||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||||
security reasons.
|
security reasons.
|
||||||
|
|
||||||
@ -5251,9 +5248,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
security reasons.
|
security reasons.
|
||||||
|
|
||||||
*'shellcmdflag'* *'shcf'*
|
*'shellcmdflag'* *'shcf'*
|
||||||
'shellcmdflag' 'shcf' string (default: "-c";
|
'shellcmdflag' 'shcf' string (default: "-c"; Windows: "/c")
|
||||||
Windows, when 'shell' does not
|
|
||||||
contain "sh" somewhere: "/c")
|
|
||||||
global
|
global
|
||||||
Flag passed to the shell to execute "!" and ":!" commands; e.g.,
|
Flag passed to the shell to execute "!" and ":!" commands; e.g.,
|
||||||
"bash.exe -c ls" or "cmd.exe /c dir". For Windows
|
"bash.exe -c ls" or "cmd.exe /c dir". For Windows
|
||||||
@ -5264,15 +5259,12 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
See |option-backslash| about including spaces and backslashes.
|
See |option-backslash| about including spaces and backslashes.
|
||||||
See |shell-unquoting| which talks about separating this option into
|
See |shell-unquoting| which talks about separating this option into
|
||||||
multiple arguments.
|
multiple arguments.
|
||||||
Also see |dos-shell| for Windows.
|
|
||||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||||
security reasons.
|
security reasons.
|
||||||
|
|
||||||
*'shellpipe'* *'sp'*
|
*'shellpipe'* *'sp'*
|
||||||
'shellpipe' 'sp' string (default ">", "| tee", "|& tee" or "2>&1| tee")
|
'shellpipe' 'sp' string (default ">", "| tee", "|& tee" or "2>&1| tee")
|
||||||
global
|
global
|
||||||
{not available when compiled without the |+quickfix|
|
|
||||||
feature}
|
|
||||||
String to be used to put the output of the ":make" command in the
|
String to be used to put the output of the ":make" command in the
|
||||||
error file. See also |:make_makeprg|. See |option-backslash| about
|
error file. See also |:make_makeprg|. See |option-backslash| about
|
||||||
including spaces and backslashes.
|
including spaces and backslashes.
|
||||||
@ -5314,7 +5306,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
third-party shells on Windows systems, such as the MKS Korn Shell
|
third-party shells on Windows systems, such as the MKS Korn Shell
|
||||||
or bash, where it should be "\"". The default is adjusted according
|
or bash, where it should be "\"". The default is adjusted according
|
||||||
the value of 'shell', to reduce the need to set this option by the
|
the value of 'shell', to reduce the need to set this option by the
|
||||||
user. See |dos-shell|.
|
user.
|
||||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||||
security reasons.
|
security reasons.
|
||||||
|
|
||||||
@ -5346,7 +5338,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*'shellslash'* *'ssl'* *'noshellslash'* *'nossl'*
|
*'shellslash'* *'ssl'* *'noshellslash'* *'nossl'*
|
||||||
'shellslash' 'ssl' boolean (default off)
|
'shellslash' 'ssl' boolean (default off)
|
||||||
global
|
global
|
||||||
{only for MSDOS and MS-Windows}
|
{only for Windows}
|
||||||
When set, a forward slash is used when expanding file names. This is
|
When set, a forward slash is used when expanding file names. This is
|
||||||
useful when a Unix-like shell is used instead of command.com or
|
useful when a Unix-like shell is used instead of command.com or
|
||||||
cmd.exe. Backward slashes can still be typed, but they are changed to
|
cmd.exe. Backward slashes can still be typed, but they are changed to
|
||||||
@ -5363,10 +5355,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
global
|
global
|
||||||
When on, use temp files for shell commands. When off use a pipe.
|
When on, use temp files for shell commands. When off use a pipe.
|
||||||
When using a pipe is not possible temp files are used anyway.
|
When using a pipe is not possible temp files are used anyway.
|
||||||
Currently a pipe is only supported on Unix and MS-Windows 2K and
|
The advantage of using a pipe is that nobody can read the temp file
|
||||||
later. You can check it with: >
|
|
||||||
:if has("filterpipe")
|
|
||||||
< The advantage of using a pipe is that nobody can read the temp file
|
|
||||||
and the 'shell' command does not need to support redirection.
|
and the 'shell' command does not need to support redirection.
|
||||||
The advantage of using a temp file is that the file type and encoding
|
The advantage of using a temp file is that the file type and encoding
|
||||||
can be detected.
|
can be detected.
|
||||||
@ -5376,19 +5365,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
|system()| does not respect this option, it always uses pipes.
|
|system()| does not respect this option, it always uses pipes.
|
||||||
|
|
||||||
*'shellxescape'* *'sxe'*
|
*'shellxescape'* *'sxe'*
|
||||||
'shellxescape' 'sxe' string (default: "";
|
'shellxescape' 'sxe' string (default: "")
|
||||||
for Windows: "\"&|<>()@^")
|
|
||||||
global
|
global
|
||||||
When 'shellxquote' is set to "(" then the characters listed in this
|
When 'shellxquote' is set to "(" then the characters listed in this
|
||||||
option will be escaped with a '^' character. This makes it possible
|
option will be escaped with a '^' character. This makes it possible
|
||||||
to execute most external commands with cmd.exe.
|
to execute most external commands with cmd.exe.
|
||||||
|
|
||||||
*'shellxquote'* *'sxq'*
|
*'shellxquote'* *'sxq'*
|
||||||
'shellxquote' 'sxq' string (default: "";
|
'shellxquote' 'sxq' string (default: "")
|
||||||
for Win32, when 'shell' is cmd.exe: "("
|
|
||||||
for Win32, when 'shell' contains "sh"
|
|
||||||
somewhere: "\""
|
|
||||||
for Unix, when using system(): "\"")
|
|
||||||
global
|
global
|
||||||
Quoting character(s), put around the command passed to the shell, for
|
Quoting character(s), put around the command passed to the shell, for
|
||||||
the "!" and ":!" commands. Includes the redirection. See
|
the "!" and ":!" commands. Includes the redirection. See
|
||||||
@ -5397,12 +5381,6 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
When the value is '(' then ')' is appended. When the value is '"('
|
When the value is '(' then ')' is appended. When the value is '"('
|
||||||
then ')"' is appended.
|
then ')"' is appended.
|
||||||
When the value is '(' then also see 'shellxescape'.
|
When the value is '(' then also see 'shellxescape'.
|
||||||
This is an empty string by default on most systems, but is known to be
|
|
||||||
useful for on Win32 version, either for cmd.exe which automatically
|
|
||||||
strips off the first and last quote on a command, or 3rd-party shells
|
|
||||||
such as the MKS Korn Shell or bash, where it should be "\"". The
|
|
||||||
default is adjusted according the value of 'shell', to reduce the need
|
|
||||||
to set this option by the user. See |dos-shell|.
|
|
||||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||||
security reasons.
|
security reasons.
|
||||||
|
|
||||||
@ -6413,8 +6391,6 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*'title'* *'notitle'*
|
*'title'* *'notitle'*
|
||||||
'title' boolean (default off, on when title can be restored)
|
'title' boolean (default off, on when title can be restored)
|
||||||
global
|
global
|
||||||
{not available when compiled without the |+title|
|
|
||||||
feature}
|
|
||||||
When on, the title of the window will be set to the value of
|
When on, the title of the window will be set to the value of
|
||||||
'titlestring' (if it is not empty), or to:
|
'titlestring' (if it is not empty), or to:
|
||||||
filename [+=-] (path) - VIM
|
filename [+=-] (path) - VIM
|
||||||
@ -6426,16 +6402,10 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
=+ indicates the file is read-only and modified
|
=+ indicates the file is read-only and modified
|
||||||
(path) is the path of the file being edited
|
(path) is the path of the file being edited
|
||||||
- VIM the server name |v:servername| or "VIM"
|
- VIM the server name |v:servername| or "VIM"
|
||||||
Only works if the terminal supports setting window titles
|
|
||||||
(currently Win32 console, all GUI versions and terminals with a non-
|
|
||||||
empty 't_ts' option - this is Unix xterm by default, where 't_ts' is
|
|
||||||
taken from the builtin termcap).
|
|
||||||
|
|
||||||
*'titlelen'*
|
*'titlelen'*
|
||||||
'titlelen' number (default 85)
|
'titlelen' number (default 85)
|
||||||
global
|
global
|
||||||
{not available when compiled without the |+title|
|
|
||||||
feature}
|
|
||||||
Gives the percentage of 'columns' to use for the length of the window
|
Gives the percentage of 'columns' to use for the length of the window
|
||||||
title. When the title is longer, only the end of the path name is
|
title. When the title is longer, only the end of the path name is
|
||||||
shown. A '<' character before the path name is used to indicate this.
|
shown. A '<' character before the path name is used to indicate this.
|
||||||
@ -6449,8 +6419,6 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*'titleold'*
|
*'titleold'*
|
||||||
'titleold' string (default "Thanks for flying Vim")
|
'titleold' string (default "Thanks for flying Vim")
|
||||||
global
|
global
|
||||||
{only available when compiled with the |+title|
|
|
||||||
feature}
|
|
||||||
This option will be used for the window title when exiting Vim if the
|
This option will be used for the window title when exiting Vim if the
|
||||||
original title cannot be restored. Only happens if 'title' is on or
|
original title cannot be restored. Only happens if 'title' is on or
|
||||||
'titlestring' is not empty.
|
'titlestring' is not empty.
|
||||||
@ -6459,13 +6427,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*'titlestring'*
|
*'titlestring'*
|
||||||
'titlestring' string (default "")
|
'titlestring' string (default "")
|
||||||
global
|
global
|
||||||
{not available when compiled without the |+title|
|
|
||||||
feature}
|
|
||||||
When this option is not empty, it will be used for the title of the
|
When this option is not empty, it will be used for the title of the
|
||||||
window. This happens only when the 'title' option is on.
|
window. This happens only when the 'title' option is on.
|
||||||
Only works if the terminal supports setting window titles (currently
|
|
||||||
Win32 console, all GUI versions and terminals with a non-empty 't_ts'
|
|
||||||
option).
|
|
||||||
When this option contains printf-style '%' items, they will be
|
When this option contains printf-style '%' items, they will be
|
||||||
expanded according to the rules used for 'statusline'.
|
expanded according to the rules used for 'statusline'.
|
||||||
Example: >
|
Example: >
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "nvim/event/process.h"
|
#include "nvim/event/process.h"
|
||||||
#include "nvim/event/libuv_process.h"
|
#include "nvim/event/libuv_process.h"
|
||||||
#include "nvim/log.h"
|
#include "nvim/log.h"
|
||||||
|
#include "nvim/os/os.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "event/libuv_process.c.generated.h"
|
# include "event/libuv_process.c.generated.h"
|
||||||
@ -24,6 +25,13 @@ int libuv_process_spawn(LibuvProcess *uvproc)
|
|||||||
if (proc->detach) {
|
if (proc->detach) {
|
||||||
uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
|
uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
|
||||||
}
|
}
|
||||||
|
#ifdef WIN32
|
||||||
|
// libuv collapses the argv to a CommandLineToArgvW()-style string. cmd.exe
|
||||||
|
// expects a different syntax (must be prepared by the caller before now).
|
||||||
|
if (os_shell_is_cmdexe(proc->argv[0])) {
|
||||||
|
uvproc->uvopts.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
uvproc->uvopts.exit_cb = exit_cb;
|
uvproc->uvopts.exit_cb = exit_cb;
|
||||||
uvproc->uvopts.cwd = proc->cwd;
|
uvproc->uvopts.cwd = proc->cwd;
|
||||||
uvproc->uvopts.env = NULL;
|
uvproc->uvopts.env = NULL;
|
||||||
|
@ -495,6 +495,13 @@ bool strequal(const char *a, const char *b)
|
|||||||
return (a == NULL && b == NULL) || (a && b && strcmp(a, b) == 0);
|
return (a == NULL && b == NULL) || (a && b && strcmp(a, b) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Case-insensitive `strequal`.
|
||||||
|
bool striequal(const char *a, const char *b)
|
||||||
|
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
|
{
|
||||||
|
return (a == NULL && b == NULL) || (a && b && STRICMP(a, b) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Avoid repeating the error message many times (they take 1 second each).
|
* Avoid repeating the error message many times (they take 1 second each).
|
||||||
* Did_outofmem_msg is reset when a character is read.
|
* Did_outofmem_msg is reset when a character is read.
|
||||||
|
@ -2678,7 +2678,8 @@ void fast_breakcheck(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call shell. Calls os_call_shell, with 'shellxquote' added.
|
// os_call_shell wrapper. Handles 'verbose', :profile, and v:shell_error.
|
||||||
|
// Invalidates cached tags.
|
||||||
int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
|
int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
@ -2686,8 +2687,7 @@ int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
|
|||||||
|
|
||||||
if (p_verbose > 3) {
|
if (p_verbose > 3) {
|
||||||
verbose_enter();
|
verbose_enter();
|
||||||
smsg(_("Calling shell to execute: \"%s\""),
|
smsg(_("Calling shell to execute: \"%s\""), cmd == NULL ? p_sh : cmd);
|
||||||
cmd == NULL ? p_sh : cmd);
|
|
||||||
ui_putc('\n');
|
ui_putc('\n');
|
||||||
verbose_leave();
|
verbose_leave();
|
||||||
}
|
}
|
||||||
|
@ -2051,7 +2051,11 @@ return {
|
|||||||
secure=true,
|
secure=true,
|
||||||
vi_def=true,
|
vi_def=true,
|
||||||
varname='p_srr',
|
varname='p_srr',
|
||||||
defaults={if_true={vi=">"}}
|
defaults={
|
||||||
|
condition='WIN32',
|
||||||
|
if_true={vi=">%s 2>&1"},
|
||||||
|
if_false={vi=">"}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
full_name='shellslash', abbreviation='ssl',
|
full_name='shellslash', abbreviation='ssl',
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
// env.c -- environment variable access
|
// Environment inspection
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
// vim.h must be included before charset.h (and possibly others) or things
|
|
||||||
// blow up
|
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
@ -919,3 +916,20 @@ bool os_term_is_nice(void)
|
|||||||
|| NULL != os_getenv("KONSOLE_DBUS_SESSION");
|
|| NULL != os_getenv("KONSOLE_DBUS_SESSION");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if `sh` looks like it resolves to "cmd.exe".
|
||||||
|
bool os_shell_is_cmdexe(const char *sh)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
if (*sh == NUL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (striequal(sh, "$COMSPEC")) {
|
||||||
|
const char *comspec = os_getenv("COMSPEC");
|
||||||
|
return striequal("cmd.exe", (char *)path_tail((char_u *)comspec));
|
||||||
|
}
|
||||||
|
if (striequal(sh, "cmd.exe") || striequal(sh, "cmd")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return striequal("cmd.exe", (char *)path_tail((char_u *)sh));
|
||||||
|
}
|
||||||
|
@ -124,11 +124,9 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t nread;
|
size_t nread;
|
||||||
|
|
||||||
int exitcode = do_os_system(shell_build_argv((char *)cmd, (char *)extra_args),
|
int exitcode = do_os_system(shell_build_argv((char *)cmd, (char *)extra_args),
|
||||||
input.data, input.len, output_ptr, &nread,
|
input.data, input.len, output_ptr, &nread,
|
||||||
emsg_silent, forward_output);
|
emsg_silent, forward_output);
|
||||||
|
|
||||||
xfree(input.data);
|
xfree(input.data);
|
||||||
|
|
||||||
if (output) {
|
if (output) {
|
||||||
|
@ -198,8 +198,16 @@ char_u *vim_strsave_shellescape(const char_u *string,
|
|||||||
/* First count the number of extra bytes required. */
|
/* First count the number of extra bytes required. */
|
||||||
size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL
|
size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL
|
||||||
for (const char_u *p = string; *p != NUL; mb_ptr_adv(p)) {
|
for (const char_u *p = string; *p != NUL; mb_ptr_adv(p)) {
|
||||||
if (*p == '\'')
|
#ifdef WIN32
|
||||||
length += 3; /* ' => '\'' */
|
if (!p_ssl) {
|
||||||
|
if (*p == '"') {
|
||||||
|
length++; // " -> ""
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (*p == '\'') {
|
||||||
|
length += 3; // ' => '\''
|
||||||
|
}
|
||||||
if ((*p == '\n' && (csh_like || do_newline))
|
if ((*p == '\n' && (csh_like || do_newline))
|
||||||
|| (*p == '!' && (csh_like || do_special))) {
|
|| (*p == '!' && (csh_like || do_special))) {
|
||||||
++length; /* insert backslash */
|
++length; /* insert backslash */
|
||||||
@ -216,10 +224,25 @@ char_u *vim_strsave_shellescape(const char_u *string,
|
|||||||
escaped_string = xmalloc(length);
|
escaped_string = xmalloc(length);
|
||||||
d = escaped_string;
|
d = escaped_string;
|
||||||
|
|
||||||
/* add opening quote */
|
// add opening quote
|
||||||
|
#ifdef WIN32
|
||||||
|
if (!p_ssl) {
|
||||||
|
*d++ = '"';
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
*d++ = '\'';
|
*d++ = '\'';
|
||||||
|
|
||||||
for (const char_u *p = string; *p != NUL; ) {
|
for (const char_u *p = string; *p != NUL; ) {
|
||||||
|
#ifdef WIN32
|
||||||
|
if (!p_ssl) {
|
||||||
|
if (*p == '"') {
|
||||||
|
*d++ = '"';
|
||||||
|
*d++ = '"';
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
if (*p == '\'') {
|
if (*p == '\'') {
|
||||||
*d++ = '\'';
|
*d++ = '\'';
|
||||||
*d++ = '\\';
|
*d++ = '\\';
|
||||||
@ -246,7 +269,12 @@ char_u *vim_strsave_shellescape(const char_u *string,
|
|||||||
MB_COPY_CHAR(p, d);
|
MB_COPY_CHAR(p, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add terminating quote and finish with a NUL */
|
// add terminating quote and finish with a NUL
|
||||||
|
# ifdef WIN32
|
||||||
|
if (!p_ssl) {
|
||||||
|
*d++ = '"';
|
||||||
|
} else
|
||||||
|
# endif
|
||||||
*d++ = '\'';
|
*d++ = '\'';
|
||||||
*d = NUL;
|
*d = NUL;
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ local nvim_dir = helpers.nvim_dir
|
|||||||
local eq, call, clear, eval, feed_command, feed, nvim =
|
local eq, call, clear, eval, feed_command, feed, nvim =
|
||||||
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
|
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
|
||||||
helpers.feed, helpers.nvim
|
helpers.feed, helpers.nvim
|
||||||
|
local command = helpers.command
|
||||||
|
local iswin = helpers.iswin
|
||||||
|
|
||||||
local Screen = require('test.functional.ui.screen')
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
|
||||||
@ -33,8 +35,7 @@ describe('system()', function()
|
|||||||
|
|
||||||
describe('command passed as a List', function()
|
describe('command passed as a List', function()
|
||||||
local function printargs_path()
|
local function printargs_path()
|
||||||
return nvim_dir..'/printargs-test'
|
return nvim_dir..'/printargs-test' .. (iswin() and '.exe' or '')
|
||||||
.. (helpers.os_name() == 'windows' and '.exe' or '')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it('sets v:shell_error if cmd[0] is not executable', function()
|
it('sets v:shell_error if cmd[0] is not executable', function()
|
||||||
@ -88,23 +89,32 @@ describe('system()', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('does NOT run in shell', function()
|
it('does NOT run in shell', function()
|
||||||
if helpers.os_name() ~= 'windows' then
|
if not iswin() then
|
||||||
eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])"))
|
eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])"))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if helpers.pending_win32(pending) then return end
|
|
||||||
|
|
||||||
it('sets v:shell_error', function()
|
it('sets v:shell_error', function()
|
||||||
eval([[system("sh -c 'exit'")]])
|
if iswin() then
|
||||||
eq(0, eval('v:shell_error'))
|
eval([[system("cmd.exe /c exit")]])
|
||||||
eval([[system("sh -c 'exit 1'")]])
|
eq(0, eval('v:shell_error'))
|
||||||
eq(1, eval('v:shell_error'))
|
eval([[system("cmd.exe /c exit 1")]])
|
||||||
eval([[system("sh -c 'exit 5'")]])
|
eq(1, eval('v:shell_error'))
|
||||||
eq(5, eval('v:shell_error'))
|
eval([[system("cmd.exe /c exit 5")]])
|
||||||
eval([[system('this-should-not-exist')]])
|
eq(5, eval('v:shell_error'))
|
||||||
eq(127, eval('v:shell_error'))
|
eval([[system('this-should-not-exist')]])
|
||||||
|
eq(1, eval('v:shell_error'))
|
||||||
|
else
|
||||||
|
eval([[system("sh -c 'exit'")]])
|
||||||
|
eq(0, eval('v:shell_error'))
|
||||||
|
eval([[system("sh -c 'exit 1'")]])
|
||||||
|
eq(1, eval('v:shell_error'))
|
||||||
|
eval([[system("sh -c 'exit 5'")]])
|
||||||
|
eq(5, eval('v:shell_error'))
|
||||||
|
eval([[system('this-should-not-exist')]])
|
||||||
|
eq(127, eval('v:shell_error'))
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('executes shell function if passed a string', function()
|
describe('executes shell function if passed a string', function()
|
||||||
@ -120,6 +130,40 @@ describe('system()', function()
|
|||||||
screen:detach()
|
screen:detach()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
if iswin() then
|
||||||
|
it('with shell=cmd.exe', function()
|
||||||
|
command('set shell=cmd.exe')
|
||||||
|
eq('""\n', eval([[system('echo ""')]]))
|
||||||
|
eq('"a b"\n', eval([[system('echo "a b"')]]))
|
||||||
|
eq('a \nb\n', eval([[system('echo a & echo b')]]))
|
||||||
|
eq('a \n', eval([[system('echo a 2>&1')]]))
|
||||||
|
eval([[system('cd "C:\Program Files"')]])
|
||||||
|
eq(0, eval('v:shell_error'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('with shell=cmd', function()
|
||||||
|
command('set shell=cmd')
|
||||||
|
eq('"a b"\n', eval([[system('echo "a b"')]]))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('with shell=$COMSPEC', function()
|
||||||
|
local comspecshell = eval("fnamemodify($COMSPEC, ':t')")
|
||||||
|
if comspecshell == 'cmd.exe' then
|
||||||
|
command('set shell=$COMSPEC')
|
||||||
|
eq('"a b"\n', eval([[system('echo "a b"')]]))
|
||||||
|
else
|
||||||
|
pending('$COMSPEC is not cmd.exe: ' .. comspecshell)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('works with powershell', function()
|
||||||
|
helpers.set_shell_powershell()
|
||||||
|
eq('a\nb\n', eval([[system('echo a b')]]))
|
||||||
|
eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]]))
|
||||||
|
eq('a b\n', eval([[system('echo "a b"')]]))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
it('`echo` and waits for its return', function()
|
it('`echo` and waits for its return', function()
|
||||||
feed(':call system("echo")<cr>')
|
feed(':call system("echo")<cr>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
@ -180,7 +224,11 @@ describe('system()', function()
|
|||||||
|
|
||||||
describe('passing no input', function()
|
describe('passing no input', function()
|
||||||
it('returns the program output', function()
|
it('returns the program output', function()
|
||||||
eq("echoed", eval('system("echo -n echoed")'))
|
if iswin() then
|
||||||
|
eq("echoed\n", eval('system("echo echoed")'))
|
||||||
|
else
|
||||||
|
eq("echoed", eval('system("echo -n echoed")'))
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
it('to backgrounded command does not crash', function()
|
it('to backgrounded command does not crash', function()
|
||||||
-- This is indeterminate, just exercise the codepath. May get E5677.
|
-- This is indeterminate, just exercise the codepath. May get E5677.
|
||||||
@ -277,21 +325,30 @@ describe('system()', function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if helpers.pending_win32(pending) then return end
|
|
||||||
|
|
||||||
describe('systemlist()', function()
|
describe('systemlist()', function()
|
||||||
-- Similar to `system()`, but returns List instead of String.
|
-- Similar to `system()`, but returns List instead of String.
|
||||||
before_each(clear)
|
before_each(clear)
|
||||||
|
|
||||||
it('sets the v:shell_error variable', function()
|
it('sets v:shell_error', function()
|
||||||
eval([[systemlist("sh -c 'exit'")]])
|
if iswin() then
|
||||||
eq(0, eval('v:shell_error'))
|
eval([[systemlist("cmd.exe /c exit")]])
|
||||||
eval([[systemlist("sh -c 'exit 1'")]])
|
eq(0, eval('v:shell_error'))
|
||||||
eq(1, eval('v:shell_error'))
|
eval([[systemlist("cmd.exe /c exit 1")]])
|
||||||
eval([[systemlist("sh -c 'exit 5'")]])
|
eq(1, eval('v:shell_error'))
|
||||||
eq(5, eval('v:shell_error'))
|
eval([[systemlist("cmd.exe /c exit 5")]])
|
||||||
eval([[systemlist('this-should-not-exist')]])
|
eq(5, eval('v:shell_error'))
|
||||||
eq(127, eval('v:shell_error'))
|
eval([[systemlist('this-should-not-exist')]])
|
||||||
|
eq(1, eval('v:shell_error'))
|
||||||
|
else
|
||||||
|
eval([[systemlist("sh -c 'exit'")]])
|
||||||
|
eq(0, eval('v:shell_error'))
|
||||||
|
eval([[systemlist("sh -c 'exit 1'")]])
|
||||||
|
eq(1, eval('v:shell_error'))
|
||||||
|
eval([[systemlist("sh -c 'exit 5'")]])
|
||||||
|
eq(5, eval('v:shell_error'))
|
||||||
|
eval([[systemlist('this-should-not-exist')]])
|
||||||
|
eq(127, eval('v:shell_error'))
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('exectues shell function', function()
|
describe('exectues shell function', function()
|
||||||
@ -389,6 +446,7 @@ describe('systemlist()', function()
|
|||||||
after_each(delete_file(fname))
|
after_each(delete_file(fname))
|
||||||
|
|
||||||
it('replaces NULs by newline characters', function()
|
it('replaces NULs by newline characters', function()
|
||||||
|
if helpers.pending_win32(pending) then return end
|
||||||
eq({'part1\npart2\npart3'}, eval('systemlist("cat '..fname..'")'))
|
eq({'part1\npart2\npart3'}, eval('systemlist("cat '..fname..'")'))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -348,7 +348,7 @@ end
|
|||||||
local function set_shell_powershell()
|
local function set_shell_powershell()
|
||||||
source([[
|
source([[
|
||||||
set shell=powershell shellquote=\" shellpipe=\| shellredir=>
|
set shell=powershell shellquote=\" shellpipe=\| shellredir=>
|
||||||
set shellcmdflag=\ -ExecutionPolicy\ RemoteSigned\ -Command
|
set shellcmdflag=\ -NoProfile\ -ExecutionPolicy\ RemoteSigned\ -Command
|
||||||
let &shellxquote=' '
|
let &shellxquote=' '
|
||||||
]])
|
]])
|
||||||
end
|
end
|
||||||
|
@ -45,11 +45,8 @@ describe(':edit term://*', function()
|
|||||||
local bufcontents = {}
|
local bufcontents = {}
|
||||||
local winheight = curwinmeths.get_height()
|
local winheight = curwinmeths.get_height()
|
||||||
local buf_cont_start = rep_size - sb - winheight + 2
|
local buf_cont_start = rep_size - sb - winheight + 2
|
||||||
local function bufline (i)
|
|
||||||
return ('%d: foobar'):format(i)
|
|
||||||
end
|
|
||||||
for i = buf_cont_start,(rep_size - 1) do
|
for i = buf_cont_start,(rep_size - 1) do
|
||||||
bufcontents[#bufcontents + 1] = bufline(i)
|
bufcontents[#bufcontents + 1] = ('%d: foobar'):format(i)
|
||||||
end
|
end
|
||||||
bufcontents[#bufcontents + 1] = ''
|
bufcontents[#bufcontents + 1] = ''
|
||||||
bufcontents[#bufcontents + 1] = '[Process exited 0]'
|
bufcontents[#bufcontents + 1] = '[Process exited 0]'
|
||||||
|
@ -67,12 +67,37 @@ describe('env function', function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('os_shell_is_cmdexe', function()
|
||||||
|
itp('returns true for expected names', function()
|
||||||
|
eq(true, cimp.os_shell_is_cmdexe(to_cstr('cmd.exe')))
|
||||||
|
eq(true, cimp.os_shell_is_cmdexe(to_cstr('cmd')))
|
||||||
|
eq(true, cimp.os_shell_is_cmdexe(to_cstr('CMD.EXE')))
|
||||||
|
eq(true, cimp.os_shell_is_cmdexe(to_cstr('CMD')))
|
||||||
|
|
||||||
|
os_setenv('COMSPEC', '/foo/bar/cmd.exe', 0)
|
||||||
|
eq(true, cimp.os_shell_is_cmdexe(to_cstr('$COMSPEC')))
|
||||||
|
os_setenv('COMSPEC', [[C:\system32\cmd.exe]], 0)
|
||||||
|
eq(true, cimp.os_shell_is_cmdexe(to_cstr('$COMSPEC')))
|
||||||
|
end)
|
||||||
|
itp('returns false for unexpected names', function()
|
||||||
|
eq(false, cimp.os_shell_is_cmdexe(to_cstr('')))
|
||||||
|
eq(false, cimp.os_shell_is_cmdexe(to_cstr('powershell')))
|
||||||
|
eq(false, cimp.os_shell_is_cmdexe(to_cstr(' cmd.exe ')))
|
||||||
|
eq(false, cimp.os_shell_is_cmdexe(to_cstr('cm')))
|
||||||
|
eq(false, cimp.os_shell_is_cmdexe(to_cstr('md')))
|
||||||
|
eq(false, cimp.os_shell_is_cmdexe(to_cstr('cmd.ex')))
|
||||||
|
|
||||||
|
os_setenv('COMSPEC', '/foo/bar/cmd', 0)
|
||||||
|
eq(false, cimp.os_shell_is_cmdexe(to_cstr('$COMSPEC')))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
describe('os_getenv', function()
|
describe('os_getenv', function()
|
||||||
itp('reads an env variable', function()
|
itp('reads an env variable', function()
|
||||||
local name = 'NVIM_UNIT_TEST_GETENV_1N'
|
local name = 'NVIM_UNIT_TEST_GETENV_1N'
|
||||||
local value = 'NVIM_UNIT_TEST_GETENV_1V'
|
local value = 'NVIM_UNIT_TEST_GETENV_1V'
|
||||||
eq(NULL, os_getenv(name))
|
eq(NULL, os_getenv(name))
|
||||||
-- need to use os_setenv, because lua dosn't have a setenv function
|
-- Use os_setenv because Lua dosen't have setenv.
|
||||||
os_setenv(name, value, 1)
|
os_setenv(name, value, 1)
|
||||||
eq(value, os_getenv(name))
|
eq(value, os_getenv(name))
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user