Configuring Neovim and Kitty to follow Gnome dark/light theme
Make Kitty and Neovim follow your changing color scheme in gnome!
I'm one of the people that do not constantly use dark mode in their software, but instead prefer to match it with the time of day. In gnome this can be achieved using Night Theme Switcher extension.
Once enabled it will transition between night and dark themes automatically at sunrise and sunset. Additionally it allows to execute a script when it does so, which we will use for our implementation.
Kitty
Kitty supports functionality to change a theme via cli like so:
kitten themes --reload-in=all Rosé Pine Dawn
In case you are using home manager, a workaround is to create theme.conf
file in $HOME/.config/kitty
and include it with include theme.conf
from your kitty.conf
.
We leave file file empty so that we can later modify it with the theme of our choice.
echo "include themes/rose-pine-dawn.conf" >$HOME/.config/kitty/theme.conf
# Notify kitty procesed of changed configuration.
kill -SIGUSR1 $(pidof kitty)
Neovim
With kitty theme changing out of the way, we can focus on neovim. We could do similar approach as Kitty, by modifying a config file and reloading neovim configurations. But i took a different approach.
Instead of modifying config, i thought if there is a way of reading what theme is currently set, and decide based on that programmatically.
We can read gsettings
to figure out current color scheme like so:
gsettings get org.gnome.desktop.interface color-scheme
Which outputs 'prefer-dark'
when set to dark or 'default'
for normal.
With plenary.job we can run that command and based on response decide what "color scheme" to set. Like so:
-- Create a job to detect current gnome color scheme and set background
local Job = require("plenary.job")
local set_background = function()
local j = Job:new({ command = "gsettings", args = { "get", "org.gnome.desktop.interface", "color-scheme" } })
j:sync()
if j:result()[1] == "'default'" then
vim.o.background = "light"
else
vim.o.background = "dark"
end
end
-- Call imidiatly to set initially
set_background()
Last thing is then to somehow notify neovim instances about the theme change. It would be nice if we could hook in to dbus events and implement this without even the need of external tools. But for now, we can listen for a SIGUSR1
event instead and trigger the set_background()
function.
-- Debounce to not call the method too often in case of multiple signals.
local debounce = function(ms, fn)
local running = false
return function()
if running then
return
end
vim.defer_fn(function()
running = false
end, ms)
running = true
vim.schedule(fn)
end
end
-- Listen for SIGUSR1 signal to update background
local group = vim.api.nvim_create_augroup("BackgroundWatch", { clear = true })
vim.api.nvim_create_autocmd("Signal", {
pattern = "SIGUSR1",
callback = debounce(500, set_background),
group = group,
})
Making it all work together
Now that we have both figured out, we have to implement our sunset.sh
and sunrise.sh
scripts.
sunrise.sh
#!/bin/env bash
# Kitty terminal
echo "include themes/rose-pine-dawn.conf" >$HOME/.config/kitty/theme.conf
kill -SIGUSR1 $(pidof kitty)
# Neovim
kill -SIGUSR1 $(pidof nvim)
sunset.sh
#!/bin/env bash
# Kitty terminal
echo "include themes/rose-pine-moon.conf" >$HOME/.config/kitty/theme.conf
kill -SIGUSR1 $(pidof kitty)
# Neovim
kill -SIGUSR1 $(pidof nvim)
Final look
You can see my full implementation in my dotfiles repository.
---
This site is not using any commenting system, but you can share your thoughts with the author by sending an email to me@mnts.dev.
---