Files
nvim/lua/git/repo.lua
T

130 lines
2.9 KiB
Lua

local util = require("git.util")
local M = {}
M.UNMERGED = {
DD = true,
AU = true,
UD = true,
UA = true,
DU = true,
AA = true,
UU = true,
}
---@param code string
---@return string? char
---@return string? hl_group
function M.indicator(code)
if code == "" then
return nil
end
if code == "??" then
return "?", "GitUntracked"
end
if code == "!!" then
return "!", "GitIgnored"
end
if M.UNMERGED[code] then
return "U", "GitUnmerged"
end
local x, y = code:sub(1, 1), code:sub(2, 2)
if x == "R" or y == "R" then
return "R", "GitRenamed"
end
if y == " " and x ~= " " then
return x, "GitStaged"
end
if y == "D" then
return "D", "GitDeleted"
end
return "M", "GitUnstaged"
end
---@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
---@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