skip to content

Search

Automatic theme switching for dotfiles

2 min read

Automate day-and-night theme switching across dotfiles using stow and envsubst. Covers alternative tools like yadm and chezmoi.

# config
Not in series

Following up on my previous post, Automatic Theme Switching for VS Code, I wanted to apply day-and-night theme switching across all my dotfiles.

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:

{{ if eq .theme "day" }}
import = ["~/.local/share/alacritty-theme/themes/atom_one_light.toml"]
{{ else }}
import = ["~/.local/share/alacritty-theme/themes/onedark.toml"]
{{ end }}
#+end_src
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 using a shell variable:

import = ["~/.local/share/alacritty-theme/themes/${ALACRITTY_THEME}.toml"]

Then, I dynamically substituted different values based on the time of day:

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

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. Since I’m using NvChad , I noticed that even after updating the theme in ~/.config/nvim/lua/chadrc.lua, changes are not applied immediately. This happens because Neovim stores compiled Lua files in ~/.cache/nvim/luac.

To ensure your updated theme is applied on startup, you can force a reaload 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,
})