feat(git/statusline): expose status via b:git_status, opt-in via enable()

This commit is contained in:
2026-05-09 19:54:49 +02:00
parent 9b29325508
commit a7932bab5a
5 changed files with 124 additions and 36 deletions
+2
View File
@@ -95,3 +95,5 @@ require("ts").setup({
"https://github.com/tree-sitter-grammars/tree-sitter-yaml",
"https://github.com/georgeharker/tree-sitter-zsh",
})
require("git.statusline").enable()
+1 -1
View File
@@ -77,7 +77,7 @@ vim.opt.inccommand = "split"
vim.opt.winborder = "rounded"
vim.opt.confirm = true
vim.opt.statusline = "%{expand('%:.')} %{%v:lua.require('git.statusline').render()%} %3(%m%)"
vim.opt.statusline = "%{expand('%:.')} %{%get(b:, 'git_status_string', '')%} %3(%m%)"
.. " %="
.. " %{%v:lua.vim.diagnostic.status()%}"
.. " %{&filetype} %{&fileencoding} %{&fileformat}"
+4 -2
View File
@@ -220,6 +220,7 @@ end
---@return string?
function Repo:head()
return self:get_cached("head", function(self)
local f = io.open(vim.fs.joinpath(self.gitdir, "HEAD"), "r")
if not f then
return nil
@@ -238,6 +239,7 @@ function Repo:head()
return sha:sub(1, 7)
end
return nil
end)
end
---@return string[]
@@ -408,7 +410,7 @@ end
---@return string
local function path_for_buf(buf)
local path = vim.api.nvim_buf_get_name(buf)
if path == "" or path:match("^%a+://") then
if path == "" or util.is_uri(path) then
return vim.fn.getcwd()
end
return vim.fn.resolve(path)
@@ -514,7 +516,7 @@ local function is_worktree_buf(buf)
return false
end
local path = vim.api.nvim_buf_get_name(buf)
return path ~= "" and not path:match("^%a+://")
return path ~= "" and not util.is_uri(path)
end
---@param buf? integer
+92 -14
View File
@@ -1,31 +1,109 @@
local repo = require("git.repo")
local util = require("git.util")
local M = {}
---@class ow.Git.Statusline.Status
---@field head string?
---@field entries ow.Git.Status.Entry[]
---@field unstaged boolean
---@field staged boolean
---@field conflict boolean
---@param entries ow.Git.Status.Entry[]
---@param head string?
---@return ow.Git.Statusline.Status
local function build(entries, head)
local out = {
head = head,
entries = entries,
unstaged = false,
staged = false,
conflict = false,
}
for _, e in ipairs(entries) do
if e.kind == "unstaged" or e.kind == "untracked" then
out.unstaged = true
elseif e.kind == "staged" then
out.staged = true
elseif e.kind == "unmerged" then
out.conflict = true
end
end
return out
end
---@param entries ow.Git.Status.Entry[]
---@return string
function M.render()
local r = repo.find()
if not r then
return ""
end
local name = vim.api.nvim_buf_get_name(0)
if name == "" then
return ""
end
local rel = vim.fs.relpath(r.worktree, vim.fn.resolve(name))
local list = rel and r.status.entries[rel]
if not list then
local function render(entries)
if #entries == 0 then
return ""
end
local parts = {}
for _, e in ipairs(list) do
for _, e in ipairs(entries) do
table.insert(parts, string.format("%%#%s#%s%%*", e.hl, e.char))
end
return table.concat(parts, " ")
end
repo.on("refresh", function()
---@param buf integer
local function clear(buf)
vim.b[buf].git_status = nil
vim.b[buf].git_status_string = nil
end
---@param buf integer
---@param r ow.Git.Repo?
local function update_buf(buf, r)
if not vim.api.nvim_buf_is_valid(buf) then
return
end
local name = vim.api.nvim_buf_get_name(buf)
if name == "" or util.is_uri(name) then
return clear(buf)
end
r = r or repo.find(buf)
if not r then
return clear(buf)
end
local rel = vim.fs.relpath(r.worktree, vim.fn.resolve(name))
if not rel then
return clear(buf)
end
local entries = r.status.entries[rel] or {}
vim.b[buf].git_status = build(entries, r:head())
vim.b[buf].git_status_string = render(entries)
end
local enabled = false
function M.enable()
if enabled then
return
end
enabled = true
repo.on("refresh", function(r)
for buf in pairs(r.buffers) do
if vim.api.nvim_buf_is_loaded(buf) then
update_buf(buf, r)
end
end
vim.cmd.redrawstatus({ bang = true })
end)
vim.api.nvim_create_autocmd("BufWinEnter", {
group = vim.api.nvim_create_augroup(
"ow.git.statusline",
{ clear = true }
),
callback = function(args)
update_buf(args.buf, nil)
end,
})
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_loaded(buf) then
update_buf(buf, nil)
end
end
end
return M
+6
View File
@@ -20,6 +20,12 @@ function M.setup_scratch(buf, opts)
end
end
---@param name string
---@return boolean
function M.is_uri(name)
return name:match("^%a+://") ~= nil
end
---@param buf integer
---@param name string
function M.set_buf_name(buf, name)