aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnan Ajmain <3nan.ajmain@gmail.com>2021-11-09 20:22:21 +0600
committerJustin M. Keyes <justinkz@gmail.com>2022-06-25 07:20:58 -0700
commit0b9664f5240be4d9e9d6882fcd398970fd3a9532 (patch)
treee02103f3cfd37f6c313c096a41c0d660ea6ebaf2
parentb7084fef4c850d0352488b14dcff0f36a7e75e1c (diff)
downloadrneovim-0b9664f5240be4d9e9d6882fcd398970fd3a9532.tar.gz
rneovim-0b9664f5240be4d9e9d6882fcd398970fd3a9532.tar.bz2
rneovim-0b9664f5240be4d9e9d6882fcd398970fd3a9532.zip
fix: make_filter_cmd for :! powershell #15913
Problem: Nvim fails to create tempfile "…/nvim6UJx04/7" when 'shell' is set to pwsh (PowerShell Core). This breaks filtered shell commands ":{range}!". With shell set to cmd, it works. Solution: PowerShell doesn't use "<" for stdin redirection. Instead, use "-RedirectStandardInput". Closes #15913
-rw-r--r--runtime/doc/options.txt4
-rw-r--r--src/nvim/ex_cmds.c32
-rw-r--r--test/functional/helpers.lua4
-rw-r--r--test/functional/vimscript/system_spec.lua28
4 files changed, 58 insertions, 10 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 20805377d8..4d86f792da 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5292,9 +5292,9 @@ A jump table for the options with a short description can be found at |Q_op|.
unescaping, so to keep yourself sane use |:let-&| like shown above.
*shell-powershell*
To use PowerShell: >
- let &shell = has('win32') ? 'powershell' : 'pwsh'
+ let &shell = executable('pwsh') ? 'pwsh' : 'powershell'
let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;'
- let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
+ let &shellredir = '-RedirectStandardOutput %s -NoNewWindow -Wait'
let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
set shellquote= shellxquote=
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index a1f0a123b1..0f351d8af6 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1573,14 +1573,18 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
#else
false;
#endif
+ bool is_pwsh = STRNCMP(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0
+ || STRNCMP(invocation_path_tail(p_sh, NULL), "powershell", 10) == 0;
size_t len = STRLEN(cmd) + 1; // At least enough space for cmd + NULL.
len += is_fish_shell ? sizeof("begin; " "; end") - 1
- : sizeof("(" ")") - 1;
+ : is_pwsh ? STRLEN("Start-Process ")
+ : sizeof("(" ")") - 1;
if (itmp != NULL) {
- len += STRLEN(itmp) + sizeof(" { " " < " " } ") - 1;
+ len += is_pwsh ? STRLEN(itmp) + STRLEN(" -RedirectStandardInput ")
+ : STRLEN(itmp) + sizeof(" { " " < " " } ") - 1;
}
if (otmp != NULL) {
len += STRLEN(otmp) + STRLEN(p_srr) + 2; // two extra spaces (" "),
@@ -1590,7 +1594,10 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
#if defined(UNIX)
// Put delimiters around the command (for concatenated commands) when
// redirecting input and/or output.
- if (itmp != NULL || otmp != NULL) {
+ if (is_pwsh) {
+ xstrlcpy(buf, "Start-Process ", len);
+ xstrlcat(buf, (char *)cmd, len);
+ } else if (itmp != NULL || otmp != NULL) {
char *fmt = is_fish_shell ? "begin; %s; end"
: "(%s)";
vim_snprintf(buf, len, fmt, cmd);
@@ -1599,13 +1606,22 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
}
if (itmp != NULL) {
- xstrlcat(buf, " < ", len - 1);
+ if (is_pwsh) {
+ xstrlcat(buf, " -RedirectStandardInput ", len - 1);
+ } else {
+ xstrlcat(buf, " < ", len - 1);
+ }
xstrlcat(buf, (const char *)itmp, len - 1);
}
#else
// For shells that don't understand braces around commands, at least allow
// the use of commands in a pipe.
- xstrlcpy(buf, (char *)cmd, len);
+ if (is_pwsh) {
+ xstrlcpy(buf, "Start-Process ", len);
+ xstrlcat(buf, (char *)cmd, len);
+ } else {
+ xstrlcpy(buf, (char *)cmd, len);
+ }
if (itmp != NULL) {
// If there is a pipe, we have to put the '<' in front of it.
// Don't do this when 'shellquote' is not empty, otherwise the
@@ -1616,7 +1632,11 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
*p = NUL;
}
}
- xstrlcat(buf, " < ", len);
+ if (is_pwsh) {
+ xstrlcat(buf, " -RedirectStandardInput ", len);
+ } else {
+ xstrlcat(buf, " < ", len);
+ }
xstrlcat(buf, (const char *)itmp, len);
if (*p_shq == NUL) {
const char *const p = find_pipe((const char *)cmd);
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index d31d337b63..2018f80052 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -525,9 +525,9 @@ function module.set_shell_powershell()
module.exec([[
let &shell = ']]..shell..[['
set shellquote= shellxquote=
- let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
- let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ]]..cmd..[['
+ let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
+ let &shellredir = '-RedirectStandardOutput %s -NoNewWindow -Wait'
]])
end
diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua
index 9cc6424d31..dd1ac694e7 100644
--- a/test/functional/vimscript/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -6,6 +6,8 @@ local eq, call, clear, eval, feed_command, feed, nvim =
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
helpers.feed, helpers.nvim
local command = helpers.command
+local insert = helpers.insert
+local expect = helpers.expect
local exc_exec = helpers.exc_exec
local iswin = helpers.iswin
local os_kill = helpers.os_kill
@@ -630,3 +632,29 @@ describe('systemlist()', function()
end)
end)
+
+it(':{range}! works with powershell for filter and redirection #16271', function()
+ clear()
+ if not helpers.has_powershell() then
+ pending("not tested; powershell was not found", function() end)
+ return
+ end
+ local screen = Screen.new(500, 8)
+ screen:attach()
+ helpers.set_shell_powershell()
+ insert([[
+ 3
+ 1
+ 4
+ 2]])
+ feed(':4verbose %!sort<cr>')
+ screen:expect{
+ any=[[Executing command: "Start%-Process sort %-RedirectStandardInput .* %-RedirectStandardOutput .* %-NoNewWindow %-Wait".*4 lines filtered.*Press ENTER or type command to continue]]
+ }
+ feed('<CR>')
+ expect([[
+ 1
+ 2
+ 3
+ 4]])
+end)