❀✿❀ SuperLaserNino ✿❀✿

Make Neovim respect your macOS appearance settings

7 January 2025

365 words

[It turns out they’re working on native support for this feature, but it looks like my approach might be more flexible, so I decided to post this anyway.]

When I discovered that Ghostty can change its colours based on the system light/dark mode settings, I was curious whether I could achieve the same effect in Neovim. It turns out, it’s possible! (You don’t need to use Ghostty for this to work, that was just my inspiration to figure this out.)

This code only works on macOS, but I’m sure you could get an AI to translate it to work on Windows or Linux:

function CheckAppearance()
  local theme = vim.fn.system('defaults read -g AppleInterfaceStyle'):gsub('\n', '')
  if theme == 'Dark' then
    vim.o.background = 'dark'
    vim.cmd('colorscheme modus_vivendi')
    vim.cmd [[ hi DiffText cterm=bold gui=bold ctermbg=225 guibg=DarkRed ]]
    -- For some reason the RenderMarkdown plugin doesn't pick up the changes
    -- when run through an autocmd
    vim.cmd [[ hi RenderMarkdown_bgtofg_RenderMarkdownCode guifg=#1e1e1e ]]
  else
    vim.o.background = 'light'
    -- These are my settings, but you can go wild and put whatever you want
    vim.cmd('colorscheme modus_operandi')
    vim.cmd [[ hi DiffText cterm=bold gui=bold ctermbg=225 guibg=LightRed ]]
    -- For some reason the RenderMarkdown plugin doesn't pick up the changes
    -- when run through an autocmd
    vim.cmd [[ hi RenderMarkdown_bgtofg_RenderMarkdownCode guifg=#f2f2f2 ]]
  end
end

-- Run on startup
CheckAppearance()

So far, it’ll just check the appearance setting when you start Neovim. There are a few ways to get it to dynamically detect changes to the setting:

Manually. Just create a user command and run it manually (ugh):

vim.api.nvim_create_user_command('CheckAppearance', function()
  CheckAppearance()
end, {})

On focus gained. This is what I’m using – Neovim will check the appearance whenever you activate it. This means it won’t switch immediately with the system, but it’ll always match when you’re actually using Neovim:

vim.api.nvim_create_autocmd("FocusGained", {
  callback = function()
    CheckAppearance()
  end,
})

Note: Some plugins might not pick up the changes properly, so you might have to add extra stuff in the CheckAppearance function, like that RenderMarkdown_bgtofg_RenderMarkdownCode highlight rule.

Here’s what it looks like in the end: