refactor(git): unify around the Repo abstraction
This commit is contained in:
+122
-23
@@ -23,8 +23,10 @@ local function git_cmds()
|
||||
if cached_cmds then
|
||||
return cached_cmds
|
||||
end
|
||||
local result = vim
|
||||
.system({ "git", "--list-cmds=main,others,alias" }, { text = true })
|
||||
local result = vim.system(
|
||||
{ "git", "--list-cmds=main,others,alias" },
|
||||
{ text = true }
|
||||
)
|
||||
:wait()
|
||||
if result.code ~= 0 then
|
||||
util.error("git --list-cmds failed: %s", vim.trim(result.stderr or ""))
|
||||
@@ -70,30 +72,31 @@ local function place_split(name)
|
||||
return buf
|
||||
end
|
||||
|
||||
---@param worktree string
|
||||
---@param r ow.Git.Repo
|
||||
---@param args string[]
|
||||
---@param conf ow.Git.SplitHandler
|
||||
local function run_in_split(worktree, args, conf)
|
||||
local function run_in_split(r, args, conf)
|
||||
local cmd = { "git" }
|
||||
vim.list_extend(cmd, args)
|
||||
util.exec(cmd, {
|
||||
cwd = worktree,
|
||||
cwd = r.worktree,
|
||||
on_done = function(stdout)
|
||||
if not stdout then
|
||||
return
|
||||
end
|
||||
local name = "[git " .. table.concat(args, " ") .. "]"
|
||||
local buf = place_split(name)
|
||||
vim.b[buf].git_worktree = worktree
|
||||
vim.b[buf].git_sha = nil
|
||||
vim.b[buf].git_parent_sha = nil
|
||||
repo.attach(buf, r)
|
||||
object.attach_dispatch(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 = repo.rev_parse(worktree, user_rev, true)
|
||||
local sha = r:rev_parse(user_rev, true)
|
||||
if sha then
|
||||
vim.b[buf].git_sha = sha
|
||||
vim.b[buf].git_parent_sha =
|
||||
repo.rev_parse(worktree, user_rev .. "^", true)
|
||||
state.sha = sha
|
||||
state.parent_sha = r:rev_parse(user_rev .. "^", true)
|
||||
end
|
||||
end
|
||||
vim.bo[buf].filetype = conf.ft
|
||||
@@ -111,14 +114,14 @@ local function run_in_split(worktree, args, conf)
|
||||
})
|
||||
end
|
||||
|
||||
---@param worktree string
|
||||
---@param r ow.Git.Repo
|
||||
---@param args string[]
|
||||
local function run_to_messages(worktree, args)
|
||||
local function run_to_messages(r, args)
|
||||
local cmd = { "git" }
|
||||
vim.list_extend(cmd, args)
|
||||
vim.system(
|
||||
cmd,
|
||||
{ cwd = worktree, text = true },
|
||||
{ cwd = r.worktree, text = true },
|
||||
vim.schedule_wrap(function(obj)
|
||||
local out = vim.trim(obj.stdout or "")
|
||||
local err = vim.trim(obj.stderr or "")
|
||||
@@ -175,8 +178,8 @@ end
|
||||
|
||||
---@param args string[]
|
||||
function M.run(args)
|
||||
local _, worktree = repo.current_repo()
|
||||
if not worktree then
|
||||
local r = repo.find()
|
||||
if not r then
|
||||
util.warning("not in a git repository")
|
||||
return
|
||||
end
|
||||
@@ -190,10 +193,10 @@ function M.run(args)
|
||||
if sub == "show" then
|
||||
local arg = first_positional(args, 2)
|
||||
if arg and arg:find(":", 1, true) then
|
||||
object.open_object(worktree, arg)
|
||||
object.open_object(r, arg)
|
||||
return
|
||||
end
|
||||
run_in_split(worktree, args, { ft = "git", needs_rev = true })
|
||||
run_in_split(r, args, { ft = "git", needs_rev = true })
|
||||
return
|
||||
end
|
||||
|
||||
@@ -201,22 +204,118 @@ function M.run(args)
|
||||
if vim.list_contains(args, "-p") then
|
||||
local rev = first_positional(args, 2)
|
||||
if rev then
|
||||
object.open_object(worktree, rev)
|
||||
object.open_object(r, rev)
|
||||
return
|
||||
end
|
||||
end
|
||||
run_in_split(worktree, args, { ft = "git", needs_rev = true })
|
||||
run_in_split(r, args, { ft = "git", needs_rev = true })
|
||||
return
|
||||
end
|
||||
|
||||
local conf = sub and SPLIT_HANDLERS[sub]
|
||||
if conf then
|
||||
run_in_split(worktree, args, conf)
|
||||
run_in_split(r, args, conf)
|
||||
else
|
||||
run_to_messages(worktree, args)
|
||||
run_to_messages(r, args)
|
||||
end
|
||||
end
|
||||
|
||||
---@param arg_lead string
|
||||
---@return string[]
|
||||
function M.complete_rev(arg_lead)
|
||||
local r = repo.find()
|
||||
if not r then
|
||||
return {}
|
||||
end
|
||||
|
||||
local stage, stage_path_lead = arg_lead:match("^:([0-3]):(.*)$")
|
||||
if stage then
|
||||
local out = util.exec(
|
||||
{ "git", "ls-files", "--stage" },
|
||||
{ cwd = r.worktree, silent = true }
|
||||
)
|
||||
if not out then
|
||||
return {}
|
||||
end
|
||||
local matches = {}
|
||||
for _, line in ipairs(util.split_lines(out)) do
|
||||
local row_stage, row_path = line:match("^%S+ %S+ (%d)\t(.*)$")
|
||||
if
|
||||
row_stage == stage
|
||||
and row_path
|
||||
and row_path:sub(1, #stage_path_lead) == stage_path_lead
|
||||
then
|
||||
table.insert(matches, ":" .. stage .. ":" .. row_path)
|
||||
end
|
||||
end
|
||||
return matches
|
||||
end
|
||||
|
||||
local colon = arg_lead:find(":", 1, true)
|
||||
if not colon then
|
||||
local matches = {}
|
||||
for _, ref in ipairs(r:list_refs()) do
|
||||
if ref:sub(1, #arg_lead) == arg_lead then
|
||||
table.insert(matches, ref)
|
||||
end
|
||||
end
|
||||
return matches
|
||||
end
|
||||
|
||||
local rev = arg_lead:sub(1, colon - 1)
|
||||
local path_lead = arg_lead:sub(colon + 1)
|
||||
local dir, name_lead = path_lead:match("^(.*/)([^/]*)$")
|
||||
dir = dir or ""
|
||||
name_lead = name_lead or path_lead
|
||||
|
||||
if rev ~= "" then
|
||||
local cmd = { "git", "ls-tree", rev }
|
||||
if dir ~= "" then
|
||||
table.insert(cmd, dir)
|
||||
end
|
||||
local out = util.exec(cmd, { cwd = r.worktree, silent = true })
|
||||
if not out then
|
||||
return {}
|
||||
end
|
||||
local matches = {}
|
||||
for _, line in ipairs(util.split_lines(out)) do
|
||||
local typ, full_path = line:match("^%S+ (%S+) %S+\t(.*)$")
|
||||
if typ and full_path then
|
||||
local basename = dir == "" and full_path
|
||||
or full_path:sub(#dir + 1)
|
||||
if typ == "tree" then
|
||||
basename = basename .. "/"
|
||||
end
|
||||
if basename:sub(1, #name_lead) == name_lead then
|
||||
table.insert(matches, rev .. ":" .. dir .. basename)
|
||||
end
|
||||
end
|
||||
end
|
||||
return matches
|
||||
end
|
||||
|
||||
local cmd = { "git", "ls-files" }
|
||||
if dir ~= "" then
|
||||
table.insert(cmd, dir)
|
||||
end
|
||||
local out = util.exec(cmd, { cwd = r.worktree, silent = true })
|
||||
if not out then
|
||||
return {}
|
||||
end
|
||||
local matches = {}
|
||||
local seen = {}
|
||||
for _, full_path in ipairs(util.split_lines(out)) do
|
||||
local rel = dir == "" and full_path or full_path:sub(#dir + 1)
|
||||
local slash = rel:find("/", 1, true)
|
||||
local segment = slash and rel:sub(1, slash) or rel
|
||||
if not seen[segment] and segment:sub(1, #name_lead) == name_lead then
|
||||
seen[segment] = true
|
||||
table.insert(matches, ":" .. dir .. segment)
|
||||
end
|
||||
end
|
||||
return matches
|
||||
end
|
||||
|
||||
---@param arg_lead string
|
||||
---@param cmd_line string
|
||||
---@return string[]
|
||||
|
||||
Reference in New Issue
Block a user