local repo = require("git.repo") local util = require("git.util") local M = {} local LOG_FORMAT = "%h %ad {%an}%d %s" local DEFAULT_MAX_COUNT = 1000 local URI_PREFIX = "gitlog://" ---@param worktree string ---@param max_count integer ---@return string? local function fetch(worktree, max_count) local cmd = { "git", "log", "--graph", "--all", "--decorate", "--date=short", "--format=format:" .. LOG_FORMAT, } if max_count > 0 then table.insert(cmd, "--max-count=" .. max_count) end return util.exec(cmd, { cwd = worktree }) end ---@param buf integer local function populate(buf) local worktree = vim.b[buf].git_worktree local max_count = vim.b[buf].git_log_max_count or DEFAULT_MAX_COUNT local stdout = fetch(worktree, max_count) if not stdout then return end vim.bo[buf].modifiable = true vim.api.nvim_buf_set_lines(buf, 0, -1, false, util.split_lines(stdout)) vim.bo[buf].modifiable = false vim.bo[buf].modified = false end ---BufReadCmd handler for `gitlog://` URIs. ---@param buf integer function M.read_uri(buf) local name = vim.api.nvim_buf_get_name(buf) local worktree = name:sub(#URI_PREFIX + 1) if worktree == "" then return end vim.b[buf].git_worktree = worktree vim.bo[buf].swapfile = false vim.bo[buf].bufhidden = "hide" vim.bo[buf].buftype = "nofile" -- Skip the assignment when ft is already set so re-runs don't -- re-fire `FileType` autocmds (ftplugin reload, treesitter attach). if vim.bo[buf].filetype ~= "gitlog" then vim.bo[buf].filetype = "gitlog" end populate(buf) end ---@class ow.Git.LogOpts ---@field max_count integer? cap on commits to show. Nil uses the default, <= 0 means "all" ---@param opts ow.Git.LogOpts? function M.open(opts) opts = opts or {} local _, worktree = repo.resolve_cwd() if not worktree then util.warning("not in a git repository") return end local buf = vim.fn.bufadd(URI_PREFIX .. worktree) vim.b[buf].git_worktree = worktree vim.b[buf].git_log_max_count = opts.max_count or DEFAULT_MAX_COUNT local was_loaded = vim.api.nvim_buf_is_loaded(buf) local win = vim.fn.bufwinid(buf) if win == -1 then util.place_buf(buf, nil) else vim.api.nvim_set_current_win(win) end -- `place_buf` triggers `bufload` -> `read_uri` for a fresh buffer. -- An already-loaded buffer needs an explicit refresh. if was_loaded then populate(buf) end end return M