From d81cf95b481f9bbcc1aedcc3313919d8e95eb6c3 Mon Sep 17 00:00:00 2001 From: Oscar Wallberg Date: Tue, 26 May 2026 14:02:37 +0200 Subject: [PATCH] fix(git): stop the blame statuscolumn leaking into new windows --- lua/git/blame.lua | 35 ++++++++++++++++++++++++++--------- test/git/blame_test.lua | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/lua/git/blame.lua b/lua/git/blame.lua index 738682d..d62715b 100644 --- a/lua/git/blame.lua +++ b/lua/git/blame.lua @@ -521,9 +521,21 @@ end ---@type table local saved_statuscolumn = {} ----Reconcile every window's `'statuscolumn'` with the overlay state: a ----window showing an overlay buffer gets the blame statuscolumn, and its ----previous value is saved so it can be restored on toggle-off. +---Set a window's `'statuscolumn'` with `scope = "local"`, so the global +---value stays clean and splits and new windows do not inherit the gutter. +---@param win integer +---@param value string +local function set_statuscolumn(win, value) + vim.api.nvim_set_option_value( + "statuscolumn", + value, + { win = win, scope = "local" } + ) +end + +---Reconcile every window's `'statuscolumn'` with the overlay state. +---Overlay windows get the blame statuscolumn, and a window that has it +---but should not (a split inherits window options) is restored. local function refresh_overlay_columns() for win in pairs(saved_statuscolumn) do if not vim.api.nvim_win_is_valid(win) then @@ -533,11 +545,16 @@ local function refresh_overlay_columns() for _, win in ipairs(vim.api.nvim_list_wins()) do local state = states[vim.api.nvim_win_get_buf(win)] local on = state ~= nil and state.overlay - if on and saved_statuscolumn[win] == nil then - saved_statuscolumn[win] = vim.wo[win].statuscolumn - vim.wo[win].statuscolumn = BLAME_EXPR .. native_items(win) - elseif not on and saved_statuscolumn[win] ~= nil then - vim.wo[win].statuscolumn = saved_statuscolumn[win] + local has_blame = vim.startswith(vim.wo[win].statuscolumn, BLAME_EXPR) + if on and not has_blame then + saved_statuscolumn[win] = saved_statuscolumn[win] + or vim.wo[win].statuscolumn + set_statuscolumn(win, BLAME_EXPR .. native_items(win)) + elseif not on and has_blame then + set_statuscolumn( + win, + saved_statuscolumn[win] or vim.go.statuscolumn + ) saved_statuscolumn[win] = nil end end @@ -560,7 +577,7 @@ local function render(buf) build_blame_text(state, win) built = true end - vim.wo[win].statuscolumn = BLAME_EXPR .. native_items(win) + set_statuscolumn(win, BLAME_EXPR .. native_items(win)) end end end diff --git a/test/git/blame_test.lua b/test/git/blame_test.lua index 316c94d..3b0fb6a 100644 --- a/test/git/blame_test.lua +++ b/test/git/blame_test.lua @@ -450,6 +450,32 @@ t.test("overlay re-budgets when a gutter option changes", function() end, "the blame to re-budget for the widened signcolumn") end) +t.test("the overlay statuscolumn does not leak into other windows", function() + local _, buf = setup("a\nb\nc\n") + vim.api.nvim_set_current_buf(buf) + blame.toggle_overlay(buf) + t.wait_for(function() + local s = blame.state(buf) + return s ~= nil and s.blame_width ~= nil + end, "the overlay to render") + t.falsy( + vim.go.statuscolumn:find("git.blame", 1, true), + "the overlay leaves the global statuscolumn untouched" + ) + + vim.cmd("new") + local plain = vim.api.nvim_get_current_win() + t.defer(function() + if vim.api.nvim_win_is_valid(plain) then + vim.api.nvim_win_close(plain, true) + end + end) + t.falsy( + vim.wo[plain].statuscolumn:find("git.blame", 1, true), + "a new window does not inherit the blame gutter" + ) +end) + t.test("overlay gutter shows sha, author and an absolute date", function() local _, buf = setup("a\nb\nc\n") vim.api.nvim_set_current_buf(buf)