alphabaster: add light theme, draw nvim in terminal colors
Rex never reports its background to programs, so nvim uses terminal slot
numbers instead of hex and follows whichever theme Rex has loaded.

Assisted-by: Claude Opus 5.5 via Claude Code
change upluqpnnylnxuzuuznswqtqsmpppupmp
commit 89872705a756999e87d186ab1103db43f913b430
author Alpha Chen <alpha@kejadlen.dev>
date
parent vtlvxvzy
diff --git a/.config/ghostty/config b/.config/ghostty/config
index 7a97cac8..8848f1f2 100644
--- a/.config/ghostty/config
+++ b/.config/ghostty/config
@@ -21,6 +21,11 @@ palette = 13=#EDBBE0
 palette = 14=#B6E2EA
 palette = 15=#FFFFFF
 
+# Fills for alphabaster in nvim; see .config/nvim/fnl/alphabaster/README.md.
+palette = 60=#626880
+palette = 235=#282A36
+palette = 236=#333333
+
 cursor-color = #f2d5cf
 cursor-text = #121218
 selection-background = #626880
diff --git a/.config/ghostty/themes/alphabaster b/.config/ghostty/themes/alphabaster
index fb32fcf0..61e8da5f 100644
--- a/.config/ghostty/themes/alphabaster
+++ b/.config/ghostty/themes/alphabaster
@@ -20,3 +20,6 @@ cursor-color = #f2d5cf
 cursor-text = #121218
 selection-background = #626880
 selection-foreground = #F0F0E4
+palette = 60=#626880
+palette = 235=#282A36
+palette = 236=#333333
diff --git a/.config/ghostty/themes/alphabaster-light b/.config/ghostty/themes/alphabaster-light
new file mode 100644
index 00000000..3485feee
--- /dev/null
+++ b/.config/ghostty/themes/alphabaster-light
@@ -0,0 +1,25 @@
+background = #FCFCFA
+foreground = #121218
+palette = 0=#282A36
+palette = 1=#AD251D
+palette = 2=#276A2B
+palette = 3=#745A00
+palette = 4=#6E42BC
+palette = 5=#9B317A
+palette = 6=#0A6677
+palette = 7=#8C8C80
+palette = 8=#5F6480
+palette = 9=#BD3229
+palette = 10=#317634
+palette = 11=#806500
+palette = 12=#7A4FC4
+palette = 13=#A64185
+palette = 14=#0D7283
+palette = 15=#FFFFFF
+cursor-color = #121218
+cursor-text = #FCFCFA
+selection-background = #DCD6EE
+selection-foreground = #121218
+palette = 60=#DCD6EE
+palette = 235=#EEEEEA
+palette = 236=#EBEBE6
diff --git a/.config/nvim/fnl/alphabaster/README.md b/.config/nvim/fnl/alphabaster/README.md
index 17e72389..17d26799 100644
--- a/.config/nvim/fnl/alphabaster/README.md
+++ b/.config/nvim/fnl/alphabaster/README.md
@@ -29,17 +29,20 @@ Initial design used red for comments (matching original Alabaster). In practice,
 
 Lavender/purple for strings matches the paramount colorscheme, preserving muscle memory. Strings and constants are conceptually similar anyway: literal values that serve as reference points. Using the same color for both simplifies the mental model from 4 categories to 3 visual colors.
 
-### Colors sourced from Ghostty
+### Colors come from the terminal
 
-All colors come from `~/.config/ghostty/config` to maintain consistency between terminal and editor:
+The colorscheme sets terminal color numbers, not hex values, and `init.fnl` turns `termguicolors` off. Neovim draws with whichever theme the terminal has loaded, so it switches between `~/.config/ghostty/themes/alphabaster` and `alphabaster-light` along with the terminal.
 
-```
-Background:  #121218
-Foreground:  #F0F0E4
-Yellow:      #E6E6A1  (comments)
-Lavender:    #C4AAEA  (strings, constants)
-Cyan:        #A2D6E0  (definitions)
-```
+| Role | Slot | Dark | Light |
+|---|---|---|---|
+| Comments | 8 | `#9BA3C9` | `#5F6480` |
+| Strings, constants | 12 | `#D0BCF0` | `#7A4FC4` |
+| Definitions | 6 | `#A2D6E0` | `#0A6677` |
+| Surfaces (status line, floats, cursor line) | 235 | `#282A36` | `#EEEEEA` |
+| Unfocused background | 236 | `#333333` | `#EBEBE6` |
+| Selection | 60 | `#626880` | `#DCD6EE` |
+
+Slots 0–15 hold text colors, and none of them works as a fill in both themes, so the theme files also redefine xterm slots 235, 236, and 60. In Rex, turn on Settings › Themes › Use extended theme palette for both modes, or those three fall back to xterm's standard grays.
 
 ## File Structure
 
diff --git a/.config/nvim/fnl/alphabaster/init.fnl b/.config/nvim/fnl/alphabaster/init.fnl
index c93afa58..9e91bf9a 100644
--- a/.config/nvim/fnl/alphabaster/init.fnl
+++ b/.config/nvim/fnl/alphabaster/init.fnl
@@ -18,8 +18,16 @@
 (local {: colors : semantic} (require :alphabaster.palette))
 (local api vim.api)
 
+;; :sp is dropped because cterm has no underline color, and nvim_set_hl would
+;; read a slot number there as an RGB integer.
 (fn hi [group opts]
-  (api.nvim_set_hl 0 group opts))
+  (api.nvim_set_hl 0 group
+                   (collect [k v (pairs opts)]
+                     (case k
+                       :fg (values :ctermfg v)
+                       :bg (values :ctermbg v)
+                       :sp nil
+                       _ (values k v)))))
 
 (fn link [group target]
   (api.nvim_set_hl 0 group {:link target}))
@@ -29,12 +37,12 @@
   (set vim.g.colors_name :alphabaster)
 
   ;;; Base
-  (hi :Normal {:fg colors.fg :bg colors.bg})
+  (hi :Normal {})
   ;; NormalNC matches Normal so inactive splits don't dim on their own;
   ;; the FocusLost autocmd in init.fnl dims both together when the whole
   ;; terminal pane loses focus.
-  (hi :NormalNC {:fg colors.fg :bg colors.bg})
-  (hi :NormalFloat {:fg colors.fg :bg colors.black})
+  (hi :NormalNC {})
+  (hi :NormalFloat {:bg colors.surface})
   (hi :FloatBorder {:fg colors.bright-black})
 
   ;;; === THE 4 SEMANTIC CATEGORIES ===
@@ -78,28 +86,28 @@
   (link :Character :Constant)
 
   ;;; UI elements
-  (hi :Visual {:bg colors.selection-bg :fg colors.selection-fg})
-  (hi :CursorLine {:bg colors.black})
-  (hi :CursorLineNr {:fg semantic.definition :bg colors.black})
+  (hi :Visual {:bg colors.selection-bg})
+  (hi :CursorLine {:bg colors.surface})
+  (hi :CursorLineNr {:fg semantic.definition :bg colors.surface})
   (hi :LineNr {:fg colors.bright-black})
   ;; No explicit bg — inherits from Normal/NormalNC so it dims with the window.
   (hi :SignColumn {})
   (hi :VertSplit {:fg colors.bright-black})
   (hi :WinSeparator {:fg colors.bright-black})
-  (hi :StatusLine {:bg colors.black})
-  (hi :StatusLineNC {:bg colors.black :fg colors.comment-gray})
-  (hi :Pmenu {:fg colors.fg :bg colors.black})
-  (hi :PmenuSel {:fg colors.fg :bg colors.selection-bg})
-  (hi :PmenuSbar {:bg colors.black})
+  (hi :StatusLine {:bg colors.surface})
+  (hi :StatusLineNC {:bg colors.surface :fg semantic.comment})
+  (hi :Pmenu {:bg colors.surface})
+  (hi :PmenuSel {:bg colors.selection-bg})
+  (hi :PmenuSbar {:bg colors.surface})
   (hi :PmenuThumb {:bg colors.bright-black})
-  (hi :TabLine {:fg colors.fg :bg colors.black})
-  (hi :TabLineSel {:fg colors.fg :bg colors.selection-bg :bold true})
-  (hi :TabLineFill {:bg colors.black})
+  (hi :TabLine {:bg colors.surface})
+  (hi :TabLineSel {:bg colors.selection-bg :bold true})
+  (hi :TabLineFill {:bg colors.surface})
 
   ;;; Search — high contrast, needs to pop
-  (hi :Search {:fg colors.fg :bg colors.selection-bg})
-  (hi :IncSearch {:fg colors.bg :bg colors.bright-yellow})
-  (hi :CurSearch {:fg colors.bg :bg colors.bright-green})
+  (hi :Search {:bg colors.selection-bg})
+  (hi :IncSearch {:fg colors.bright-yellow :reverse true})
+  (hi :CurSearch {:fg colors.bright-green :reverse true})
 
   ;;; Diagnostics — these are actionable, worth color
   (hi :DiagnosticError {:fg semantic.error})
@@ -238,13 +246,13 @@
 
   ;; indent-blankline
   ;; Indent guides should be subtle — they're structural, not semantic
-  (hi :IblIndent {:fg colors.black})
+  (hi :IblIndent {:fg colors.surface})
   (hi :IblScope {:fg colors.bright-black})  ;; current scope slightly brighter
 
   ;; treesitter-context
   ;; The sticky context header at top of window
-  (hi :TreesitterContext {:bg colors.black})
-  (hi :TreesitterContextLineNumber {:fg semantic.definition :bg colors.black})
+  (hi :TreesitterContext {:bg colors.surface})
+  (hi :TreesitterContextLineNumber {:fg semantic.definition :bg colors.surface})
 
   ;; fidget (LSP progress)
   (hi :FidgetTitle {:fg semantic.definition})
@@ -252,9 +260,9 @@
 
   ;; fzf.vim
   ;; Matched characters should stand out
-  (hi :fzf1 {:fg colors.fg :bg colors.black})
-  (hi :fzf2 {:fg colors.fg :bg colors.black})
-  (hi :fzf3 {:fg colors.fg :bg colors.black})
+  (hi :fzf1 {:bg colors.surface})
+  (hi :fzf2 {:bg colors.surface})
+  (hi :fzf3 {:bg colors.surface})
 
   ;; dirvish (file browser)
   (link :DirvishPathTail :Normal)
@@ -279,7 +287,7 @@
   (hi :FoldColumn {:fg colors.bright-black})
   (hi :NonText {:fg colors.bright-black})
   (hi :SpecialKey {:fg colors.bright-black})
-  (hi :Whitespace {:fg colors.black})  ;; listchars (tabs, trailing spaces)
+  (hi :Whitespace {:fg colors.surface})  ;; listchars (tabs, trailing spaces)
   (hi :Directory {:fg semantic.definition})
   (hi :Title {:fg semantic.definition})
   (hi :Question {:fg semantic.info})
@@ -287,12 +295,12 @@
   (hi :WarningMsg {:fg semantic.warn})
   (hi :ErrorMsg {:fg semantic.error :bold true})
   (hi :Todo {:fg semantic.comment :bold true})
-  (hi :Underlined {:fg colors.fg :underline true})
-  (hi :Ignore {:fg colors.bg})
-  (hi :Error {:fg colors.bg :bg semantic.error})
+  (hi :Underlined {:underline true})
+  (hi :Ignore {:fg colors.surface})
+  (hi :Error {:fg semantic.error :reverse true})
   (hi :Conceal {:fg colors.bright-black})
-  (hi :CursorColumn {:bg colors.black})
-  (hi :ColorColumn {:bg colors.black})
-  (hi :QuickFixLine {:bg colors.black}))
+  (hi :CursorColumn {:bg colors.surface})
+  (hi :ColorColumn {:bg colors.surface})
+  (hi :QuickFixLine {:bg colors.surface}))
 
 {: setup}
diff --git a/.config/nvim/fnl/alphabaster/lightline.fnl b/.config/nvim/fnl/alphabaster/lightline.fnl
index 33a6ed4c..e8108941 100644
--- a/.config/nvim/fnl/alphabaster/lightline.fnl
+++ b/.config/nvim/fnl/alphabaster/lightline.fnl
@@ -5,16 +5,20 @@
 
 (local {: colors : semantic} (require :alphabaster.palette))
 
-;; Lightline expects: [fg, bg, cterm_fg, cterm_bg]
-;; We only use GUI colors, so cterm values are placeholders.
-(fn ll [fg bg]
-  [fg bg 0 0])
-
-(local normal   (ll colors.fg colors.black))
-(local inactive (ll colors.comment-gray colors.black))
-(local insert   (ll colors.bg semantic.string))
-(local visual   (ll colors.fg colors.selection-bg))
-(local replace  (ll colors.bg semantic.error))
+;; Lightline expects: [gui_fg, gui_bg, cterm_fg, cterm_bg, attr]
+;; The palette is cterm slots, so the GUI values are placeholders.
+(fn ll [fg bg ?attr]
+  [:NONE :NONE fg bg ?attr])
+
+;; Reversing an accent paints it behind text in the terminal's background.
+(fn accent [color]
+  (ll color :NONE :reverse))
+
+(local normal   (ll :NONE colors.surface))
+(local inactive (ll semantic.comment colors.surface))
+(local insert   (accent semantic.string))
+(local visual   (ll :NONE colors.selection-bg))
+(local replace  (accent semantic.error))
 
 ;; Middle section is transparent (matches your current config)
 (local middle [[:NONE :NONE :NONE :NONE]])
diff --git a/.config/nvim/fnl/alphabaster/palette.fnl b/.config/nvim/fnl/alphabaster/palette.fnl
index 0337b228..da0885ae 100644
--- a/.config/nvim/fnl/alphabaster/palette.fnl
+++ b/.config/nvim/fnl/alphabaster/palette.fnl
@@ -1,47 +1,37 @@
 ;; fnl/alphabaster/palette.fnl
 ;;
-;; Color definitions sourced from ~/.config/ghostty/config
+;; Terminal color numbers rather than hex, so Neovim draws with whichever
+;; theme the terminal has loaded: ~/.config/ghostty/themes/alphabaster or
+;; alphabaster-light. Requires termguicolors off.
 
-;; Ghostty terminal colors (named)
 (local colors
-  {:bg         "#121218"
-   :fg         "#F0F0E4"
-
-   ;; ANSI normal
-   :black      "#282A36"
-   :red        "#FFB3B3"
-   :green      "#7BC275"
-   :yellow     "#E6E6A1"
-   :blue       "#C4AAEA"
-   :magenta    "#E2A6D4"
-   :cyan       "#A2D6E0"
-   :white      "#F0F0E4"
-
-   ;; ANSI bright
-   :bright-black   "#9BA3C9"
-   :bright-red     "#FFC9C9"
-   :bright-green   "#96D988"
-   :bright-yellow  "#EFE9B0"
-   :bright-blue    "#D0BCF0"
-   :bright-magenta "#EDBBE0"
-   :bright-cyan    "#B6E2EA"
-   :bright-white   "#FFFFFF"
-
-   ;; Special
-   :comment-gray "#A0A0A0"
-   :cursor     "#f2d5cf"
-   :selection-bg "#626880"
-   :selection-fg "#F0F0E4"
-
-   ;; Dimmed background for unfocused windows (matches tmux pane-focus-out)
-   :dim-bg     "#333333"})
+  {;; ANSI slots
+   :red            1
+   :green          2
+   :yellow         3
+   :blue           4
+   :magenta        5
+   :cyan           6
+   :bright-black   8
+   :bright-red     9
+   :bright-green   10
+   :bright-yellow  11
+   :bright-blue    12
+   :bright-magenta 13
+   :bright-cyan    14
+
+   ;; No ANSI slot reads as a fill in both themes, so the theme files redefine
+   ;; these xterm slots. Rex needs "Use extended theme palette" on for them.
+   :surface      235
+   :dim-bg       236  ;; unfocused background (matches tmux pane-focus-out)
+   :selection-bg 60})
 
 ;; Semantic roles (Alabaster philosophy)
 ;; Only 4 categories get color. Everything else is default fg.
 (local semantic
-  {:comment    colors.comment-gray   ;; visible but secondary
-   :string     colors.bright-blue ;; lavender/purple
-   :constant   colors.bright-blue ;; same as strings — all literal values are lavender
+  {:comment    colors.bright-black ;; visible but secondary
+   :string     colors.bright-blue  ;; lavender/purple
+   :constant   colors.bright-blue  ;; same as strings — all literal values are lavender
    :definition colors.cyan
 
    ;; Diagnostics
diff --git a/.config/nvim/fnl/init.fnl b/.config/nvim/fnl/init.fnl
index d6182ccd..4a542a5b 100644
--- a/.config/nvim/fnl/init.fnl
+++ b/.config/nvim/fnl/init.fnl
@@ -21,7 +21,8 @@
 (set vim.o.listchars "tab:⇥ ,trail:␣,extends:⇉,precedes:⇇,nbsp:·")
 (set vim.o.number true)
 (set vim.o.showmode false)
-(set vim.o.termguicolors true)
+;; Off so alphabaster's slot numbers draw with the terminal's theme.
+(set vim.o.termguicolors false)
 (set vim.o.virtualedit :block)
 (set vim.o.wildmode "longest:full")
 (set vim.o.winborder :rounded)
@@ -221,10 +222,10 @@
 (let [group (nvim-create-augroup :focus-dim {})
       {: colors} (require :alphabaster.palette)
       set-bg (fn [bg]
-               (nvim-set-hl 0 :Normal {:fg colors.fg : bg})
-               (nvim-set-hl 0 :NormalNC {:fg colors.fg : bg}))
+               (nvim-set-hl 0 :Normal {:ctermbg bg})
+               (nvim-set-hl 0 :NormalNC {:ctermbg bg}))
       dim-bg #(set-bg colors.dim-bg)
-      restore-bg #(set-bg colors.bg)]
+      restore-bg #(set-bg nil)]
   (nvim-create-autocmd :FocusLost {:callback dim-bg : group})
   (nvim-create-autocmd :FocusGained {:callback restore-bg : group}))