Fix nvim transparency to preserve foreground colors#4844
Conversation
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.
There was a problem hiding this comment.
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.luato 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.luawhenever 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 specificnvim_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
.editorconfigspecifiesindent_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.
If nvim_get_hl fails for a group, skip it rather than falling back to
the old { bg = "none" } approach that clears all attributes.
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.
|
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). |
|
With the original transparency.lua I get this error when pressing
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 |
|
Ohh! I had never used that feature. It's broken here too 😄 |

Summary
transparency.luausedvim.api.nvim_set_hl(0, name, { bg = "none" })which replaces the entire highlight definition, wiping out foreground and other attributes — not just the background<leader>gpfor PRs,<leader>gifor issues) which reads the foreground color fromNormal/NormalFloatat module load time, getsnil, and crashes with"Finder not found: gh_pr"nvim_get_hlto fetch existing attributes first, removes onlybg, then sets the highlight back — preserving all other attributesCompanion PR for fresh installs (source file): omacom-io/omarchy-pkgs#51
Root cause
The
snacks.ghmodule computes diff highlight colors at require-time by callingSnacks.util.color("Normal")to get the foreground. Since the transparency script cleared it,fgis nil andSnacks.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
<leader>gp— should open the GitHub PR picker without errors🤖 Generated with Claude Code