refactor(git): drive :G dispatch from buffer content
This commit is contained in:
+9
-113
@@ -7,90 +7,13 @@ local M = {}
|
||||
|
||||
---@class ow.Git.Cmd.SplitHandler
|
||||
---@field ft string
|
||||
---@field needs_rev boolean?
|
||||
---@field on_state? fun(state: ow.Git.Repo.BufState, r: ow.Git.Repo, args: string[])
|
||||
|
||||
---@param r ow.Git.Repo
|
||||
---@param args string[] -- diff args including leading "diff"
|
||||
---@return string left_ref
|
||||
---@return string? right_ref -- nil means worktree
|
||||
local function compute_diff_refs(r, args)
|
||||
local cached = false
|
||||
local positional = {} ---@type string[]
|
||||
local saw_separator = false
|
||||
for i = 2, #args do
|
||||
local a = args[i]
|
||||
if saw_separator then
|
||||
break
|
||||
elseif a == "--" then
|
||||
saw_separator = true
|
||||
elseif a == "--cached" or a == "--staged" then
|
||||
cached = true
|
||||
elseif a:sub(1, 1) ~= "-" then
|
||||
table.insert(positional, a)
|
||||
end
|
||||
end
|
||||
|
||||
local function defaults()
|
||||
if cached then
|
||||
return "HEAD", ":"
|
||||
end
|
||||
return ":", nil
|
||||
end
|
||||
|
||||
if #positional == 0 then
|
||||
return defaults()
|
||||
end
|
||||
|
||||
local first = positional[1] --[[@as string]]
|
||||
if #positional == 1 then
|
||||
local lhs, rhs = first:match("^(.-)%.%.%.(.+)$")
|
||||
if lhs then
|
||||
return (lhs ~= "" and lhs or "HEAD"), rhs
|
||||
end
|
||||
lhs, rhs = first:match("^(.-)%.%.(.+)$")
|
||||
if lhs then
|
||||
return (lhs ~= "" and lhs or "HEAD"),
|
||||
(rhs ~= "" and rhs or "HEAD")
|
||||
end
|
||||
if r:rev_parse(first, true) then
|
||||
if cached then
|
||||
return first, ":"
|
||||
end
|
||||
return first, nil
|
||||
end
|
||||
return defaults()
|
||||
end
|
||||
|
||||
local second = positional[2] --[[@as string]]
|
||||
local first_ok = r:rev_parse(first, true) ~= nil
|
||||
if first_ok and r:rev_parse(second, true) then
|
||||
return first, second
|
||||
end
|
||||
if first_ok then
|
||||
if cached then
|
||||
return first, ":"
|
||||
end
|
||||
return first, nil
|
||||
end
|
||||
return defaults()
|
||||
end
|
||||
|
||||
---@type table<string, ow.Git.Cmd.SplitHandler>
|
||||
local SPLIT_HANDLERS = {
|
||||
log = { ft = "git" },
|
||||
diff = {
|
||||
ft = "gitdiff",
|
||||
on_state = function(state, r, args)
|
||||
local left, right = compute_diff_refs(r, args)
|
||||
state.left_ref = left
|
||||
state.right_ref = right
|
||||
end,
|
||||
},
|
||||
diff = { ft = "git" },
|
||||
}
|
||||
|
||||
M._compute_diff_refs = compute_diff_refs
|
||||
|
||||
---@type string[]?
|
||||
local cached_cmds
|
||||
|
||||
@@ -207,28 +130,16 @@ function M.parse_args(line)
|
||||
return args
|
||||
end
|
||||
|
||||
---@param args string[]
|
||||
---@param start integer
|
||||
---@return string?
|
||||
local function first_positional(args, start)
|
||||
for i = start, #args do
|
||||
local a = args[i]
|
||||
if a:sub(1, 1) ~= "-" then
|
||||
return a
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@return integer buf
|
||||
local function place_split(name)
|
||||
local buf = vim.fn.bufnr("\\V" .. name)
|
||||
if buf == -1 then
|
||||
buf = util.new_scratch({ name = name, bufhidden = "hide" })
|
||||
return buf
|
||||
end
|
||||
-- bufadd resolves the name the same way nvim_buf_set_name does
|
||||
-- (cwd-prefixing for non-absolute names), so calling it twice with
|
||||
-- the same name returns the same buffer.
|
||||
local buf = vim.fn.bufadd(name)
|
||||
if not vim.api.nvim_buf_is_loaded(buf) then
|
||||
vim.fn.bufload(buf)
|
||||
util.setup_scratch(buf, { bufhidden = "hide" })
|
||||
end
|
||||
local win = vim.fn.bufwinid(buf)
|
||||
if win ~= -1 then
|
||||
@@ -278,9 +189,7 @@ end
|
||||
---@param args string[]
|
||||
---@param conf ow.Git.Cmd.SplitHandler
|
||||
local function run_in_split(r, args, conf)
|
||||
local cmd = { "git" }
|
||||
vim.list_extend(cmd, args)
|
||||
util.exec(cmd, {
|
||||
util.git(args, {
|
||||
cwd = r.worktree,
|
||||
on_done = function(stdout)
|
||||
if not stdout then
|
||||
@@ -291,19 +200,6 @@ local function run_in_split(r, args, conf)
|
||||
object.attach_dispatch(buf)
|
||||
attach_history_keys(buf)
|
||||
local state = r:state(buf) --[[@as -nil]]
|
||||
state.sha = nil
|
||||
state.parent_sha = nil
|
||||
if conf.needs_rev then
|
||||
local user_rev = first_positional(args, 2) or "HEAD"
|
||||
local sha = r:rev_parse(user_rev, true)
|
||||
if sha then
|
||||
state.sha = sha
|
||||
state.parent_sha = r:rev_parse(user_rev .. "^", true)
|
||||
end
|
||||
end
|
||||
if conf.on_state then
|
||||
conf.on_state(state, r, args)
|
||||
end
|
||||
vim.bo[buf].filetype = conf.ft
|
||||
-- Force a new undo block so each rerun is its own undo step.
|
||||
vim.bo[buf].undolevels = vim.bo[buf].undolevels
|
||||
@@ -386,7 +282,7 @@ function M.run(args)
|
||||
object.open(r, args[2])
|
||||
return
|
||||
end
|
||||
run_in_split(r, args, { ft = "git", needs_rev = true })
|
||||
run_in_split(r, args, { ft = "git" })
|
||||
return
|
||||
end
|
||||
|
||||
@@ -395,7 +291,7 @@ function M.run(args)
|
||||
object.open(r, args[3])
|
||||
return
|
||||
end
|
||||
run_in_split(r, args, { ft = "git", needs_rev = true })
|
||||
run_in_split(r, args, { ft = "git" })
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user