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,
})