From 67128fe09b31a29ca77034c2783a7e0fc64f8cd1 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Fri, 20 Mar 2026 15:37:34 -0400 Subject: [PATCH] theme dark:light --- config/nvim/lua/theme.lua | 12 ++++-- home/ghostty.nix | 2 +- home/scripts.nix | 5 ++- home/zsh.nix | 88 +++++++++++++++++++++++++++++++++++++++ lib/theme.nix | 81 ++++++++++++++++++++++------------- scripts/default.nix | 6 ++- scripts/theme.sh | 36 ++++++++++++++-- 7 files changed, 190 insertions(+), 40 deletions(-) diff --git a/config/nvim/lua/theme.lua b/config/nvim/lua/theme.lua index 8f90d8c..62016a7 100644 --- a/config/nvim/lua/theme.lua +++ b/config/nvim/lua/theme.lua @@ -7,11 +7,16 @@ local active_schemes = { } local function ensure_server_socket() - if vim.v.servername ~= nil and vim.v.servername ~= "" then - return + local socket_path = ("/tmp/nvim-%d.sock"):format(vim.fn.getpid()) + local active_servers = vim.fn.serverlist() + + for _, server in ipairs(active_servers) do + if server == socket_path then return end end - local socket_path = ("/tmp/nvim-%d.sock"):format(vim.fn.getpid()) + local stat = vim.uv.fs_stat(socket_path) + if stat and stat.type == "socket" then vim.fn.delete(socket_path) end + vim.fn.serverstart(socket_path) end @@ -55,6 +60,7 @@ function M.apply(mode) vim.g.cozybox_theme_mode = next_mode apply_cozybox_overrides() + vim.schedule(function() pcall(vim.cmd, "redraw!") end) end function M.setup() diff --git a/home/ghostty.nix b/home/ghostty.nix index 150f608..13e359b 100644 --- a/home/ghostty.nix +++ b/home/ghostty.nix @@ -5,7 +5,7 @@ }: let theme = import ../lib/theme.nix {inherit config;}; ghosttyConfig = '' - theme = "dark:cozybox-dark,light:cozybox-light" + theme = "cozybox-current" font-family = Berkeley Mono font-codepoint-map = U+f101-U+f25c=nonicons background-opacity = 1 diff --git a/home/scripts.nix b/home/scripts.nix index 070b2ff..2e7a5c2 100644 --- a/home/scripts.nix +++ b/home/scripts.nix @@ -9,7 +9,7 @@ in { home.packages = builtins.attrValues customScripts.packages; home.activation.initializeThemeState = lib.hm.dag.entryAfter ["writeBoundary"] '' - mkdir -p "${customScripts.theme.paths.stateDir}" "${customScripts.theme.paths.tmuxDir}" + mkdir -p "${customScripts.theme.paths.stateDir}" "${customScripts.theme.paths.ghosttyDir}" "${customScripts.theme.paths.tmuxDir}" if [[ -f "${customScripts.theme.paths.stateFile}" ]]; then mode=$(tr -d '[:space:]' < "${customScripts.theme.paths.stateFile}") @@ -20,14 +20,17 @@ in { case "$mode" in light) + ghostty_target="${customScripts.theme.paths.ghosttyDir}/cozybox-light" tmux_target="${customScripts.tmuxConfigs.light}" ;; *) printf '%s\n' "${customScripts.theme.defaultMode}" > "${customScripts.theme.paths.stateFile}" + ghostty_target="${customScripts.theme.paths.ghosttyDir}/cozybox-dark" tmux_target="${customScripts.tmuxConfigs.dark}" ;; esac + ln -sfn "$ghostty_target" "${customScripts.theme.paths.ghosttyCurrentFile}" ln -sfn "$tmux_target" "${customScripts.theme.paths.tmuxCurrentFile}" ''; } diff --git a/home/zsh.nix b/home/zsh.nix index 358e442..effccd1 100644 --- a/home/zsh.nix +++ b/home/zsh.nix @@ -108,6 +108,91 @@ $path ) + _codex_read_theme_mode() { + local mode_file="$HOME/.local/state/theme/current" + if [[ -f "$mode_file" ]]; then + local mode + mode=$(tr -d '[:space:]' < "$mode_file") + if [[ "$mode" == light || "$mode" == dark ]]; then + printf '%s' "$mode" + return + fi + fi + + printf 'dark' + } + + _codex_apply_highlight_styles() { + local mode="$(_codex_read_theme_mode)" + if [[ "$mode" == "''${_CODEX_LAST_HIGHLIGHT_THEME:-}" ]]; then + return + fi + + typeset -gA ZSH_HIGHLIGHT_STYLES + + if [[ "$mode" == light ]]; then + ZSH_HIGHLIGHT_STYLES[arg0]='fg=#427b58' + ZSH_HIGHLIGHT_STYLES[autodirectory]='fg=#427b58,underline' + ZSH_HIGHLIGHT_STYLES[back-dollar-quoted-argument]='fg=#076678' + ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]='fg=#076678' + ZSH_HIGHLIGHT_STYLES[back-quoted-argument-delimiter]='fg=#8f3f71' + ZSH_HIGHLIGHT_STYLES[bracket-error]='fg=#ea6962,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-1]='fg=#076678,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-2]='fg=#427b58,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-3]='fg=#8f3f71,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-4]='fg=#b57614,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-5]='fg=#076678,bold' + ZSH_HIGHLIGHT_STYLES[comment]='fg=#928374' + ZSH_HIGHLIGHT_STYLES[command-substitution-delimiter]='fg=#8f3f71' + ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]='fg=#076678' + ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=#b57614' + ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=#b57614' + ZSH_HIGHLIGHT_STYLES[global-alias]='fg=#076678' + ZSH_HIGHLIGHT_STYLES[globbing]='fg=#076678' + ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=#076678' + ZSH_HIGHLIGHT_STYLES[path]='fg=#3c3836,underline' + ZSH_HIGHLIGHT_STYLES[precommand]='fg=#427b58,underline' + ZSH_HIGHLIGHT_STYLES[process-substitution-delimiter]='fg=#8f3f71' + ZSH_HIGHLIGHT_STYLES[rc-quote]='fg=#076678' + ZSH_HIGHLIGHT_STYLES[redirection]='fg=#b57614' + ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=#b57614' + ZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=#b57614' + ZSH_HIGHLIGHT_STYLES[suffix-alias]='fg=#427b58,underline' + ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#ea6962,bold' + else + ZSH_HIGHLIGHT_STYLES[arg0]='fg=#8ec97c' + ZSH_HIGHLIGHT_STYLES[autodirectory]='fg=#8ec97c,underline' + ZSH_HIGHLIGHT_STYLES[back-dollar-quoted-argument]='fg=#8ec07c' + ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]='fg=#8ec07c' + ZSH_HIGHLIGHT_STYLES[back-quoted-argument-delimiter]='fg=#d3869b' + ZSH_HIGHLIGHT_STYLES[bracket-error]='fg=#ea6962,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-1]='fg=#5b84de,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-2]='fg=#8ec97c,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-3]='fg=#d3869b,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-4]='fg=#d8a657,bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-5]='fg=#8ec07c,bold' + ZSH_HIGHLIGHT_STYLES[comment]='fg=#7c6f64' + ZSH_HIGHLIGHT_STYLES[command-substitution-delimiter]='fg=#d3869b' + ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]='fg=#8ec07c' + ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=#d8a657' + ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=#d8a657' + ZSH_HIGHLIGHT_STYLES[global-alias]='fg=#8ec07c' + ZSH_HIGHLIGHT_STYLES[globbing]='fg=#5b84de' + ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=#5b84de' + ZSH_HIGHLIGHT_STYLES[path]='fg=#d4be98,underline' + ZSH_HIGHLIGHT_STYLES[precommand]='fg=#8ec97c,underline' + ZSH_HIGHLIGHT_STYLES[process-substitution-delimiter]='fg=#d3869b' + ZSH_HIGHLIGHT_STYLES[rc-quote]='fg=#8ec07c' + ZSH_HIGHLIGHT_STYLES[redirection]='fg=#d8a657' + ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=#d8a657' + ZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=#d8a657' + ZSH_HIGHLIGHT_STYLES[suffix-alias]='fg=#8ec97c,underline' + ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#ea6962,bold' + fi + + typeset -g _CODEX_LAST_HIGHLIGHT_THEME="$mode" + } + unalias ga 2>/dev/null git() { @@ -153,6 +238,7 @@ zle -N zle-line-finish precmd() { + _codex_apply_highlight_styles _codex_set_cursor beam } @@ -160,6 +246,8 @@ _codex_set_cursor beam } + _codex_apply_highlight_styles + if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init zsh)" fi diff --git a/lib/theme.nix b/lib/theme.nix index 1e1b2fb..1e832ec 100644 --- a/lib/theme.nix +++ b/lib/theme.nix @@ -4,71 +4,92 @@ stateDir = "${config.xdg.stateHome}/theme"; stateFile = "${config.xdg.stateHome}/theme/current"; ghosttyDir = "${config.xdg.configHome}/ghostty/themes"; - ghosttyCurrentFile = "${config.xdg.configHome}/ghostty/themes/current.conf"; + ghosttyCurrentFile = "${config.xdg.configHome}/ghostty/themes/cozybox-current"; tmuxDir = "${config.xdg.configHome}/tmux/theme"; tmuxCurrentFile = "${config.xdg.configHome}/tmux/theme/current.conf"; }; themes = { dark = { - ghosttyTheme = "Gruvbox Material Dark"; background = "#181818"; surface = "#1e1e1e"; selectionBackground = "#504945"; selectionForeground = "#ebdbb2"; cursorColor = "#ddc7a1"; + cursorText = "#181818"; + foreground = "#ebdbb2"; text = "#d4be98"; mutedText = "#7c6f64"; - red = "#ea6962"; - green = "#8ec97c"; - yellow = "#d8a657"; - blue = "#5b84de"; - aqua = "#8ec07c"; purple = "#d3869b"; - orange = "#e78a4e"; border = "#181818"; + palette = [ + "#1d2021" + "#ea6962" + "#8ec97c" + "#d79921" + "#5b84de" + "#b16286" + "#689d6a" + "#a89984" + "#928374" + "#ea6962" + "#8ec97c" + "#fabd2f" + "#5b84de" + "#d3869b" + "#8ec07c" + "#ebdbb2" + ]; }; light = { - ghosttyTheme = "Gruvbox Material Light"; background = "#e7e7e7"; surface = "#e1e1e1"; selectionBackground = "#c3c7c9"; - selectionForeground = "#1d2021"; + selectionForeground = "#3c3836"; cursorColor = "#282828"; - text = "#282828"; + cursorText = "#e7e7e7"; + foreground = "#3c3836"; + text = "#3c3836"; mutedText = "#665c54"; - red = "#ea6962"; - green = "#8ec97c"; - yellow = "#d8a657"; - blue = "#5b84de"; - aqua = "#8ec07c"; purple = "#d3869b"; - orange = "#e78a4e"; border = "#c3c7c9"; + palette = [ + "#f9f5d7" + "#ea6962" + "#8ec97c" + "#d8a657" + "#5b84de" + "#d3869b" + "#8ec07c" + "#7c6f64" + "#928374" + "#ea6962" + "#8ec97c" + "#d8a657" + "#5b84de" + "#d3869b" + "#8ec07c" + "#3c3836" + ]; }; }; renderGhostty = mode: let theme = themes.${mode}; + paletteLines = + builtins.concatStringsSep "\n" + (builtins.genList + (index: "palette = ${toString index}=${builtins.elemAt theme.palette index}") + (builtins.length theme.palette)); in '' - theme = "${theme.ghosttyTheme}" background = ${theme.background} + foreground = ${theme.foreground} cursor-color = ${theme.cursorColor} + cursor-text = ${theme.cursorText} selection-background = ${theme.selectionBackground} selection-foreground = ${theme.selectionForeground} - palette = 1=${theme.red} - palette = 2=${theme.green} - palette = 3=${theme.yellow} - palette = 4=${theme.blue} - palette = 5=${theme.purple} - palette = 6=${theme.aqua} - palette = 9=${theme.red} - palette = 10=${theme.green} - palette = 11=${theme.yellow} - palette = 12=${theme.blue} - palette = 13=${theme.purple} - palette = 14=${theme.aqua} + ${paletteLines} ''; renderTmux = mode: let diff --git a/scripts/default.nix b/scripts/default.nix index 83e5ea9..9a73fa5 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -64,11 +64,15 @@ theme = mkScript { name = "theme"; file = ./theme.sh; - runtimeInputs = with pkgs; [coreutils neovim tmux]; + runtimeInputs = with pkgs; [coreutils findutils neovim tmux]; replacements = { "@DEFAULT_MODE@" = theme.defaultMode; "@STATE_DIR@" = theme.paths.stateDir; "@STATE_FILE@" = theme.paths.stateFile; + "@GHOSTTY_DIR@" = theme.paths.ghosttyDir; + "@GHOSTTY_CURRENT_FILE@" = theme.paths.ghosttyCurrentFile; + "@GHOSTTY_DARK_FILE@" = "${theme.paths.ghosttyDir}/cozybox-dark"; + "@GHOSTTY_LIGHT_FILE@" = "${theme.paths.ghosttyDir}/cozybox-light"; "@TMUX_DIR@" = theme.paths.tmuxDir; "@TMUX_CURRENT_FILE@" = theme.paths.tmuxCurrentFile; "@TMUX_DARK_FILE@" = "${tmuxConfigs.dark}"; diff --git a/scripts/theme.sh b/scripts/theme.sh index 05ff252..972c2f6 100644 --- a/scripts/theme.sh +++ b/scripts/theme.sh @@ -16,14 +16,20 @@ read_mode() { link_mode_assets() { local mode="$1" + local ghostty_target local tmux_target + local apple_dark_mode case "$mode" in dark) + ghostty_target="@GHOSTTY_DARK_FILE@" tmux_target="@TMUX_DARK_FILE@" + apple_dark_mode=true ;; light) + ghostty_target="@GHOSTTY_LIGHT_FILE@" tmux_target="@TMUX_LIGHT_FILE@" + apple_dark_mode=false ;; *) echo "invalid mode: $mode" >&2 @@ -31,18 +37,40 @@ link_mode_assets() { ;; esac - mkdir -p "@STATE_DIR@" "@TMUX_DIR@" + mkdir -p "@STATE_DIR@" "@GHOSTTY_DIR@" "@TMUX_DIR@" printf '%s\n' "$mode" > "@STATE_FILE@" + ln -sfn "$ghostty_target" "@GHOSTTY_CURRENT_FILE@" ln -sfn "$tmux_target" "@TMUX_CURRENT_FILE@" if command -v tmux >/dev/null 2>&1 && tmux start-server >/dev/null 2>&1; then tmux source-file "@TMUX_CONFIG@" >/dev/null 2>&1 || true fi - for socket in /tmp/nvim-*.sock; do + if [[ "$(uname -s)" == "Darwin" ]] && command -v osascript >/dev/null 2>&1; then + osascript -e "tell application \"System Events\" to tell appearance preferences to set dark mode to ${apple_dark_mode}" >/dev/null 2>&1 || true + + osascript <<'EOF' >/dev/null 2>&1 || true +tell application "System Events" + if not (exists process "Ghostty") then + return + end if + + tell process "Ghostty" + click menu item "Reload Configuration" of menu 1 of menu bar item "Ghostty" of menu bar 1 + end tell +end tell +EOF + fi + + while IFS= read -r socket; do [[ -S "$socket" ]] || continue - nvim --server "$socket" --remote-send "ThemeSync $mode" >/dev/null 2>&1 || true - done + nvim --server "$socket" --remote-expr "execute('ThemeSync $mode')" >/dev/null 2>&1 || true + done < <( + { + find /tmp -maxdepth 1 -type s -name 'nvim-*.sock' 2>/dev/null + find "${TMPDIR:-/tmp}" -type s -path "*/nvim.${USER}/*/nvim.*" 2>/dev/null + } | sort -u + ) } mode="${1:-current}"