Files
nvim/lua/git/repo.lua
T

126 lines
2.9 KiB
Lua

local util = require("git.util")
local M = {}
---@param path string
---@return string? gitdir
---@return string? worktree
function M.resolve(path)
local found = vim.fs.find(".git", { upward = true, path = path })[1]
if not found then
return nil
end
local worktree = vim.fs.dirname(found)
local stat = vim.uv.fs_stat(found)
if not stat then
return nil
end
if stat.type == "directory" then
return found, worktree
end
local f = io.open(found, "r")
if not f then
return nil
end
local content = f:read("*a")
f:close()
local gitdir = content:match("gitdir:%s*(%S+)")
if not gitdir then
util.warning(".git file at %s has no `gitdir:` line", found)
return nil
end
if not gitdir:match("^/") then
gitdir = vim.fs.joinpath(worktree, gitdir)
end
return vim.fs.normalize(gitdir), worktree
end
---@return string? gitdir
---@return string? worktree
function M.resolve_cwd()
local path = vim.api.nvim_buf_get_name(0)
if path == "" or path:match("^%a+://") then
path = vim.fn.getcwd()
end
return M.resolve(path)
end
---@param path string
---@return string?
function M.head(path)
local gitdir = M.resolve(path)
if not gitdir then
return nil
end
local f = io.open(vim.fs.joinpath(gitdir, "HEAD"), "r")
if not f then
return nil
end
local first = f:read("*l")
f:close()
if not first then
return nil
end
local branch = first:match("^ref:%s*refs/heads/(%S+)")
if branch then
return branch
end
local sha = first:match("^(%x+)")
if sha then
return sha:sub(1, 7)
end
return nil
end
---@param worktree string
---@return string[]
function M.list_refs(worktree)
local out = util.exec({
"git",
"for-each-ref",
"--format=%(refname:short)",
"refs/heads",
"refs/tags",
"refs/remotes",
}, { cwd = worktree, silent = true })
if not out then
return {}
end
local refs = util.split_lines(out)
table.insert(refs, 1, "HEAD")
return refs
end
---@param arg_lead string
---@return string[]
function M.complete_rev(arg_lead)
local _, worktree = M.resolve_cwd()
if not worktree then
return {}
end
local matches = {}
for _, ref in ipairs(M.list_refs(worktree)) do
if ref:sub(1, #arg_lead) == arg_lead then
table.insert(matches, ref)
end
end
return matches
end
---@param worktree string
---@param rev string
---@param short boolean
---@return string?
function M.rev_parse(worktree, rev, short)
local cmd = { "git", "rev-parse", "--verify", "--quiet" }
if short then
table.insert(cmd, "--short")
end
table.insert(cmd, rev)
local stdout = util.exec(cmd, { cwd = worktree, silent = true })
local trimmed = stdout and vim.trim(stdout) or ""
return trimmed ~= "" and trimmed or nil
end
return M