refactor(git): replace status_view URI scheme with path-style name

This commit is contained in:
2026-05-19 16:29:09 +02:00
parent 4461a65b90
commit ffd5584a05
3 changed files with 110 additions and 84 deletions
+17 -76
View File
@@ -7,8 +7,6 @@ local util = require("git.core.util")
local M = {} local M = {}
M.URI_PREFIX = "gitstatus://"
---@type ow.Git.StatusView.Placement[] ---@type ow.Git.StatusView.Placement[]
M.PLACEMENTS = { "sidebar", "split", "current" } M.PLACEMENTS = { "sidebar", "split", "current" }
@@ -16,14 +14,10 @@ M.PLACEMENTS = { "sidebar", "split", "current" }
local SECTIONS = { "untracked", "unstaged", "staged", "unmerged" } local SECTIONS = { "untracked", "unstaged", "staged", "unmerged" }
local WINDOW_WIDTH = 50 local WINDOW_WIDTH = 50
---@param name string ---@param r ow.Git.Repo
---@return integer? bufnr ---@return string
local function find_buf(name) local function buf_name_for(r)
for _, b in ipairs(vim.api.nvim_list_bufs()) do return r.worktree .. "/Git Status"
if vim.api.nvim_buf_get_name(b) == name then
return b
end
end
end end
---@alias ow.Git.StatusView.Placement "sidebar"|"split"|"current" ---@alias ow.Git.StatusView.Placement "sidebar"|"split"|"current"
@@ -697,8 +691,9 @@ function M.open(opts)
util.error("not in a git repository") util.error("not in a git repository")
return return
end end
local previous_win = vim.api.nvim_get_current_win() local previous_win = vim.api.nvim_get_current_win()
local buf = vim.fn.bufadd(M.URI_PREFIX .. r.worktree) local buf = vim.fn.bufadd(buf_name_for(r))
local visible = vim.fn.bufwinid(buf) local visible = vim.fn.bufwinid(buf)
if visible ~= -1 then if visible ~= -1 then
@@ -707,78 +702,24 @@ function M.open(opts)
return return
end end
local was_loaded = vim.api.nvim_buf_is_loaded(buf) if not state[buf] then
local win = place(buf, placement) vim.fn.bufload(buf)
repo.bind(buf, r)
vim.bo[buf].bufhidden = placement == "sidebar" and "wipe" or "hide" util.setup_scratch(buf, {})
local s = state[buf] vim.bo[buf].filetype = "gitstatus"
if s then setup_buffer(buf, r, placement)
s.win = win
s.placement = placement
end end
vim.bo[buf].bufhidden = placement == "sidebar" and "wipe" or "hide"
local win = place(buf, placement)
state[buf].win = win
state[buf].placement = placement
set_keymaps(buf, placement) set_keymaps(buf, placement)
if placement == "sidebar" then if placement == "sidebar" then
vim.api.nvim_set_current_win(previous_win) vim.api.nvim_set_current_win(previous_win)
end end
if was_loaded then
refresh(buf)
end
r:refresh()
end
---@param buf integer
function M.read_uri(buf)
local name = vim.api.nvim_buf_get_name(buf)
local raw = name:sub(#M.URI_PREFIX + 1)
if raw == "" then
return
end
local worktree = vim.fs.abspath(raw)
local r = repo.resolve(worktree)
if not r then
util.error("not a git worktree: %s", raw)
return
end
if r.worktree ~= worktree then
util.warning("%s is not a worktree root, using %s", raw, r.worktree)
end
local canonical = M.URI_PREFIX .. r.worktree
if name ~= canonical then
local existing = find_buf(canonical)
if existing and existing ~= buf then
local win = vim.api.nvim_get_current_win()
if vim.api.nvim_win_get_buf(win) == buf then
vim.api.nvim_win_set_buf(win, existing)
end
vim.api.nvim_buf_delete(buf, { force = true })
local s = state[existing]
if s then
s.win = win
s.placement = "current"
end
refresh(existing)
r:refresh()
return
end
pcall(vim.api.nvim_buf_set_name, buf, canonical)
end
repo.bind(buf, r)
util.setup_scratch(buf, { bufhidden = "hide" })
vim.bo[buf].filetype = "gitstatus"
---@type integer?
local win = vim.fn.bufwinid(buf)
if win == -1 then
win = nil
end
if not state[buf] then
setup_buffer(buf, r, "current", win)
else
state[buf].win = win
end
refresh(buf) refresh(buf)
r:refresh() r:refresh()
end end
+3 -8
View File
@@ -103,14 +103,6 @@ vim.api.nvim_create_autocmd("BufReadCmd", {
require("git.log_view").read_uri(args.buf) require("git.log_view").read_uri(args.buf)
end, end,
}) })
vim.api.nvim_create_autocmd("BufReadCmd", {
pattern = "gitstatus://*",
group = group,
callback = function(args)
require("git.status_view").read_uri(args.buf)
end,
})
vim.api.nvim_create_user_command("G", function(opts) vim.api.nvim_create_user_command("G", function(opts)
local cmd = require("git.cmd") local cmd = require("git.cmd")
cmd.run(cmd.parse_args(opts.args), { bang = opts.bang }) cmd.run(cmd.parse_args(opts.args), { bang = opts.bang })
@@ -233,6 +225,9 @@ vim.keymap.set("n", "<Plug>(git-diff-horizontal-head)", function()
}) })
end, { silent = true, desc = "Diff against HEAD (horizontal)" }) end, { silent = true, desc = "Diff against HEAD (horizontal)" })
vim.keymap.set("n", "<Plug>(git-status-open)", function()
require("git.status_view").open()
end, { silent = true, desc = "Open git status sidebar" })
vim.keymap.set("n", "<Plug>(git-status-toggle)", function() vim.keymap.set("n", "<Plug>(git-status-toggle)", function()
require("git.status_view").toggle() require("git.status_view").toggle()
end, { silent = true, desc = "Toggle git status sidebar" }) end, { silent = true, desc = "Toggle git status sidebar" })
+90
View File
@@ -315,3 +315,93 @@ t.test(
) )
end end
) )
t.test("sidebar buffer is named <worktree>/Git Status", function()
local repo = h.make_repo({ ["foo.txt"] = "x\n" })
vim.cmd("cd " .. repo)
require("git.status_view").open({ placement = "sidebar" })
local r = assert(require("git.core.repo").find(vim.fn.getcwd()))
local buf = find_sidebar()
assert(buf, "sidebar buffer should exist")
t.eq(
vim.api.nvim_buf_get_name(buf),
r.worktree .. "/Git Status",
"buffer name should be <worktree>/Git Status"
)
end)
t.test(
"calling open twice without closing focuses the existing sidebar",
function()
local repo = h.make_repo({ ["foo.txt"] = "x\n" })
vim.cmd("cd " .. repo)
require("git.status_view").open({ placement = "sidebar" })
local first = find_sidebar()
assert(first, "first sidebar buffer should exist")
require("git.status_view").open({ placement = "sidebar" })
local second = find_sidebar()
assert(second, "second sidebar buffer should exist")
t.eq(
first,
second,
"consecutive opens should reuse the visible sidebar"
)
local count = 0
for _, b in ipairs(vim.api.nvim_list_bufs()) do
if vim.bo[b].filetype == "gitstatus" then
count = count + 1
end
end
t.eq(count, 1, "only one gitstatus buffer should exist")
end
)
t.test("opening for different worktrees creates separate buffers", function()
local repo_a = h.make_repo({ ["a.txt"] = "x\n" })
local repo_b = h.make_repo({ ["b.txt"] = "y\n" })
vim.cmd("cd " .. repo_a)
require("git.status_view").open({ placement = "sidebar" })
local buf_a = find_sidebar()
require("git.status_view").toggle()
vim.cmd("cd " .. repo_b)
require("git.status_view").open({ placement = "sidebar" })
local buf_b = find_sidebar()
assert(buf_a and buf_b)
t.truthy(
buf_a ~= buf_b,
"different worktrees should produce different buffers"
)
end)
t.test("sidebar buffer is buftype=nofile and not buflisted", function()
local repo = h.make_repo({ ["foo.txt"] = "x\n" })
vim.cmd("cd " .. repo)
require("git.status_view").open({ placement = "sidebar" })
local buf = find_sidebar()
assert(buf, "sidebar buffer should exist")
t.eq(vim.bo[buf].buftype, "nofile", "buftype should be nofile")
t.eq(vim.bo[buf].buflisted, false, "buflisted should be false")
end)
t.test("sidebar buffer name does not get written to disk", function()
local repo = h.make_repo({ ["foo.txt"] = "x\n" })
vim.cmd("cd " .. repo)
require("git.status_view").open({ placement = "sidebar" })
local buf = find_sidebar()
assert(buf, "sidebar buffer should exist")
local name = vim.api.nvim_buf_get_name(buf)
vim.api.nvim_buf_call(buf, function()
pcall(function()
vim.cmd("silent! write")
end)
end)
t.eq(
vim.uv.fs_stat(name),
nil,
"no real file should be created at the sidebar buffer's path"
)
end)