fix(terminal): properly deal with args in vim.o.shell. Fixes #69

This commit is contained in:
Folke Lemaitre 2024-11-13 10:42:03 +01:00
parent f704f7479f
commit 2ccb70fd3a
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
2 changed files with 59 additions and 1 deletions

View file

@ -92,7 +92,7 @@ function M.open(cmd, opts)
cwd = opts.cwd,
env = opts.env,
}
vim.fn.termopen(cmd or { vim.o.shell }, vim.tbl_isempty(term_opts) and vim.empty_dict() or term_opts)
vim.fn.termopen(cmd or M.parse(vim.o.shell), vim.tbl_isempty(term_opts) and vim.empty_dict() or term_opts)
end)
if opts.interactive ~= false then
@ -133,4 +133,37 @@ function M.toggle(cmd, opts)
return terminals[id]
end
--- Parses a shell command into a table of arguments.
--- - spaces inside quotes (only double quotes are supported) are preserved
--- - backslash
---@param cmd string
function M.parse(cmd)
local args = {}
local in_quotes, escape_next, current = false, false, ""
local function add()
if #current > 0 then
table.insert(args, current)
current = ""
end
end
for i = 1, #cmd do
local char = cmd:sub(i, i)
if escape_next then
current = current .. ((char == '"' or char == "\\") and "" or "\\") .. char
escape_next = false
elseif char == "\\" and in_quotes then
escape_next = true
elseif char == '"' then
in_quotes = not in_quotes
elseif char:find("[ \t]") and not in_quotes then
add()
else
current = current .. char
end
end
add()
return args
end
return M

25
tests/terminal_spec.lua Normal file
View file

@ -0,0 +1,25 @@
---@module "luassert"
local terminal = require("snacks.terminal")
local tests = {
{ "bash", { "bash" } },
{ '"bash"', { "bash" } },
{
'"C:\\Program Files\\Git\\bin\\bash.exe" -c "echo hello"',
{ "C:\\Program Files\\Git\\bin\\bash.exe", "-c", "echo hello" },
},
{ "pwsh -NoLogo", { "pwsh", "-NoLogo" } },
{ 'echo "foo\tbar"', { "echo", "foo\tbar" } },
{ "echo\tfoo", { "echo", "foo" } },
{ 'this "is \\"a test"', { "this", 'is "a test' } },
}
describe("terminal.parse", function()
for _, test in ipairs(tests) do
it("should parse " .. test[1], function()
local result = terminal.parse(test[1])
assert.are.same(test[2], result)
end)
end
end)