mirror of
https://github.com/neovim/neovim
synced 2025-07-15 16:51:49 +00:00
feat(defaults): shelltemp=false #33012
Co-authored-by: zeertzjq <zeertzjq@outlook.com> Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
This commit is contained in:
@ -81,6 +81,7 @@ OPTIONS
|
||||
• 'chistory' and 'lhistory' set size of the |quickfix-stack|.
|
||||
• 'diffopt' `inline:` configures diff highlighting for changes within a line.
|
||||
• 'pummaxwidth' sets maximum width for the completion popup menu.
|
||||
• 'shelltemp' defaults to "false".
|
||||
|
||||
PLUGINS
|
||||
|
||||
|
@ -5411,7 +5411,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
< Also see 'completeslash'.
|
||||
|
||||
*'shelltemp'* *'stmp'* *'noshelltemp'* *'nostmp'*
|
||||
'shelltemp' 'stmp' boolean (default on)
|
||||
'shelltemp' 'stmp' boolean (default off)
|
||||
global
|
||||
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.
|
||||
|
2
runtime/lua/vim/_meta/options.lua
generated
2
runtime/lua/vim/_meta/options.lua
generated
@ -5716,7 +5716,7 @@ vim.go.ssl = vim.go.shellslash
|
||||
--- `system()` does not respect this option, it always uses pipes.
|
||||
---
|
||||
--- @type boolean
|
||||
vim.o.shelltemp = true
|
||||
vim.o.shelltemp = false
|
||||
vim.o.stmp = vim.o.shelltemp
|
||||
vim.go.shelltemp = vim.o.shelltemp
|
||||
vim.go.stmp = vim.go.shelltemp
|
||||
|
@ -1146,7 +1146,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
|
||||
}
|
||||
|
||||
// Create the shell command in allocated memory.
|
||||
char *cmd_buf = make_filter_cmd(cmd, itmp, otmp);
|
||||
char *cmd_buf = make_filter_cmd(cmd, itmp, otmp, do_in);
|
||||
ui_cursor_goto(Rows - 1, 0);
|
||||
|
||||
if (do_out) {
|
||||
@ -1344,8 +1344,9 @@ static char *find_pipe(const char *cmd)
|
||||
/// @param cmd Command to execute.
|
||||
/// @param itmp NULL or the input file.
|
||||
/// @param otmp NULL or the output file.
|
||||
/// @param do_in true if stdin is needed.
|
||||
/// @returns an allocated string with the shell command.
|
||||
char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
|
||||
char *make_filter_cmd(char *cmd, char *itmp, char *otmp, bool do_in)
|
||||
{
|
||||
bool is_fish_shell =
|
||||
#if defined(UNIX)
|
||||
@ -1367,6 +1368,11 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
|
||||
len += is_pwsh ? strlen(itmp) + sizeof("& { Get-Content " " | & " " }") - 1 + 6 // +6: #20530
|
||||
: strlen(itmp) + sizeof(" { " " < " " } ") - 1;
|
||||
}
|
||||
|
||||
if (do_in && is_pwsh) {
|
||||
len += sizeof(" $input | ");
|
||||
}
|
||||
|
||||
if (otmp != NULL) {
|
||||
len += strlen(otmp) + strlen(p_srr) + 2; // two extra spaces (" "),
|
||||
}
|
||||
@ -1380,8 +1386,11 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
|
||||
xstrlcat(buf, " | & ", len - 1); // FIXME: add `&` ourself or leave to user?
|
||||
xstrlcat(buf, cmd, len - 1);
|
||||
xstrlcat(buf, " }", len - 1);
|
||||
} else if (do_in) {
|
||||
xstrlcpy(buf, " $input | ", len - 1);
|
||||
xstrlcat(buf, cmd, len);
|
||||
} else {
|
||||
xstrlcpy(buf, cmd, len - 1);
|
||||
xstrlcpy(buf, cmd, len);
|
||||
}
|
||||
} else {
|
||||
#if defined(UNIX)
|
||||
|
@ -7621,7 +7621,7 @@ local options = {
|
||||
},
|
||||
{
|
||||
abbreviation = 'stmp',
|
||||
defaults = true,
|
||||
defaults = false,
|
||||
desc = [=[
|
||||
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.
|
||||
|
@ -778,7 +778,7 @@ char *get_cmd_output(char *cmd, char *infile, int flags, size_t *ret_len)
|
||||
}
|
||||
|
||||
// Add the redirection stuff
|
||||
char *command = make_filter_cmd(cmd, infile, tempname);
|
||||
char *command = make_filter_cmd(cmd, infile, tempname, false);
|
||||
|
||||
// Call the shell to execute the command (errors are ignored).
|
||||
// Don't check timestamps here.
|
||||
@ -1253,11 +1253,19 @@ static size_t write_output(char *output, size_t remaining, bool eof)
|
||||
char *start = output;
|
||||
size_t off = 0;
|
||||
while (off < remaining) {
|
||||
if (output[off] == NL) {
|
||||
// CRLF
|
||||
if (output[off] == CAR && output[off + 1] == NL) {
|
||||
output[off] = NUL;
|
||||
ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
|
||||
size_t skip = off + 2;
|
||||
output += skip;
|
||||
remaining -= skip;
|
||||
off = 0;
|
||||
continue;
|
||||
} else if (output[off] == CAR || output[off] == NL) {
|
||||
// Insert the line
|
||||
output[off] = NUL;
|
||||
ml_append(curwin->w_cursor.lnum++, output, (int)off + 1,
|
||||
false);
|
||||
ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
|
||||
size_t skip = off + 1;
|
||||
output += skip;
|
||||
remaining -= skip;
|
||||
@ -1276,7 +1284,7 @@ static size_t write_output(char *output, size_t remaining, bool eof)
|
||||
if (remaining) {
|
||||
// append unfinished line
|
||||
ml_append(curwin->w_cursor.lnum++, output, 0, false);
|
||||
// remember that the NL was missing
|
||||
// remember that the line ending was missing
|
||||
curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
|
||||
output += remaining;
|
||||
} else {
|
||||
|
@ -23,22 +23,47 @@ describe(':make', function()
|
||||
n.set_shell_powershell()
|
||||
end)
|
||||
|
||||
it('captures stderr & non zero exit code #14349', function()
|
||||
it('captures stderr & non zero exit code using "commands" #14349', function()
|
||||
api.nvim_set_option_value('makeprg', testprg('shell-test') .. ' foo', {})
|
||||
local out = eval('execute("make")')
|
||||
-- Error message is captured in the file and printed in the footer
|
||||
matches(
|
||||
'[\r\n]+.*[\r\n]+Unknown first argument%: foo[\r\n]+%(1 of 1%)%: Unknown first argument%: foo',
|
||||
out
|
||||
)
|
||||
matches('[\r\n]+.*[\r\n]+%(1 of 1%)%: Unknown first argument%: foo', out)
|
||||
end)
|
||||
|
||||
it('captures stderr & zero exit code #14349', function()
|
||||
it('captures stderr & zero exit code using "commands" #14349', function()
|
||||
api.nvim_set_option_value('makeprg', testprg('shell-test'), {})
|
||||
local out = eval('execute("make")')
|
||||
-- Ensure there are no "shell returned X" messages between
|
||||
-- command and last line (indicating zero exit)
|
||||
matches('LastExitCode%s+ready [$]%s+[(]', out)
|
||||
matches('[\n]+%(1 of 1%)%: ready [$]', out)
|
||||
end)
|
||||
|
||||
it('captures stderr & non zero exit code using "cmdlets"', function()
|
||||
api.nvim_set_option_value(
|
||||
'shellpipe',
|
||||
'2>&1 | Tee-Object -FilePath %s; exit $LastExitCode',
|
||||
{}
|
||||
)
|
||||
api.nvim_set_option_value('makeprg', testprg('shell-test') .. ' foo', {})
|
||||
local out = eval('execute("make")')
|
||||
-- Error message is captured in the file and printed in the footer
|
||||
matches(
|
||||
'[\r\n]+.*[\r\n]+.*Unknown first argument%: foo%^%[%[0m[\r\n]+shell returned 3[\r\n]+%(1 of 1%)%: Unknown first argument%: foo',
|
||||
out
|
||||
)
|
||||
end)
|
||||
|
||||
it('captures stderr & zero exit code using "cmdlets"', function()
|
||||
api.nvim_set_option_value(
|
||||
'shellpipe',
|
||||
'2>&1 | Tee-Object -FilePath %s; exit $LastExitCode',
|
||||
{}
|
||||
)
|
||||
api.nvim_set_option_value('makeprg', testprg('shell-test'), {})
|
||||
local out = eval('execute("make")')
|
||||
-- Ensure there are no "shell returned X" messages between
|
||||
-- command and last line (indicating zero exit)
|
||||
matches('.*ready [$]%s+%^%[%[0m', out)
|
||||
matches('\n.*%: ready [$]', out)
|
||||
end)
|
||||
end)
|
||||
|
@ -35,6 +35,11 @@ local function prepare_gz_file(name, text)
|
||||
eq(nil, vim.uv.fs_stat(name))
|
||||
end
|
||||
|
||||
local function prepare_file(name, text)
|
||||
os.remove(name)
|
||||
write_file(name, text)
|
||||
end
|
||||
|
||||
describe('file reading, writing and bufnew and filter autocommands', function()
|
||||
local text1 = dedent([[
|
||||
start of testfile
|
||||
@ -63,23 +68,27 @@ describe('file reading, writing and bufnew and filter autocommands', function()
|
||||
end)
|
||||
teardown(function()
|
||||
os.remove('Xtestfile.gz')
|
||||
os.remove('Xtestfile')
|
||||
os.remove('XtestfileByFileReadPost')
|
||||
os.remove('Xtest.c')
|
||||
os.remove('test.out')
|
||||
end)
|
||||
|
||||
it('FileReadPost', function()
|
||||
feed_command('set bin')
|
||||
prepare_file('Xtestfile', text1)
|
||||
os.remove('XtestfileByFileReadPost')
|
||||
--execute('au FileChangedShell * echo "caught FileChangedShell"')
|
||||
feed_command("au FileReadPost Xtestfile '[,']w XtestfileByFileReadPost")
|
||||
-- Read the testfile.
|
||||
feed_command('$r Xtestfile')
|
||||
expect('\n' .. text1)
|
||||
eq(text1, read_file('XtestfileByFileReadPost'))
|
||||
end)
|
||||
|
||||
if not has_gzip() then
|
||||
pending('skipped (missing `gzip` utility)', function() end)
|
||||
else
|
||||
it('FileReadPost (using gzip)', function()
|
||||
prepare_gz_file('Xtestfile', text1)
|
||||
--execute('au FileChangedShell * echo "caught FileChangedShell"')
|
||||
feed_command('set bin')
|
||||
feed_command("au FileReadPost *.gz '[,']!gzip -d")
|
||||
-- Read and decompress the testfile.
|
||||
feed_command('$r Xtestfile.gz')
|
||||
expect('\n' .. text1)
|
||||
end)
|
||||
|
||||
it('BufReadPre, BufReadPost (using gzip)', function()
|
||||
prepare_gz_file('Xtestfile', text1)
|
||||
local gzip_data = read_file('Xtestfile.gz')
|
||||
@ -112,18 +121,18 @@ describe('file reading, writing and bufnew and filter autocommands', function()
|
||||
-- Discard all prompts and messages.
|
||||
feed('<C-L>')
|
||||
expect([[
|
||||
|
||||
start of testfiLe
|
||||
Line 2 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 4 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 6 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 8 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 10 Abcdefghijklmnopqrstuvwxyz
|
||||
end of testfiLe]])
|
||||
|
||||
start of testfiLe
|
||||
Line 2 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 4 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 6 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 8 Abcdefghijklmnopqrstuvwxyz
|
||||
Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Line 10 Abcdefghijklmnopqrstuvwxyz
|
||||
end of testfiLe]])
|
||||
end)
|
||||
end
|
||||
|
||||
|
@ -642,7 +642,7 @@ function M.source(code)
|
||||
end
|
||||
|
||||
function M.has_powershell()
|
||||
return M.eval('executable("' .. (is_os('win') and 'powershell' or 'pwsh') .. '")') == 1
|
||||
return M.eval('executable("pwsh")') == 1
|
||||
end
|
||||
|
||||
--- Sets Nvim shell to powershell.
|
||||
@ -655,7 +655,7 @@ function M.set_shell_powershell(fake)
|
||||
if not fake then
|
||||
assert(found)
|
||||
end
|
||||
local shell = found and (is_os('win') and 'powershell' or 'pwsh') or M.testprg('pwsh-test')
|
||||
local shell = found and 'pwsh' or M.testprg('pwsh-test')
|
||||
local cmd = 'Remove-Item -Force '
|
||||
.. table.concat(
|
||||
is_os('win') and { 'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort', 'alias:tee' }
|
||||
@ -671,7 +671,7 @@ function M.set_shell_powershell(fake)
|
||||
let &shellcmdflag .= '$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';'
|
||||
let &shellcmdflag .= ']] .. cmd .. [['
|
||||
let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode'
|
||||
let &shellpipe = '2>&1 | %%{ "$_" } | tee %s; exit $LastExitCode'
|
||||
let &shellpipe = '> %s 2>&1'
|
||||
]])
|
||||
return found
|
||||
end
|
||||
|
@ -558,9 +558,12 @@ end)
|
||||
describe('shell :!', function()
|
||||
before_each(clear)
|
||||
|
||||
it(':{range}! with powershell filter/redirect #16271 #19250', function()
|
||||
it(':{range}! with powershell using "commands" filter/redirect #16271 #19250', function()
|
||||
if not n.has_powershell() then
|
||||
return
|
||||
end
|
||||
local screen = Screen.new(500, 8)
|
||||
local found = n.set_shell_powershell(true)
|
||||
n.set_shell_powershell()
|
||||
insert([[
|
||||
3
|
||||
1
|
||||
@ -569,23 +572,44 @@ describe('shell :!', function()
|
||||
if is_os('win') then
|
||||
feed(':4verbose %!sort /R<cr>')
|
||||
screen:expect {
|
||||
any = [[Executing command: .?& { Get%-Content .* | & sort /R } 2>&1 | %%{ "$_" } | Out%-File .*; exit $LastExitCode"]],
|
||||
any = [[Executing command: " $input | sort /R".*]],
|
||||
}
|
||||
else
|
||||
feed(':4verbose %!sort -r<cr>')
|
||||
screen:expect {
|
||||
any = [[Executing command: .?& { Get%-Content .* | & sort %-r } 2>&1 | %%{ "$_" } | Out%-File .*; exit $LastExitCode"]],
|
||||
any = [[Executing command: " $input | sort %-r".*]],
|
||||
}
|
||||
end
|
||||
feed('<CR>')
|
||||
if found then
|
||||
-- Not using fake powershell, so we can test the result.
|
||||
expect([[
|
||||
4
|
||||
3
|
||||
2
|
||||
1]])
|
||||
expect([[
|
||||
4
|
||||
3
|
||||
2
|
||||
1]])
|
||||
end)
|
||||
|
||||
it(':{range}! with powershell using "cmdlets" filter/redirect #16271 #19250', function()
|
||||
if not n.has_powershell() then
|
||||
pending('powershell not found', function() end)
|
||||
return
|
||||
end
|
||||
local screen = Screen.new(500, 8)
|
||||
n.set_shell_powershell()
|
||||
insert([[
|
||||
3
|
||||
1
|
||||
4
|
||||
2]])
|
||||
feed(':4verbose %!Sort-Object -Descending<cr>')
|
||||
screen:expect {
|
||||
any = [[Executing command: " $input | Sort%-Object %-Descending".*]],
|
||||
}
|
||||
feed('<CR>')
|
||||
expect([[
|
||||
4
|
||||
3
|
||||
2
|
||||
1]])
|
||||
end)
|
||||
|
||||
it(':{range}! without redirecting to buffer', function()
|
||||
@ -596,20 +620,19 @@ describe('shell :!', function()
|
||||
4
|
||||
2]])
|
||||
feed(':4verbose %w !sort<cr>')
|
||||
if is_os('win') then
|
||||
screen:expect {
|
||||
any = [[Executing command: .?sort %< .*]],
|
||||
}
|
||||
else
|
||||
screen:expect {
|
||||
any = [[Executing command: .?%(sort%) %< .*]],
|
||||
}
|
||||
end
|
||||
screen:expect {
|
||||
any = [[Executing command: "sort".*]],
|
||||
}
|
||||
feed('<CR>')
|
||||
|
||||
if not n.has_powershell() then
|
||||
return
|
||||
end
|
||||
|
||||
n.set_shell_powershell(true)
|
||||
feed(':4verbose %w !sort<cr>')
|
||||
screen:expect {
|
||||
any = [[Executing command: .?& { Get%-Content .* | & sort }]],
|
||||
any = [[Executing command: " $input | sort".*]],
|
||||
}
|
||||
feed('<CR>')
|
||||
n.expect_exit(command, 'qall!')
|
||||
|
@ -19,6 +19,7 @@ if exists('s:did_load')
|
||||
set nohlsearch noincsearch
|
||||
set nrformats=bin,octal,hex
|
||||
set shortmess=filnxtToOS
|
||||
set shelltemp
|
||||
set sidescroll=0
|
||||
set tags=./tags,tags
|
||||
set undodir^=.
|
||||
|
Reference in New Issue
Block a user