refactor(git): drive :G dispatch from buffer content
This commit is contained in:
+63
-69
@@ -182,8 +182,7 @@ local function populate(buf, r, rev, state, rev_sha)
|
||||
if rev.path == nil then
|
||||
local commit_sha = r:rev_parse(rev_str .. "^{commit}", true)
|
||||
if commit_sha then
|
||||
local patch = util.exec({
|
||||
"git",
|
||||
local patch = util.git({
|
||||
"diff-tree",
|
||||
"-p",
|
||||
"-m",
|
||||
@@ -195,7 +194,6 @@ local function populate(buf, r, rev, state, rev_sha)
|
||||
if patch then
|
||||
stdout = (stdout:gsub("\n*$", "\n\n")) .. patch
|
||||
end
|
||||
state.parent_sha = r:rev_parse(commit_sha .. "^", true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -220,8 +218,12 @@ function M.read_uri(buf)
|
||||
repo.bind(buf, r)
|
||||
local state = r:state(buf) --[[@as -nil]]
|
||||
|
||||
vim.bo[buf].swapfile = false
|
||||
vim.bo[buf].bufhidden = "delete"
|
||||
local writable = rev.stage == 0 and rev.path ~= nil
|
||||
util.setup_scratch(buf, {
|
||||
bufhidden = "delete",
|
||||
buftype = writable and "acwrite" or "nofile",
|
||||
modifiable = writable,
|
||||
})
|
||||
|
||||
local rev_sha = r:rev_parse(rev:format(), true)
|
||||
if not rev_sha then
|
||||
@@ -234,15 +236,9 @@ function M.read_uri(buf)
|
||||
|
||||
state.immutable = is_immutable_rev(rev)
|
||||
|
||||
if rev.stage == 0 and rev.path then
|
||||
vim.bo[buf].buftype = "acwrite"
|
||||
if not state.index_writer then
|
||||
attach_index_writer(buf, r, rev.path)
|
||||
state.index_writer = true
|
||||
end
|
||||
else
|
||||
vim.bo[buf].buftype = "nofile"
|
||||
vim.bo[buf].modifiable = false
|
||||
if writable and not state.index_writer then
|
||||
attach_index_writer(buf, r, rev.path --[[@as string]])
|
||||
state.index_writer = true
|
||||
end
|
||||
|
||||
if rev.path then
|
||||
@@ -283,35 +279,47 @@ local function refresh(buf, r)
|
||||
end
|
||||
end
|
||||
|
||||
---@param r ow.Git.Repo
|
||||
---@param ref string? -- nil = worktree, ":" = index, else commit/sha
|
||||
---@param buf integer
|
||||
---@param path string
|
||||
local function set_ft_from_path(buf, path)
|
||||
local ft = vim.filetype.match({ filename = path, buf = buf })
|
||||
if ft then
|
||||
vim.bo[buf].filetype = ft
|
||||
end
|
||||
end
|
||||
|
||||
---@param r ow.Git.Repo
|
||||
---@param blob string?
|
||||
---@param path string
|
||||
---@param blob string? -- diff section blob hash; if zero, side has no content
|
||||
---@return integer?
|
||||
local function side_buf(r, ref, path, blob)
|
||||
if blob and is_zero(blob) then
|
||||
local function side_buf(r, blob, path)
|
||||
if not blob or is_zero(blob) then
|
||||
return nil
|
||||
end
|
||||
if ref == nil then
|
||||
local p = vim.fs.joinpath(r.worktree, path)
|
||||
if not vim.uv.fs_stat(p) then
|
||||
return nil
|
||||
end
|
||||
local full, status = r:resolve_sha(blob)
|
||||
if status == "ambiguous" then
|
||||
util.error("ambiguous blob abbreviation: %s", blob)
|
||||
return nil
|
||||
end
|
||||
if full then
|
||||
local buf = M.buf_for(r, Revision.new({ base = full }))
|
||||
set_ft_from_path(buf, path)
|
||||
return buf
|
||||
end
|
||||
local p = vim.fs.joinpath(r.worktree, path)
|
||||
if vim.uv.fs_stat(p) then
|
||||
local buf = vim.fn.bufadd(p)
|
||||
vim.fn.bufload(buf)
|
||||
return buf
|
||||
end
|
||||
local rev = ref == ":" and Revision.new({ stage = 0, path = path })
|
||||
or Revision.new({ base = ref, path = path })
|
||||
return M.buf_for(r, rev)
|
||||
return nil
|
||||
end
|
||||
|
||||
---@param r ow.Git.Repo
|
||||
---@param ref string?
|
||||
---@param path string
|
||||
---@param blob string?
|
||||
local function load_side(r, ref, path, blob)
|
||||
local buf = side_buf(r, ref, path, blob)
|
||||
---@param path string
|
||||
local function load_side(r, blob, path)
|
||||
local buf = side_buf(r, blob, path)
|
||||
if not buf then
|
||||
util.error("no content for %s", path)
|
||||
return
|
||||
@@ -321,16 +329,14 @@ local function load_side(r, ref, path, blob)
|
||||
end
|
||||
|
||||
---@param r ow.Git.Repo
|
||||
---@param left_ref string?
|
||||
---@param right_ref string?
|
||||
---@param section ow.Git.DiffSection
|
||||
local function open_section(r, left_ref, right_ref, section)
|
||||
local function open_section(r, section)
|
||||
if not section.blob_a or not section.blob_b then
|
||||
util.error("no index line, cannot determine blob SHAs")
|
||||
return
|
||||
end
|
||||
local left = side_buf(r, left_ref, section.path_a, section.blob_a)
|
||||
local right = side_buf(r, right_ref, section.path_b, section.blob_b)
|
||||
local left = side_buf(r, section.blob_a, section.path_a)
|
||||
local right = side_buf(r, section.blob_b, section.path_b)
|
||||
if left and right then
|
||||
require("git.diff").open(left, right, true)
|
||||
return
|
||||
@@ -377,36 +383,24 @@ function M.open_under_cursor()
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
local r = s.repo
|
||||
|
||||
if s.sha and not s.left_ref then
|
||||
local sha = line:match("^commit (%x+)$")
|
||||
or line:match("^parent (%x+)$")
|
||||
or line:match("^tree (%x+)$")
|
||||
or line:match("^object (%x+)$")
|
||||
if sha then
|
||||
M.open(r, sha, { split = false })
|
||||
return true
|
||||
end
|
||||
|
||||
local entry_type, entry_sha, entry_name =
|
||||
line:match("^%d+ (%w+) (%x+)\t(.+)$")
|
||||
if entry_sha then
|
||||
local nav_rev = entry_type == "blob"
|
||||
and Revision.new({ base = s.sha, path = entry_name }):format()
|
||||
or entry_sha
|
||||
M.open(r, nav_rev, { split = false })
|
||||
return true
|
||||
end
|
||||
local sha = line:match("^commit (%x+)$")
|
||||
or line:match("^parent (%x+)$")
|
||||
or line:match("^tree (%x+)$")
|
||||
or line:match("^object (%x+)$")
|
||||
if sha then
|
||||
M.open(r, sha, { split = false })
|
||||
return true
|
||||
end
|
||||
|
||||
local left_ref, right_ref
|
||||
if s.left_ref then
|
||||
left_ref = s.left_ref
|
||||
right_ref = s.right_ref
|
||||
elseif s.sha then
|
||||
left_ref = s.parent_sha or "0"
|
||||
right_ref = s.sha
|
||||
else
|
||||
return false
|
||||
local entry_type, entry_sha, entry_name =
|
||||
line:match("^%d+ (%w+) (%x+)\t(.+)$")
|
||||
if entry_sha then
|
||||
if entry_type == "blob" then
|
||||
load_side(r, entry_sha, entry_name --[[@as string]])
|
||||
else
|
||||
M.open(r, entry_sha, { split = false })
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local section = diff_section()
|
||||
@@ -415,23 +409,23 @@ function M.open_under_cursor()
|
||||
end
|
||||
|
||||
if line:match("^diff %-%-git ") then
|
||||
open_section(r, left_ref, right_ref, section)
|
||||
open_section(r, section)
|
||||
return true
|
||||
end
|
||||
if line:match("^%-%-%- ") then
|
||||
load_side(r, left_ref, section.path_a, section.blob_a)
|
||||
load_side(r, section.blob_a, section.path_a)
|
||||
return true
|
||||
end
|
||||
if line:match("^%+%+%+ ") then
|
||||
load_side(r, right_ref, section.path_b, section.blob_b)
|
||||
load_side(r, section.blob_b, section.path_b)
|
||||
return true
|
||||
end
|
||||
local prefix = line:sub(1, 1)
|
||||
if prefix == "+" then
|
||||
load_side(r, right_ref, section.path_b, section.blob_b)
|
||||
load_side(r, section.blob_b, section.path_b)
|
||||
return true
|
||||
elseif prefix == "-" then
|
||||
load_side(r, left_ref, section.path_a, section.blob_a)
|
||||
load_side(r, section.blob_a, section.path_a)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user