refactor(git): unify diff/object dispatch, codify naming, add :Gdiffsplit

This commit is contained in:
2026-04-29 09:47:51 +02:00
parent 44f9503960
commit 5c5da7a854
10 changed files with 587 additions and 443 deletions
+57
View File
@@ -1,5 +1,62 @@
local M = {}
---@class ow.Git.ParsedRevspec
---@field stage 0|1|2|3? index stage when the revspec is `:<path>` / `:0:<path>` / `:N:<path>`; nil otherwise
---@field path string? path component when the revspec carries one; nil for bare object refs
---Classify a `git://<revspec>` revspec into its stage / path components.
---Recognised forms:
--- * `:<path>` and `:0:<path>` -> stage 0 (the resolved index entry)
--- * `:1:<path>` / `:2:<path>` / `:3:<path>` -> merge stages base / ours / theirs
--- * `<commit-ref>:<path>` -> stage = nil, path set
--- * bare object ref (no `:`) -> stage = nil, path = nil
---@param revspec string
---@return ow.Git.ParsedRevspec
function M.parse_revspec(revspec)
local stage, path = revspec:match("^:([0123]):(.+)$")
if stage then
return { stage = tonumber(stage), path = path }
end
path = revspec:match("^:([^:]+)$")
if path then
return { stage = 0, path = path }
end
path = (revspec:match("^[^:]+:(.+)$"))
return { stage = nil, path = path }
end
---@class ow.Git.NewScratchOpts
---@field name string?
---@field bufhidden ("hide"|"wipe")? defaults to "hide"
---@field split (false|"above"|"below"|"left"|"right")? defaults to splitbelow-aware horizontal. `false` places the buffer in the current window (drops a `'` mark first so the user can jump back).
---Create a fresh non-modifiable scratch buffer and place it. Default split
---direction is horizontal, honouring `splitbelow`. Caller flips
---`modifiable`, fills the buffer, and sets `filetype` once content lands.
---@param opts ow.Git.NewScratchOpts?
---@return integer buf
---@return integer win
function M.new_scratch(opts)
opts = opts or {}
local buf = vim.api.nvim_create_buf(false, true)
vim.bo[buf].buftype = "nofile"
vim.bo[buf].bufhidden = opts.bufhidden or "hide"
vim.bo[buf].swapfile = false
vim.bo[buf].modifiable = false
vim.bo[buf].modified = false
if opts.name then
pcall(vim.api.nvim_buf_set_name, buf, opts.name)
end
if opts.split == false then
vim.cmd.normal({ "m'", bang = true })
vim.api.nvim_set_current_buf(buf)
return buf, vim.api.nvim_get_current_win()
end
local split = opts.split or (vim.o.splitbelow and "below" or "above")
local win = vim.api.nvim_open_win(buf, true, { split = split })
return buf, win
end
---@param fmt string
---@param ... any
function M.error(fmt, ...)