Following up on my previous post on automatic theme switching in VS Code, I set out to extend day/night theme switching beyond just VS Code to all my dotfiles, including Alacritty and Neovim.
Existing Tools
There are many existing tools for managing dotfiles dynamically. Here are a couple examples:
Using yadm:
# Split the config into two versions:
cp ~/.config/alacritty/alacritty.yml ~/.config/alacritty/alacritty.yml##theme=day
cp ~/.config/alacritty/alacritty.yml ~/.config/alacritty/alacritty.yml##theme=night
# Tell yadm to switch between themes:
yadm alt theme=day yadm alt theme=night
Using chezmoi:
Here’s an example of alacritty.toml.tmpl
using chezmoi’s Go template syntax:
{{ if eq .theme "day" }}
import = ["~/.local/share/alacritty-theme/themes/atom_one_light.toml"]
{{ else }}
import = ["~/.local/share/alacritty-theme/themes/onedark.toml"]
{{ end }}
chezmoi set --local theme night
chezmoi apply
My Approach with stow
+ envsubst
However since my dotfiles repo is
heavily based on stow, I wanted a solution
that integrates well with it. That’s when I came across envsubst
from
GNU gettext, which immediately stood
out for its portability and availability as a standard GNU utility.
I ended up implementing
cowboy-bebug/dotfiles/@dde6579
as my solution. Using envsubst
is simple and minimal, as expected from a GNU
utility.
Implementation
First, I created a template file at ~/.config/alacritty/alacritty.template.yml
that uses a shell variable:
import = ["~/.local/share/alacritty-theme/themes/${ALACRITTY_THEME}.toml"]
Then, I created a script, ~/.local/bin/switch-theme
, that dynamically
substitutes different values based on the time of day:
#!/usr/bin/env bash
HOUR=$(date +%H)
if [ "$HOUR" -ge 6 ] && [ "$HOUR" -lt 19 ]; then
export ALACRITTY_THEME="atom_one_light"
else
export ALACRITTY_THEME="onedark"
fi
envsubst < ~/.config/alacritty/alacritty.template.yml > ~/.config/alacritty/alacritty.yml
Don’t forget to make it executable:
chmod +x ~/.local/bin/switch-theme
This script works whether you’re managing your dotfiles with stow
, chezmoi
,
or manually.
Lastly, schedule running the script with cron
(or systemd
if you prefer):
crontab -e
And add this line:
# Switch theme at 6:01AM and 7:01PM
1 6,19 * * * /home/yourusername/.local/bin/switch-theme
Gotchas
While implementing this setup, I ran into a couple of caveats worth noting.
1. Exporting Variables
envsubst
requires variables to be exported within your script. Without
export
, envsubst
won’t recognise the variable, and the substitution will
silently fail.
2. Neovim Cache
Neovim caches Lua modules, including theme settings. When using
NvChad , I noticed that updating the theme in
~/.config/nvim/lua/chadrc.lua
doesn’t always apply changes immediately. This
is because Neovim compiles and stores Lua modules in ~/.cache/nvim/luac
, which
can cause it to load outdated config unless explicitly reloaded.
To ensure your updated theme is applied on startup, you can force a reload by
adding this snippet to chadrc.lua
:
vim.api.nvim_create_autocmd("User", {
pattern = "VeryLazy", -- ensures it runs after NvChad lazy loading
callback = function()
require("base46").load_all_highlights()
end,
})