Skip to content

Instantly share code, notes, and snippets.

@lkhphuc
Last active December 25, 2023 06:20
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lkhphuc/ea6db0458268cad1493b2674cb0fda51 to your computer and use it in GitHub Desktop.
Save lkhphuc/ea6db0458268cad1493b2674cb0fda51 to your computer and use it in GitHub Desktop.
A simple utility function to override and update any colorscheme in Neovim.

I like to have my neovim to bold the language keywords, italicize the comments, or both italicize and bold all the builtin functions, type or constants etc. And I want this to be consistent across colorschemes.

In vim/neovim, to update a highlight group it is as simple as highlight HighlightGroupToModified gui=bold,italic,underline. But this is problematic if the HighlightGroupToModified is defined as a link to other highlight group. For example highlight TSInclude might be linked to Include by your colorscheme, so executing hi TSInclude gui=bold will apply bold to TSInclude but wipe out any foreground and background color information that was originally defined by linking to Include highlight group.

Since every colorschemes can arbitrarily choose to define a highlight group explicitly or by linking, adding hi TSConstant gui=bold to your config are bound to break when you switch colorschemes. A manual approach is to recursively go down the linking chain defined by colorscheme, e.g TSConstant links to Constant links to PreProc, and apply your edit to PreProc If you like to switch colorscheme often, or have a different colorscheme for different remote hosts, it is really annoying to manually inspect all the highlight groups you would like to modified for your colorscheme.

In neovim, you can directly get the highlight group definition irrespective of the link by using vim.api.nvim_get_by_name. Then you can set the highlight group using vim.api.nvim_set_hl. You can combine it together to have a function that will update any highlight group you like, without caring if it was defined by link or not:

local function mod_hl(hl_name, opts)
  local is_ok, hl_def = pcall(vim.api.nvim_get_hl_by_name, hl_name, true)
  if is_ok then
    for k,v in pairs(opts) do hl_def[k] = v end
    vim.api.nvim_set_hl(0, hl_name, hl_def)
  end
end

The pcall is for protected call, in case when you execute this function the highlight group has not yet been defined because of some lazyloading. You can use it by calling `mod_hl("TSConstant", {bold=true, italic=false}). Now it doesn't matter if TSConstant was defined by link or not, if it was already italicize or not, you know your TSConstant will be bold and not italic, with the color still defined by your colorscheme.

Now you can define a autocommand to execute a bunch of the function call everytime you change colorscheme like:

-- Execute on VimEnter too because somehow on startup TS... is not defined even after executing colorscheme command
vim.api.nvim_create_autocmd({"VimEnter", "ColorScheme"}, {
  group = vim.api.nvim_create_augroup('Color', {}),
  pattern = "*",
  callback = function ()
    mod_hl("TSInclude", { bold=true, italic=true })
    mod_hl("TSKeywordReturn", { bold=true, italic=true })
    mod_hl("TSConstBuiltin", { bold=true, italic=true })
    .........
})

Before:

image

After:

image

Full config:

-- Due to the way different colorschemes configure different highlights group,
-- there is no universal way to add gui options to all the desired components.
-- Findout the final highlight group being linked to and update gui option.
local function mod_hl(hl_name, opts)
  local is_ok, hl_def = pcall(vim.api.nvim_get_hl_by_name, hl_name, true)
  if is_ok then
    for k,v in pairs(opts) do hl_def[k] = v end
    vim.api.nvim_set_hl(0, hl_name, hl_def)
  end
end

vim.api.nvim_create_autocmd({"VimEnter", "ColorScheme"}, {
  group = vim.api.nvim_create_augroup('Color', {}),
  pattern = "*",
  callback = function ()
    mod_hl("TSKeywordReturn", { bold=true, italic=true })
    mod_hl("TSConstBuiltin", { bold=true, italic=true })
    mod_hl("TSFuncBuiltin", { bold=true, italic=true })
    mod_hl("TSTypeBuiltin", { bold=true, italic=true })
    mod_hl("TSBoolean", { bold=true, italic=true })

    mod_hl("TSType", { bold=true })
    mod_hl("TSConstructor", { bold=true })
    mod_hl("TSOperator", { bold=true })

    mod_hl("TSInclude", { italic=true, })
    mod_hl("TSVariableBuiltin",{ italic=true })
    mod_hl("TSConditional", { italic=true })
    mod_hl("TSKeyword", { italic=true })
    mod_hl("TSKeywordFunction", { italic=true })
    mod_hl("TSComment", { italic=true })
    mod_hl("TSParameter", { italic=true })

    mod_hl("semshiBuiltin", { italic=true, })
    -- vim.api.nvim_set_hl(0, "semshiImported", {link="TSConstant"})
    -- mod_hl("semshiImported", { bold=true, })
    vim.api.nvim_set_hl(0, "semshiAttribute", {link="TSAttribute"})


    -- mod_hl("TSVariable", { bold=false, italic=false, })
    -- mod_hl("Folded", { bg="" })
  end
})

vim.cmd "set termguicolors"
vim.cmd "colorscheme catppuccin"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment