135 lines
3.4 KiB
Lua
135 lines
3.4 KiB
Lua
local repo = require("git.core.repo")
|
|
local util = require("git.core.util")
|
|
|
|
local M = {}
|
|
|
|
local LOG_FORMAT = "%h %ad {%an}%d %s"
|
|
|
|
local cr = vim.api.nvim_replace_termcodes("<CR>", true, false, true)
|
|
|
|
---@param buf integer
|
|
local function attach_dispatch(buf)
|
|
vim.keymap.set("n", "<CR>", function()
|
|
local r = repo.resolve(buf)
|
|
-- Anchor past the leading graph chars (matches the leading sha column,
|
|
-- not any hex word that happens to appear later in the subject).
|
|
local sha = r
|
|
and vim.api
|
|
.nvim_get_current_line()
|
|
:match("^[*|/\\_ ]*(%x%x%x%x%x%x%x+)")
|
|
if sha then
|
|
---@cast r -nil
|
|
require("git.object").open(r, sha, { split = false })
|
|
else
|
|
vim.api.nvim_feedkeys(cr, "n", false)
|
|
end
|
|
end, { buffer = buf, silent = true, desc = "Open commit" })
|
|
end
|
|
|
|
---@param worktree string
|
|
---@param max_count integer?
|
|
---@return string?
|
|
local function fetch(worktree, max_count)
|
|
local args = {
|
|
"log",
|
|
"--graph",
|
|
"--all",
|
|
"--decorate",
|
|
"--date=short",
|
|
"--format=format:" .. LOG_FORMAT,
|
|
}
|
|
if max_count then
|
|
table.insert(args, "--max-count=" .. max_count)
|
|
end
|
|
return util.git(args, { cwd = worktree })
|
|
end
|
|
|
|
---@type table<string, integer> -- worktree -> max_count
|
|
local max_counts = {}
|
|
|
|
---@param buf integer
|
|
---@param r ow.Git.Repo
|
|
local function populate(buf, r)
|
|
local stdout = fetch(r.worktree, max_counts[r.worktree])
|
|
if not stdout then
|
|
return
|
|
end
|
|
util.set_buf_lines(buf, 0, -1, util.split_lines(stdout))
|
|
end
|
|
|
|
---@class ow.Git.Log.OpenOpts
|
|
---@field max_count integer?
|
|
|
|
---@type table<string, fun(s: string): any>
|
|
M.opt_parsers = {
|
|
max_count = tonumber,
|
|
}
|
|
|
|
---@param opts ow.Git.Log.OpenOpts?
|
|
function M.open(opts)
|
|
opts = opts or {}
|
|
local r = repo.resolve()
|
|
if not r then
|
|
util.error("not in a git repository")
|
|
return
|
|
end
|
|
|
|
max_counts[r.worktree] = opts.max_count
|
|
local buf = vim.fn.bufadd(r.worktree .. "/GitLog")
|
|
|
|
local visible = vim.fn.bufwinid(buf)
|
|
if visible ~= -1 then
|
|
vim.api.nvim_set_current_win(visible)
|
|
populate(buf, r)
|
|
vim.api.nvim_win_set_cursor(visible, { 1, 0 })
|
|
return
|
|
end
|
|
|
|
vim.fn.bufload(buf)
|
|
repo.bind(buf, r)
|
|
util.setup_scratch(buf, { bufhidden = "hide" })
|
|
vim.bo[buf].filetype = "gitlog"
|
|
attach_dispatch(buf)
|
|
|
|
local win = util.place_buf(buf, nil)
|
|
vim.api.nvim_win_set_cursor(win, { 1, 0 })
|
|
populate(buf, r)
|
|
end
|
|
|
|
---@param cmd_opts table
|
|
function M.run_glog(cmd_opts)
|
|
local parsed = { max_count = 1000 }
|
|
for _, a in ipairs(cmd_opts.fargs) do
|
|
local k, v = a:match("^([%w_]+)=(.*)$")
|
|
if not k then
|
|
util.error("invalid argument: %s", a)
|
|
return
|
|
end
|
|
---@cast v -nil
|
|
local parser = M.opt_parsers[k]
|
|
if parser then
|
|
local value = parser(v)
|
|
if value ~= nil then
|
|
parsed[k] = value
|
|
end
|
|
end
|
|
end
|
|
M.open(parsed)
|
|
end
|
|
|
|
---@param arg_lead string
|
|
---@return string[]
|
|
function M.complete_glog(arg_lead)
|
|
local matches = {}
|
|
for k in pairs(M.opt_parsers) do
|
|
local prefix = k .. "="
|
|
if prefix:sub(1, #arg_lead) == arg_lead then
|
|
table.insert(matches, prefix)
|
|
end
|
|
end
|
|
table.sort(matches)
|
|
return matches
|
|
end
|
|
|
|
return M
|