From a15f2238aa71b25f59e365810d1beeed1304ade5 Mon Sep 17 00:00:00 2001 From: Martin Larsson Date: Fri, 25 Jul 2025 11:44:53 +0200 Subject: [PATCH] feature: Add automated colorscheme switching to Ghostty, refactor watchman_tmux into generic utility function. --- .gitignore | 1 + ghostty/config | 5 +- ghostty/ghostty-change-theme.sh | 37 +++++++++ .../common/watchman_colorsync_services.nix | 39 +++++++++ nix/home/common/watchman_tmux.nix | 66 --------------- nix/home/default.nix | 2 +- nix/utils.nix | 82 +++++++++++++++++++ 7 files changed, 164 insertions(+), 68 deletions(-) create mode 100755 ghostty/ghostty-change-theme.sh create mode 100644 nix/home/common/watchman_colorsync_services.nix delete mode 100644 nix/home/common/watchman_tmux.nix diff --git a/.gitignore b/.gitignore index 56aba49..b4e75bb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ home/.config/lazygit/state.yml neomuttrc.local karabiner/automatic_backups/ result +colorsync_ghostty_theme diff --git a/ghostty/config b/ghostty/config index 1996113..662c184 100644 --- a/ghostty/config +++ b/ghostty/config @@ -35,7 +35,10 @@ clipboard-paste-protection = false window-decoration = false shell-integration = zsh -theme = Ayu Mirage +# This is the default fallback theme. This is only used +# if the colorsync handled theme file doesn't exist. +theme = Ayu +config-file = ?colorsync_ghostty_theme background-opacity = 1.0 background-blur-radius = 7 diff --git a/ghostty/ghostty-change-theme.sh b/ghostty/ghostty-change-theme.sh new file mode 100755 index 0000000..3780f7d --- /dev/null +++ b/ghostty/ghostty-change-theme.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +THEME=$(colorsync get) + +OUTPUT="$HOME/.config/ghostty/colorsync_ghostty_theme" + +default() { + printf "theme = Ayu" > "$OUTPUT" +} + +case "$THEME" in + ayudark) + default + ;; + ayumirage) + printf "theme = Ayu Mirage" > "$OUTPUT" + ;; + ayulight) + printf "theme = ayu_light" > "$OUTPUT" + ;; + *) + default + ;; +esac + +# once SIGUSR2 is merged in Ghostty, just replace the keystroke hack with pkill -USR2 ghostty +case "$(uname)" in + Darwin) + osascript -e 'tell application "System Events" to keystroke "," using {command down, shift down}' + ;; + Linux) + wtype -M ctrl -M shift , -m shift -m ctrl + ;; + *) + echo "Unsupported OS" + ;; +esac diff --git a/nix/home/common/watchman_colorsync_services.nix b/nix/home/common/watchman_colorsync_services.nix new file mode 100644 index 0000000..1f58daf --- /dev/null +++ b/nix/home/common/watchman_colorsync_services.nix @@ -0,0 +1,39 @@ +{ + pkgs, + lib, + config, + isLinux, + isDarwin, + ... +}: +let + utils = import ../../utils.nix; +in +lib.mkMerge [ + (utils.mkWatchmanTrigger { + inherit + pkgs + lib + config + isLinux + isDarwin + ; + name = "ghostty"; + triggerName = "ghostty_theme"; + scriptPath = "$HOME/.config/ghostty/ghostty-change-theme.sh"; + description = "Register watchman trigger for Ghostty themes."; + }) + (utils.mkWatchmanTrigger { + inherit + pkgs + lib + config + isLinux + isDarwin + ; + name = "tmux"; + triggerName = "tmux_statusbar_color"; + scriptPath = "$HOME/.config/tmux/tmux-statusbar-color.sh"; + description = "Register watchman trigger for Tmux statusbar colors."; + }) +] diff --git a/nix/home/common/watchman_tmux.nix b/nix/home/common/watchman_tmux.nix deleted file mode 100644 index 421b056..0000000 --- a/nix/home/common/watchman_tmux.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ - pkgs, - lib, - config, - isLinux, - isDarwin, - ... -}: - -let - scriptPkg = pkgs.writeShellScriptBin "tmux-watchman-statuscolor" '' - set -euo pipefail - - ROOT="$HOME/.local/state/colorsync" - TRIGGER_NAME="tmux_statusbar_color" - SCRIPT="$HOME/.config/tmux/tmux-statusbar-color.sh" - WATCHMAN="${pkgs.watchman}/bin/watchman" - - "$WATCHMAN" -- watch-project "$ROOT" >/dev/null - "$WATCHMAN" -- trigger-del "$ROOT" "$TRIGGER_NAME" >/dev/null 2>&1 || true - "$WATCHMAN" -- trigger "$ROOT" "$TRIGGER_NAME" current -- bash "$SCRIPT" - ''; - - pathForService = lib.makeBinPath [ - pkgs.watchman - pkgs.bash - pkgs.coreutils - ]; - - linuxAttrs = lib.optionalAttrs isLinux { - systemd.user.startServices = "sd-switch"; - systemd.user.services.tmux-watchman = { - Unit = { - Description = "Register watchman trigger for tmux statusbar color"; - After = [ "graphical-session.target" ]; - }; - Service = { - Type = "oneshot"; - ExecStart = "${scriptPkg}/bin/tmux-watchman-statuscolor"; - Environment = [ "PATH=${pathForService}" ]; - StandardOutput = "journal"; - StandardError = "journal"; - }; - Install = { - WantedBy = [ "default.target" ]; - }; - }; - }; - - darwinAttrs = lib.optionalAttrs isDarwin { - launchd.agents.tmux-watchman = { - enable = true; - config = { - ProgramArguments = [ "${scriptPkg}/bin/tmux-watchman-statuscolor" ]; - RunAtLoad = true; - KeepAlive = false; - EnvironmentVariables = { - PATH = pathForService; - }; - StandardOutPath = "${config.home.homeDirectory}/Library/Logs/tmux-watchman.log"; - StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/tmux-watchman.err"; - }; - }; - }; -in -linuxAttrs // darwinAttrs diff --git a/nix/home/default.nix b/nix/home/default.nix index 29f052c..b8eeb75 100644 --- a/nix/home/default.nix +++ b/nix/home/default.nix @@ -67,7 +67,7 @@ let in { imports = [ - ./common/watchman_tmux.nix + ./common/watchman_colorsync_services.nix ./common/firefox.nix ]; diff --git a/nix/utils.nix b/nix/utils.nix index 8a0a3c9..a7a1a89 100644 --- a/nix/utils.nix +++ b/nix/utils.nix @@ -46,4 +46,86 @@ rec { ${pkgs.mkalias}/bin/mkalias "$src" "${outputDir}/$app_name" done ''; + + mkWatchmanTrigger = + { + pkgs, + lib, + config, + isLinux, + isDarwin, + + name, + triggerName, + scriptPath, + + root ? "$HOME/.local/state/colorsync", + description ? "Register watchman trigger for ${name}.", + watchExpr ? "current", + }: + let + serviceName = "${name}-watchman"; + # e.g. tmux-watchman-statuscolor, ghostty-watchman-theme + binName = + let + trig = lib.replaceStrings [ "_" ] [ "-" ] triggerName; + in + "${serviceName}-${trig}"; + + scriptPkg = pkgs.writeShellScriptBin binName '' + set -euo pipefail + + ROOT="${root}" + TRIGGER_NAME="${triggerName}" + SCRIPT="${scriptPath}" + WATCHMAN="${pkgs.watchman}/bin/watchman" + + "$WATCHMAN" -- watch-project "$ROOT" >/dev/null + "$WATCHMAN" -- trigger-del "$ROOT" "$TRIGGER_NAME" >/dev/null 2>&1 || true + "$WATCHMAN" -- trigger "$ROOT" "$TRIGGER_NAME" ${watchExpr} -- bash "$SCRIPT" + ''; + + pathForService = lib.makeBinPath [ + pkgs.watchman + pkgs.bash + pkgs.coreutils + ]; + + linuxAttrs = lib.optionalAttrs isLinux { + systemd.user.startServices = "sd-switch"; + systemd.user.services."${serviceName}" = { + Unit = { + Description = description; + After = [ "graphical-session.target" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${scriptPkg}/bin/${binName}"; + Environment = [ "PATH=${pathForService}" ]; + StandardOutput = "journal"; + StandardError = "journal"; + }; + Install = { + WantedBy = [ "default.target" ]; + }; + }; + }; + + darwinAttrs = lib.optionalAttrs isDarwin { + launchd.agents."${serviceName}" = { + enable = true; + config = { + ProgramArguments = [ "${scriptPkg}/bin/${binName}" ]; + RunAtLoad = true; + KeepAlive = false; + EnvironmentVariables = { + PATH = pathForService; + }; + StandardOutPath = "${config.home.homeDirectory}/Library/Logs/${serviceName}.log"; + StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/${serviceName}.err"; + }; + }; + }; + in + linuxAttrs // darwinAttrs; }