theme - extensible theme orchestrator for shell environments
theme detects the system appearance (dark or light mode) and orchestrates theme configuration across multiple tools via an extensible detector/provider/handler system.
The command performs three steps:
-
Detection - Determines system appearance (dark/light) using user-provided detector functions
-
Provider - Calls a user-registered provider function that maps appearance to theme variables (e.g., THEME_VARIANT, THEME_ACCENT)
-
Handlers - Calls all registered handler functions that configure individual tools using the exported theme variables
Detectors, providers, and handlers are auto-discovered by function name prefix or loaded from configuration files.
- -d, --detect
-
Only detect and print the system appearance (dark or light). Does not run the provider or handlers.
- -l, --list
-
List the discovered detectors, provider, and all registered handlers.
- -q, --quiet
-
Suppress warning messages.
- -h, --help
-
Show help message and exit.
- -V, --version
-
Show version information and exit.
- dark | light
-
Override the detected appearance. When specified, detection is skipped and this value is passed directly to the provider.
Detectors are user-provided shell functions that detect the system appearance. This allows users to implement detection for their specific system rather than relying on hardcoded methods.
Detectors must:
-
Be named with prefix
theme_detector_(e.g.,theme_detector_macos) -
Return 1 if detection doesn’t apply (wrong OS, missing tools)
-
Return 0 and set
THEME_APPEARANCE=darkorTHEME_APPEARANCE=lighton success
Detectors are discovered from:
-
Functions matching
theme_detector_*in current shell -
Functions defined in scripts under
~/.config/theme/detectors.d/*.sh
Detectors are tried in alphabetical order. The first one that returns 0 wins.
If no detector succeeds:
-
Uses
THEMEenvironment variable if set to "dark" or "light" -
Otherwise defaults to "light"
- macOS
-
theme_detector_macos() { [[ "$(uname -s)" == "Darwin" ]] || return 1 command -v defaults >/dev/null || return 1 if defaults read -g AppleInterfaceStyle 2>/dev/null | grep -qi dark; then THEME_APPEARANCE=dark else THEME_APPEARANCE=light fi }
- GNOME
-
theme_detector_gnome() { [[ "${XDG_CURRENT_DESKTOP:-}" == *GNOME* ]] || return 1 command -v gsettings >/dev/null || return 1 local scheme scheme=$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null) || return 1 case "$scheme" in *dark*) THEME_APPEARANCE=dark ;; *) THEME_APPEARANCE=light ;; esac }
- KDE Plasma
-
theme_detector_kde() { command -v kreadconfig5 >/dev/null || return 1 local scheme scheme=$(kreadconfig5 --file kdeglobals --group General --key ColorScheme 2>/dev/null) || return 1 case "${scheme,,}" in *dark*) THEME_APPEARANCE=dark ;; *) THEME_APPEARANCE=light ;; esac }
- Windows (WSL)
-
theme_detector_wsl() { [[ -n "${WSL_DISTRO_NAME:-}" ]] || return 1 command -v reg.exe >/dev/null || return 1 local result result=$(reg.exe query "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize" /v AppsUseLightTheme 2>/dev/null) || return 1 if [[ "$result" == *"0x0"* ]]; then THEME_APPEARANCE=dark else THEME_APPEARANCE=light fi }
A provider is a shell function that receives the detected appearance and exports theme variables for handlers to consume.
Providers must:
-
Be named with prefix
theme_provider_(e.g.,theme_provider_catppuccin) -
Accept two arguments:
$1= appearance (dark|light),$2= source (detected|default|override) -
Export
THEMEand any additional variables handlers need
Providers are discovered in order:
-
Functions matching
theme_provider_*in current shell -
Functions defined in
~/.config/theme/provider.sh
Only the first discovered provider is used.
Handlers are shell functions that configure individual tools using the theme variables exported by the provider.
Handlers must:
-
Be named with prefix
theme_handler_(e.g.,theme_handler_bat) -
Read configuration from
THEME_*environment variables -
Configure their target tool (export vars, write config files, etc.)
Handlers are discovered from:
-
Functions matching
theme_handler_*in current shell -
Functions defined in scripts under
~/.config/theme/handlers.d/*.sh
All discovered handlers are executed in alphabetical order.
theme_handler_bat() {
export BAT_THEME="Catppuccin ${THEME_VARIANT^}"
}
theme_handler_vivid() {
export LS_COLORS="$(vivid generate catppuccin-${THEME_VARIANT})"
}
theme_handler_fzf() {
if [[ "$THEME" == "dark" ]]; then
export FZF_DEFAULT_OPTS="--color=dark"
else
export FZF_DEFAULT_OPTS="--color=light"
fi
}- ~/.config/theme/config.sh
-
User configuration file. Sourced after detectors but before provider/handler discovery. Can be used to set default variables or configure behavior.
- ~/.config/theme/detectors.d/.sh*
-
Detector scripts. All
.shfiles in this directory are sourced first. Definetheme_detector_*functions to detect system appearance. - ~/.config/theme/provider.sh
-
Custom provider definition. Sourced during provider discovery.
- ~/.config/theme/handlers.d/.sh*
-
External handler scripts. All
.shfiles in this directory are sourced during handler discovery.
- THEME
-
Current theme appearance (dark or light). Set by the provider. Can also be set manually to override detection.
- THEME_VARIANT
-
Theme variant name (e.g., mocha, latte). Set by the provider.
- THEME_ACCENT
-
Accent color (e.g., blue, pink). Set by the provider.
Additional THEME_* variables may be exported by custom providers.
- 0
-
Success.
- 1
-
Runtime error (no provider found, detection failed).
- 2
-
Usage error (invalid arguments).
- Detect appearance and apply theme to all handlers
-
theme
- Force dark mode
-
theme dark
- Only detect appearance (no handlers)
-
theme --detect
- List discovered provider and handlers
-
theme --list
Add to shell configuration for automatic theming on startup:
# ~/.bashrc or ~/.zshrc
source /path/to/theme.sh
# Define detector (required - detection is user-provided)
theme_detector_macos() {
[[ "$(uname -s)" == "Darwin" ]] || return 1
if defaults read -g AppleInterfaceStyle 2>/dev/null | grep -qi dark; then
THEME_APPEARANCE=dark
else
THEME_APPEARANCE=light
fi
}
# Define provider
theme_provider_catppuccin() {
local appearance="$1"
export THEME="$appearance"
case "$appearance" in
dark) export THEME_VARIANT=mocha ;;
light) export THEME_VARIANT=latte ;;
esac
export THEME_ACCENT=blue
}
# Define handlers
theme_handler_bat() {
export BAT_THEME="Catppuccin ${THEME_VARIANT^}"
}
theme_handler_vivid() {
export LS_COLORS="$(vivid generate catppuccin-${THEME_VARIANT})"
}
# Apply theme on shell startup
theme