Skip to content

Fix nvim transparency to preserve foreground colors#4844

Merged
dhh merged 2 commits intobasecamp:devfrom
jorgemanrubia:fix-nvim-transparency-highlights
Mar 7, 2026
Merged

Fix nvim transparency to preserve foreground colors#4844
dhh merged 2 commits intobasecamp:devfrom
jorgemanrubia:fix-nvim-transparency-highlights

Conversation

@jorgemanrubia
Copy link
Copy Markdown
Member

@jorgemanrubia jorgemanrubia commented Mar 1, 2026

Summary

  • The old transparency.lua used vim.api.nvim_set_hl(0, name, { bg = "none" }) which replaces the entire highlight definition, wiping out foreground and other attributes — not just the background
  • This breaks snacks.nvim's GitHub integration (<leader>gp for PRs, <leader>gi for issues) which reads the foreground color from Normal/NormalFloat at module load time, gets nil, and crashes with "Finder not found: gh_pr"
  • The fix uses nvim_get_hl to fetch existing attributes first, removes only bg, then sets the highlight back — preserving all other attributes

Companion PR for fresh installs (source file): omacom-io/omarchy-pkgs#51

Root cause

snacks/util/init.lua:187: attempt to index local 'fg' (a nil value)

The snacks.gh module computes diff highlight colors at require-time by calling Snacks.util.color("Normal") to get the foreground. Since the transparency script cleared it, fg is nil and Snacks.util.blend(nil, bg, alpha) crashes. The pcall in the picker's finder resolution catches this, and the picker reports "Finder not found".

Test plan

  • Open nvim in a git repo and press <leader>gp — should open the GitHub PR picker without errors
  • Verify transparent backgrounds still work correctly
  • Verify foreground colors are preserved (text should look the same as before)

🤖 Generated with Claude Code

The old approach used `vim.api.nvim_set_hl(0, name, { bg = "none" })`
which replaces the entire highlight definition, wiping out foreground
and other attributes. This breaks snacks.nvim's GitHub integration
(gh_pr/gh_issue pickers) which reads the foreground color from Normal
and NormalFloat at module load time, gets nil, and crashes in
Snacks.util.blend().

The fix uses nvim_get_hl to fetch existing attributes first, removes
only bg, then sets the highlight back — preserving all other attributes.
Copilot AI review requested due to automatic review settings March 1, 2026 18:31
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Neovim transparency migration so transparent highlights no longer wipe existing foreground/style attributes, preventing plugins (e.g., snacks.nvim GitHub pickers) from reading nil highlight colors at load time.

Changes:

  • Add a new migration that rewrites ~/.config/nvim/plugin/after/transparency.lua to preserve existing highlight attributes while clearing only background.
  • Apply transparency across a defined list of common UI/plugin highlight groups.
Comments suppressed due to low confidence (2)

migrations/1772389838.sh:68

  • This migration overwrites the entire ~/.config/nvim/plugin/after/transparency.lua whenever it exists. That’s a behavior change from the earlier transparency migration (migrations/1771667323.sh) which patched the file in-place, and it can clobber user customizations or other injected highlight tweaks. Consider making this migration update only the specific nvim_set_hl(... { bg = "none" }) pattern (or only overwrite if the file matches an expected template), and/or writing a backup before replacing the file.
if [[ -f "$TRANSPARENCY_FILE" ]]; then
  cat > "$TRANSPARENCY_FILE" << 'EOF'
-- Make highlight groups transparent while preserving their other attributes
local function make_transparent(name)
	local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = name, link = false })
	if ok then
		hl.bg = nil
		vim.api.nvim_set_hl(0, name, hl)
	else
		vim.api.nvim_set_hl(0, name, { bg = "none" })
	end
end

local groups = {
	-- transparent background
	"Normal",
	"NormalFloat",
	"FloatBorder",
	"Pmenu",
	"Terminal",
	"EndOfBuffer",
	"FoldColumn",
	"Folded",
	"SignColumn",
	"LineNr",
	"CursorLineNr",
	"NormalNC",
	"WhichKeyFloat",
	"TelescopeBorder",
	"TelescopeNormal",
	"TelescopePromptBorder",
	"TelescopePromptTitle",
	-- neotree
	"NeoTreeNormal",
	"NeoTreeNormalNC",
	"NeoTreeVertSplit",
	"NeoTreeWinSeparator",
	"NeoTreeEndOfBuffer",
	-- nvim-tree
	"NvimTreeNormal",
	"NvimTreeVertSplit",
	"NvimTreeEndOfBuffer",
	-- notify
	"NotifyINFOBody",
	"NotifyERRORBody",
	"NotifyWARNBody",
	"NotifyTRACEBody",
	"NotifyDEBUGBody",
	"NotifyINFOTitle",
	"NotifyERRORTitle",
	"NotifyWARNTitle",
	"NotifyTRACETitle",
	"NotifyDEBUGTitle",
	"NotifyINFOBorder",
	"NotifyERRORBorder",
	"NotifyWARNBorder",
	"NotifyTRACEBorder",
	"NotifyDEBUGBorder",
}

for _, name in ipairs(groups) do
	make_transparent(name)
end
EOF

migrations/1772389838.sh:13

  • The Lua code in the heredoc uses tab indentation, but this repo’s .editorconfig specifies indent_style = space / indent_size = 2. To keep formatting consistent (and avoid whitespace churn in future edits), consider reindenting the embedded Lua with 2 spaces instead of tabs.
local function make_transparent(name)
	local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = name, link = false })
	if ok then
		hl.bg = nil
		vim.api.nvim_set_hl(0, name, hl)
	else

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread migrations/1772389838.sh Outdated
If nvim_get_hl fails for a group, skip it rather than falling back to
the old { bg = "none" } approach that clears all attributes.
jorgemanrubia added a commit to jorgemanrubia/omarchy-pkgs that referenced this pull request Mar 1, 2026
nvim_set_hl with just { bg = "none" } replaces the entire highlight
definition, wiping foreground and other attributes. This breaks
snacks.nvim GitHub integration (gh_pr/gh_issue pickers) which reads
fg from Normal/NormalFloat at require-time.

Use nvim_get_hl to fetch existing attributes first, remove only bg,
then set the highlight back.

See basecamp/omarchy#4844 for the companion migration for existing installs.
@dhh
Copy link
Copy Markdown
Member

dhh commented Mar 2, 2026

Can you show where this is broken?

Also, need to change the base of the config in addition to just a migration (since those are only applied to existing systems, not new installs).

@jorgemanrubia
Copy link
Copy Markdown
Member Author

With the original transparency.lua I get this error when pressing <leader>gp:

image

Can you reproduce yourself? I haven't messed with my neovim config that I know of, but I have been running Omarchy for a while, so there is a chance it is local to my box.

I had already created a PR to change the base config here omacom-io/omarchy-pkgs#51

@dhh
Copy link
Copy Markdown
Member

dhh commented Mar 2, 2026

Ohh! I had never used that feature. It's broken here too 😄

@dhh dhh merged commit 3da14f8 into basecamp:dev Mar 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants