#!/usr/bin/env nu
const THEME_CONFIG = "/home/jam/nixos/modules/theme.json"
const THEME_PYWAL = "/home/jam/nixos/modules/theme-pywal-colors.json"
const PYWAL_CONFIG = "/home/jam/.cache/wal/colors.json"
const REBUILD_SCRIPT = "/home/jam/nixos/rebuild.nu"
const HIGH_SAT = 0.75
const MID_SAT = 0.5
def print-notify [message: string] {
print $"(ansi purple)[Theme Switcher](ansi rst) ($message)"
try { notify-send "Theme Switcher" $message }
}
def attempt-rebuild [] {
try { nu $REBUILD_SCRIPT } catch { exit 1 }
}
def get-current-wallpaper [] {
let wallpaper = swww query
| lines
| first
| parse "{monitor}: image: {path}"
| get --optional path.0
if ($wallpaper | path exists) {
$wallpaper
} else {
""
}
}
def save-theme-config [mode: string, scheme: string] {
{mode: $mode scheme: $scheme}
| to json
| save --force $THEME_CONFIG
}
def update-gsettings [is_dark: bool] {
let scheme = if $is_dark { "prefer-dark" } else { "default" }
try { dconf write /org/gnome/desktop/interface/color-scheme $"'($scheme)'" }
}
def get-current-theme [] {
try {
open $THEME_CONFIG
} catch {
print-notify "Failed to load default config, falling back to light/gruvbox"
{mode: dark, scheme: gruvbox}
}
}
def is-current [mode_or_scheme: string] {
let current = get-current-theme
if (($current.mode == $mode_or_scheme) or ($current.scheme == $mode_or_scheme)) {
print-notify "Current theme and scheme already matches the desired settings."
exit 0
}
}
def generate-pywal-colors [
wallpaper: string
is_dark: bool
]: nothing -> nothing {
rm --recursive --force ($PYWAL_CONFIG | path dirname)
let mode_args = if $is_dark {
[ "--saturate" $MID_SAT ]
} else {
[ "--saturate" $HIGH_SAT "-l" ]
}
let args = [ "-n" "--backend" wal "-i" $wallpaper ] | append mode_args
wal ...$args | ignore
cp $PYWAL_CONFIG $THEME_PYWAL
}
def toggle-theme [theme: string] {
let theme_config = get-current-theme
print-notify $"Switching to ($theme) theme."
if $theme_config.scheme == pywal {
print-notify "Regenerating pywal colors..."
let wallpaper = get-current-wallpaper
if ($wallpaper | is-not-empty) {
generate-pywal-colors $wallpaper ($theme == dark)
} else {
print-notify "Warning: Could not detect current wallpaper"
}
}
print-notify "Updating theme configuration..."
$env.THEME_MODE = $theme
save-theme-config $theme $theme_config.scheme
update-gsettings ($theme == dark)
print-notify $"Switch to the ($theme) theme completed!"
}
def switch-scheme [scheme: string] {
print-notify $"Switching to ($scheme) color scheme."
let theme_config = get-current-theme
if $scheme == pywal {
print-notify "Generating pywal colors from current wallpaper..."
let wallpaper = get-current-wallpaper
if ($wallpaper | is-not-empty) {
generate-pywal-colors $wallpaper ($theme_config.mode == dark)
} else {
print-notify "Warning: Could not detect current wallpaper"
}
}
$env.THEME_SCHEME = $scheme
save-theme-config $theme_config.mode $scheme
print-notify $"Switch to ($scheme) scheme completed!"
}
def reload-applications [] {
print-notify "Reloading applications..."
niri msg action do-screen-transition --delay-ms 0 | ignore
pkill -USR1 kitty | ignore
pkill -USR2 ghostty | ignore
pkill -USR1 hx | ignore
systemctl --user restart mako | ignore
makoctl reload | ignore
pkill -SIGTERM brave | ignore
sleep 1sec
niri msg action do-screen-transition --delay-ms 500 | ignore
niri msg action spawn -- brave | ignore
}
def main [] {
print $"Usage: tt <dark|light|pywal|gruvbox|reload>
dark - Switch to dark mode
light - Switch to light mode
pywal - Use generated pywal colours from wallpaper
gruvbox - Use the gruvbox theme
reload - Reload applications"
}
def "main dark" [--force] {
if not $force { is-current dark }
toggle-theme dark
main reload
}
def "main light" [--force] {
if not $force { is-current light }
toggle-theme light
main reload
}
def "main gruvbox" [--force] {
if not $force { is-current gruvbox }
toggle-scheme gruvbox
main reload
}
def "main pywal" [--force] {
if not $force { is-current pywal }
toggle-scheme pywal
main reload
}
def "main reload" [] {
attempt-rebuild
reload-applications
}