refactor(git): convert blocking subprocess calls to async
This commit is contained in:
+66
-43
@@ -1,4 +1,5 @@
|
||||
local diff = require("git.diff")
|
||||
local git = require("git")
|
||||
local log = require("log")
|
||||
local repo = require("git.repo")
|
||||
local util = require("util")
|
||||
@@ -111,8 +112,8 @@ end
|
||||
---@param ref string
|
||||
local function show_blob(worktree, blob, path, ref)
|
||||
local buf = blob_buf(worktree, blob, path, ref)
|
||||
vim.cmd("normal! m'")
|
||||
vim.cmd("buffer " .. buf)
|
||||
vim.cmd.normal({ "m'", bang = true })
|
||||
vim.api.nvim_set_current_buf(buf)
|
||||
end
|
||||
|
||||
---@param ctx ow.Git.ShowContext
|
||||
@@ -127,53 +128,75 @@ local function show_diff(ctx, section)
|
||||
blob_buf(ctx.worktree, section.pre_blob, section.pre_path, parent)
|
||||
local right =
|
||||
blob_buf(ctx.worktree, section.post_blob, section.post_path, ctx.ref)
|
||||
vim.cmd("normal! m'")
|
||||
vim.cmd("buffer " .. left)
|
||||
vim.cmd("diffthis")
|
||||
vim.cmd("rightbelow vertical sbuffer " .. right)
|
||||
vim.cmd("diffthis")
|
||||
vim.cmd("wincmd p")
|
||||
vim.cmd.normal({ "m'", bang = true })
|
||||
local left_win = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_set_current_buf(left)
|
||||
vim.wo[left_win].diff = true
|
||||
local right_win =
|
||||
vim.api.nvim_open_win(right, true, { split = "right", win = left_win })
|
||||
vim.wo[right_win].diff = true
|
||||
vim.api.nvim_set_current_win(left_win)
|
||||
end
|
||||
|
||||
---@param worktree string
|
||||
---@param ref string
|
||||
function M.open_commit(worktree, ref)
|
||||
local sha = repo.rev_parse(worktree, ref, true) or ref
|
||||
local name = "git://" .. sha .. "/"
|
||||
-- Reuse a previously-opened buffer for the same commit; commit SHAs
|
||||
-- are immutable so the content is stable.
|
||||
local existing = vim.fn.bufnr(name)
|
||||
if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then
|
||||
vim.cmd("normal! m'")
|
||||
vim.cmd("buffer " .. existing)
|
||||
return
|
||||
end
|
||||
repo.rev_parse(worktree, ref, true, function(resolved)
|
||||
local sha = resolved or ref
|
||||
local name = "git://" .. sha .. "/"
|
||||
-- Reuse a previously-opened buffer for the same commit; commit SHAs
|
||||
-- are immutable so the content is stable.
|
||||
local existing = vim.fn.bufnr(name)
|
||||
if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then
|
||||
vim.api.nvim_open_win(existing, true, {
|
||||
split = vim.o.splitbelow and "below" or "above",
|
||||
})
|
||||
return
|
||||
end
|
||||
|
||||
local result = vim.system(
|
||||
{ "git", "show", ref },
|
||||
{ cwd = worktree, text = true }
|
||||
)
|
||||
:wait()
|
||||
if result.code ~= 0 then
|
||||
log.error("git show %s failed: %s", ref, result.stderr or "")
|
||||
return
|
||||
end
|
||||
local lines = util.split_lines(result.stdout or "")
|
||||
local parent = repo.rev_parse(worktree, ref .. "^", true)
|
||||
local buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.bo[buf].buftype = "nofile"
|
||||
vim.bo[buf].bufhidden = "hide"
|
||||
vim.bo[buf].swapfile = false
|
||||
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
||||
vim.bo[buf].modifiable = false
|
||||
vim.bo[buf].modified = false
|
||||
pcall(vim.api.nvim_buf_set_name, buf, name)
|
||||
vim.b[buf].git_worktree = worktree
|
||||
vim.b[buf].git_ref = sha
|
||||
vim.b[buf].git_parent_ref = parent
|
||||
vim.bo[buf].filetype = "git"
|
||||
vim.cmd("normal! m'")
|
||||
vim.cmd("buffer " .. buf)
|
||||
local buf, win = git.new_scratch({ name = name })
|
||||
vim.b[buf].git_worktree = worktree
|
||||
vim.b[buf].git_ref = sha
|
||||
|
||||
vim.system(
|
||||
{ "git", "show", ref },
|
||||
{ cwd = worktree, text = true },
|
||||
vim.schedule_wrap(function(result)
|
||||
if result.code ~= 0 then
|
||||
log.error(
|
||||
"git show %s failed: %s",
|
||||
ref,
|
||||
vim.trim(result.stderr or "")
|
||||
)
|
||||
-- Tear down the empty placeholder window+buffer so a
|
||||
-- retry runs a fresh fetch instead of hitting the
|
||||
-- cached-buffer branch and reopening an empty pane.
|
||||
if vim.api.nvim_win_is_valid(win) then
|
||||
pcall(vim.api.nvim_win_close, win, true)
|
||||
end
|
||||
if vim.api.nvim_buf_is_valid(buf) then
|
||||
pcall(vim.api.nvim_buf_delete, buf, { force = true })
|
||||
end
|
||||
return
|
||||
end
|
||||
if not vim.api.nvim_buf_is_valid(buf) then
|
||||
return
|
||||
end
|
||||
local lines = util.split_lines(result.stdout or "")
|
||||
repo.rev_parse(worktree, ref .. "^", true, function(parent)
|
||||
if not vim.api.nvim_buf_is_valid(buf) then
|
||||
return
|
||||
end
|
||||
vim.b[buf].git_parent_ref = parent
|
||||
vim.bo[buf].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
||||
vim.bo[buf].modifiable = false
|
||||
vim.bo[buf].modified = false
|
||||
vim.bo[buf].filetype = "git"
|
||||
end)
|
||||
end)
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
---@return boolean dispatched true if the cursor was on an actionable line
|
||||
|
||||
Reference in New Issue
Block a user