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=nightUsing 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 applyMy 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.ymlDon’t forget to make it executable:
chmod +x ~/.local/bin/switch-themeThis 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 -eAnd 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,
})