diff --git a/ansible/roles/developer-gui/files/ghostty/config b/ansible/roles/developer-gui/files/ghostty/config index 5b3ee09..f33fc7f 100644 --- a/ansible/roles/developer-gui/files/ghostty/config +++ b/ansible/roles/developer-gui/files/ghostty/config @@ -24,11 +24,32 @@ font-feature = +dlig # ============================================================ # Theme - Auto-switches with system light/dark mode # ============================================================ -# Solarized: vendored theme files in ./themes/ (self-contained - no reliance on -# Ghostty builtin themes or OS packages). Auto-switches light/dark with the OS. -# Upstream renamed/removed the "Builtin Solarized" names once already; vendoring -# means a future rename cannot break us. -theme = light:solarized-light,dark:solarized-dark +# Solarized: Ghostty's own bundled iTerm2 Solarized pair. These ship INSIDE +# Ghostty on every platform - macOS in Ghostty.app/Contents/Resources/ghostty/ +# themes/, Linux in /usr/share/ghostty/themes/ (owned by the ghostty package +# itself, verified with dpkg -S). No OS package, no vendored files, nothing to +# install. The "iTerm2" in the name is just upstream's naming from the +# iterm2-color-schemes collection - iTerm2 is NOT required. +# +# Auto-switches light/dark with the OS desktop appearance. +# +# We do NOT vendor a canonical Schoonover palette any more, for two reasons: +# +# 1. Vendored theme files only resolve from the XDG dir. macOS reads its +# CONFIG from ~/Library/Application Support/com.mitchellh.ghostty/ but +# resolves a bare theme NAME only from ~/.config/ghostty/themes/ and the +# app bundle. Themes deployed next to the macOS config were never found, +# and Ghostty silently fell back to its default dark theme. +# 2. The canonical palette is actively worse. It sets ANSI 8 to #002b36 - +# the exact dark background, so bright-black text was invisible - and +# ANSI 7 to #eee8d5 against the #fdf6e3 light background. The iTerm2 +# variant lifts both off the background (#335e69 / #bbb5a2) and is +# otherwise identical to canonical Solarized. +# +# TRADEOFF: upstream renamed "Builtin Solarized" out from under us once +# before. If the theme stops applying after a Ghostty upgrade, check +# `ghostty +list-themes` for the current name. +theme = light:iTerm2 Solarized Light,dark:iTerm2 Solarized Dark # ============================================================ # Terminal Compatibility diff --git a/ansible/roles/developer-gui/files/ghostty/themes/solarized-dark b/ansible/roles/developer-gui/files/ghostty/themes/solarized-dark deleted file mode 100644 index f3ca9be..0000000 --- a/ansible/roles/developer-gui/files/ghostty/themes/solarized-dark +++ /dev/null @@ -1,25 +0,0 @@ -# Solarized Dark — self-contained Ghostty theme (hyperi-developer) -# Canonical Solarized palette by Ethan Schoonover (https://ethanschoonover.com/solarized) -# Vendored so the install never depends on Ghostty's builtin themes or OS packages. -palette = 0=#073642 -palette = 1=#dc322f -palette = 2=#859900 -palette = 3=#b58900 -palette = 4=#268bd2 -palette = 5=#d33682 -palette = 6=#2aa198 -palette = 7=#eee8d5 -palette = 8=#002b36 -palette = 9=#cb4b16 -palette = 10=#586e75 -palette = 11=#657b83 -palette = 12=#839496 -palette = 13=#6c71c4 -palette = 14=#93a1a1 -palette = 15=#fdf6e3 -background = #002b36 -foreground = #839496 -cursor-color = #839496 -cursor-text = #002b36 -selection-background = #073642 -selection-foreground = #93a1a1 diff --git a/ansible/roles/developer-gui/files/ghostty/themes/solarized-light b/ansible/roles/developer-gui/files/ghostty/themes/solarized-light deleted file mode 100644 index 9450d59..0000000 --- a/ansible/roles/developer-gui/files/ghostty/themes/solarized-light +++ /dev/null @@ -1,25 +0,0 @@ -# Solarized Light — self-contained Ghostty theme (hyperi-developer) -# Canonical Solarized palette by Ethan Schoonover (https://ethanschoonover.com/solarized) -# Vendored so the install never depends on Ghostty's builtin themes or OS packages. -palette = 0=#073642 -palette = 1=#dc322f -palette = 2=#859900 -palette = 3=#b58900 -palette = 4=#268bd2 -palette = 5=#d33682 -palette = 6=#2aa198 -palette = 7=#eee8d5 -palette = 8=#002b36 -palette = 9=#cb4b16 -palette = 10=#586e75 -palette = 11=#657b83 -palette = 12=#839496 -palette = 13=#6c71c4 -palette = 14=#93a1a1 -palette = 15=#fdf6e3 -background = #fdf6e3 -foreground = #657b83 -cursor-color = #657b83 -cursor-text = #fdf6e3 -selection-background = #eee8d5 -selection-foreground = #586e75 diff --git a/ansible/roles/developer-gui/tasks/ghostty.yml b/ansible/roles/developer-gui/tasks/ghostty.yml index 21809b4..a44c34c 100644 --- a/ansible/roles/developer-gui/tasks/ghostty.yml +++ b/ansible/roles/developer-gui/tasks/ghostty.yml @@ -132,14 +132,6 @@ mode: '0644' when: ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] -# Vendored Solarized themes - always refreshed (managed files, not user-edited) -- name: Deploy Ghostty themes (Linux skel) - ansible.builtin.copy: - src: ghostty/themes/ - dest: "{{ ghostty_skel_dir }}/themes/" - mode: '0644' - when: ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] - # Deploy to current user as well (Linux) - name: Create Ghostty config directory for actual user (Linux) ansible.builtin.file: @@ -170,26 +162,37 @@ force: false when: ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] -- name: Deploy Ghostty themes for actual user (Linux) - ansible.builtin.copy: - src: ghostty/themes/ - dest: "{{ user_home }}/.config/ghostty/themes/" - mode: '0644' - owner: "{{ actual_user }}" - group: "{{ actual_user }}" - when: ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] - # Heal existing configs: the base config ships with force:false to preserve user -# edits, so older installs keep their (broken) builtin Solarized theme line. This -# rewrites just that line to the vendored themes without touching anything else. +# edits, so older installs keep a stale theme line - either the long-dead +# "Builtin Solarized *" names or the vendored "solarized-light/dark" ones. This +# rewrites just that line to the bundled themes without touching anything else. +# +# The regexp matches the replacement too, so this is idempotent: a config +# already on the new line is rewritten to the identical string and ansible +# reports ok, not changed. - name: Fix stale Ghostty Solarized theme line in existing user config (Linux) ansible.builtin.replace: path: "{{ user_home }}/.config/ghostty/config" - regexp: '^theme\s*=.*Solarized.*$' - replace: 'theme = light:solarized-light,dark:solarized-dark' + regexp: '^theme\s*=.*[Ss]olarized.*$' + replace: 'theme = light:iTerm2 Solarized Light,dark:iTerm2 Solarized Dark' failed_when: false when: ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] +# Remove the vendored theme files left behind by earlier runs of this role. +# Ghostty now uses its own bundled iTerm2 Solarized pair, so these are dead +# files - and leaving them means a stale theme silently wins if anyone still +# has a "solarized-light" line in a config we did not heal. +- name: Remove retired vendored Ghostty themes (Linux) + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - "{{ user_home }}/.config/ghostty/themes/solarized-light" + - "{{ user_home }}/.config/ghostty/themes/solarized-dark" + - "{{ ghostty_skel_dir }}/themes/solarized-light" + - "{{ ghostty_skel_dir }}/themes/solarized-dark" + when: ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] + # ============================================================ # macOS Configuration Deployment # ============================================================ @@ -217,11 +220,19 @@ become: false when: ansible_facts['distribution'] == 'MacOSX' -- name: Deploy Ghostty themes (macOS) - ansible.builtin.copy: - src: ghostty/themes/ - dest: "{{ ghostty_macos_dir }}/themes/" - mode: '0644' +# No theme deployment on macOS. Ghostty resolves a bare theme NAME from +# ~/.config/ghostty/themes/ and the app bundle only - never from the macOS +# Application Support dir where its config lives. Themes copied here were +# therefore never found, which is exactly the bug this change retires. +# +# Clean up the files earlier runs left in that dead directory. +- name: Remove retired vendored Ghostty themes (macOS) + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - "{{ ghostty_macos_dir }}/themes/solarized-light" + - "{{ ghostty_macos_dir }}/themes/solarized-dark" become: false when: ansible_facts['distribution'] == 'MacOSX'