fix(git/cmd): parse :G args with shell-style quoting
This commit is contained in:
+95
-22
@@ -42,6 +42,95 @@ local function git_cmds()
|
||||
return cached_cmds
|
||||
end
|
||||
|
||||
---@param tok string
|
||||
---@return boolean
|
||||
local function is_expansion_target(tok)
|
||||
local first = tok:sub(1, 1)
|
||||
if first == "%" or first == "#" then
|
||||
return true
|
||||
end
|
||||
if tok:match("^<%w+>") then
|
||||
return true
|
||||
end
|
||||
if tok == "~" or tok:sub(1, 2) == "~/" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---@param line string
|
||||
---@param i integer
|
||||
---@param buf string[]
|
||||
---@param escapes string?
|
||||
---@return integer
|
||||
local function parse_quoted(line, i, buf, escapes)
|
||||
local quote = line:sub(i, i)
|
||||
local n = #line
|
||||
i = i + 1
|
||||
while i <= n do
|
||||
local c = line:sub(i, i)
|
||||
if c == quote then
|
||||
return i + 1
|
||||
elseif escapes and c == "\\" and i < n then
|
||||
local nxt = line:sub(i + 1, i + 1)
|
||||
if escapes:find(nxt, 1, true) then
|
||||
table.insert(buf, nxt)
|
||||
i = i + 2
|
||||
else
|
||||
table.insert(buf, c)
|
||||
i = i + 1
|
||||
end
|
||||
else
|
||||
table.insert(buf, c)
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
---@param line string
|
||||
---@return string[]
|
||||
function M.parse_args(line)
|
||||
local args = {}
|
||||
local i, n = 1, #line
|
||||
while i <= n do
|
||||
local c = line:sub(i, i)
|
||||
if c == " " or c == "\t" then
|
||||
i = i + 1
|
||||
else
|
||||
local buf = {}
|
||||
local quoted = false
|
||||
while i <= n do
|
||||
c = line:sub(i, i)
|
||||
if c == " " or c == "\t" then
|
||||
break
|
||||
elseif c == "\\" and i < n then
|
||||
table.insert(buf, line:sub(i + 1, i + 1))
|
||||
i = i + 2
|
||||
elseif c == '"' then
|
||||
quoted = true
|
||||
i = parse_quoted(line, i, buf, '"\\$`')
|
||||
elseif c == "'" then
|
||||
quoted = true
|
||||
i = parse_quoted(line, i, buf, nil)
|
||||
else
|
||||
table.insert(buf, c)
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
local tok = table.concat(buf)
|
||||
if not quoted and is_expansion_target(tok) then
|
||||
local expanded = vim.fn.expand(tok) --[[@as string]]
|
||||
if expanded ~= "" then
|
||||
tok = expanded
|
||||
end
|
||||
end
|
||||
table.insert(args, tok)
|
||||
end
|
||||
end
|
||||
return args
|
||||
end
|
||||
|
||||
---@param args string[]
|
||||
---@param start integer
|
||||
---@return string?
|
||||
@@ -139,18 +228,6 @@ local function run_to_messages(r, args)
|
||||
)
|
||||
end
|
||||
|
||||
---@param args string[]
|
||||
---@param flag string
|
||||
---@return boolean
|
||||
local function has_flag(args, flag)
|
||||
for _, a in ipairs(args) do
|
||||
if a == flag then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---@param args string[]
|
||||
---@return boolean
|
||||
local function has_message(args)
|
||||
@@ -177,14 +254,13 @@ function M.run(args)
|
||||
|
||||
local sub = args[1]
|
||||
if sub == "commit" and not has_message(args) then
|
||||
commit.commit({ amend = has_flag(args, "--amend") })
|
||||
commit.commit({ args = vim.list_slice(args, 2) })
|
||||
return
|
||||
end
|
||||
|
||||
if sub == "show" then
|
||||
local arg = first_positional(args, 2)
|
||||
if arg and arg:find(":", 1, true) then
|
||||
object.open(r, arg)
|
||||
if #args == 2 and args[2]:find(":", 1, true) then
|
||||
object.open(r, args[2])
|
||||
return
|
||||
end
|
||||
run_in_split(r, args, { ft = "git", needs_rev = true })
|
||||
@@ -192,12 +268,9 @@ function M.run(args)
|
||||
end
|
||||
|
||||
if sub == "cat-file" then
|
||||
if vim.list_contains(args, "-p") then
|
||||
local rev = first_positional(args, 2)
|
||||
if rev then
|
||||
object.open(r, rev)
|
||||
return
|
||||
end
|
||||
if #args == 3 and args[2] == "-p" then
|
||||
object.open(r, args[3])
|
||||
return
|
||||
end
|
||||
run_in_split(r, args, { ft = "git", needs_rev = true })
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user