v0.25.1 025a25b

themes.md RawHistoryFolder

zut themes

zut uses the controlling terminal as the source of truth for its default appearance. Theme files are JSON overlays: every field is optional.

Built-in choices

Open /settings and select color theme.

  • auto (default) follows the terminal default foreground and background, ANSI palette, color depth, and reported light/dark scheme. It does not paint a full-row background or set a cursor color.
  • dark and light use zut's fixed palettes. They remain fixed when the terminal appearance changes.
  • A custom theme overlays auto. Unspecified roles remain terminal-owned; explicit JSON values remain literal overrides.

inherited is no longer a theme choice. A persisted inherited value resets to auto.

ZUT_THEME=dark or ZUT_THEME=light forces that choice for one process. The settings dialog still saves the next-launch preference, but cannot override the environment for the running process. An unset ZUT_THEME or ZUT_THEME=auto uses the saved preference.

Live terminal changes

Interactive zut queries terminal defaults and ANSI slots at startup. When the terminal supports DEC mode 2031 color-scheme notifications, zut follows reported scheme changes and refreshes its terminal profile. It probes the mode before changing it and disables it on exit only when zut enabled a known-reset mode itself. Terminals without notification support receive a low-rate OSC 11 and scheme query fallback (about two seconds).

Terminal support varies through multiplexers and remote sessions. If a reply does not arrive, zut remains usable with terminal default SGR colors and ANSI slots. Existing scrollback is never recolored or cleared by a theme change; only the visible live frame is repainted.

Theme files and reload

User themes live under:

$ZUT_HOME/themes/*.json

Extension-owned themes are loaded in place from:

$ZUT_HOME/extensions/<extension>/theme.json
$ZUT_HOME/extensions/<extension>/themes/theme.json
<project>/.zut/extensions/<extension>/theme.json
<project>/.zut/extensions/<extension>/themes/theme.json

An active custom file is polled every 500 ms. A valid complete edit applies without restarting zut. Invalid JSON, invalid colors, unsupported syntax styles, and oversized files leave the last valid revision active. Brief atomic rename gaps are tolerated; a file that stays missing resets the saved choice to auto and shows a status message.

Minimal files

{
  "name": "pink-accent",
  "colors": { "accent": 204 }
}

Shared overrides can appear at the top level or directly in colors. Mode-specific overrides go under colors.dark and colors.light; zut uses a reported color scheme when available, and a background-luminance fallback otherwise.

{
  "name": "split-accent",
  "colors": {
    "dark": { "accent": 204 },
    "light": { "accent": 161 }
  }
}
{
  "name": "spinner-only",
  "spinner_frames": ["◢", "◣", "◤", "◥"],
  "spinner_interval_ms": 120
}

Color values

Every semantic color accepts one of:

254
"#42454b"
{ "mode": "256", "index": 254 }
{ "mode": "ansi", "index": 100 }
{ "mode": "rgb", "r": 66, "g": 69, "b": 75 }

Numeric values are literal xterm-256 indexes. ANSI values are literal ANSI SGR colors. RGB values use truecolor when available, otherwise zut quantizes them to the active terminal capability. auto-generated colors are distinct: they retain terminal-default or terminal-palette-slot provenance and therefore change with the terminal palette.

Color roles are fg, muted, accent, background, user, user_bubble_bg, user_bubble_fg, assistant, tool, tool_out, error, warning, spinner, thinking_max (or thinkingMax), selection_bg, and selection_fg. background intentionally paints the full zut row; omit it to retain terminal background ownership.

spinner_frames contains 1–64 non-empty frames. spinner_interval_ms must be between 10 and 10000. Theme files are limited to 1 MiB.

Syntax

Custom syntax entries use Chroma style entries, for example:

{
  "colors": {
    "dark": {
      "syntax": {
        "keyword": "#f05b8d bold",
        "literal_string": "#58c760",
        "comment": "#a1a1a1 italic"
      }
    }
  }
}

In auto, zut keeps Chroma for lexing but emits its own exact terminal SGR sequences. Keywords, names, strings, errors, numbers, comments, and plain text therefore retain terminal ANSI-slot identity instead of being remapped through the xterm color cube.

source
1# zut themes
2
3zut uses the controlling terminal as the source of truth for its default
4appearance. Theme files are JSON overlays: every field is optional.
5
6## Built-in choices
7
8Open `/settings` and select **color theme**.
9
10- **auto** (default) follows the terminal default foreground and background,
11  ANSI palette, color depth, and reported light/dark scheme. It does not paint
12  a full-row background or set a cursor color.
13- **dark** and **light** use zut's fixed palettes. They remain fixed when the
14  terminal appearance changes.
15- A **custom theme** overlays `auto`. Unspecified roles remain terminal-owned;
16  explicit JSON values remain literal overrides.
17
18`inherited` is no longer a theme choice. A persisted `inherited` value resets
19to `auto`.
20
21`ZUT_THEME=dark` or `ZUT_THEME=light` forces that choice for one process. The
22settings dialog still saves the next-launch preference, but cannot override the
23environment for the running process. An unset `ZUT_THEME` or `ZUT_THEME=auto`
24uses the saved preference.
25
26## Live terminal changes
27
28Interactive zut queries terminal defaults and ANSI slots at startup. When the
29terminal supports DEC mode 2031 color-scheme notifications, zut follows
30reported scheme changes and refreshes its terminal profile. It probes the mode
31before changing it and disables it on exit only when zut enabled a known-reset
32mode itself. Terminals without notification support receive a low-rate OSC 11
33and scheme query fallback (about two seconds).
34
35Terminal support varies through multiplexers and remote sessions. If a reply
36does not arrive, zut remains usable with terminal default SGR colors and ANSI
37slots. Existing scrollback is never recolored or cleared by a theme change;
38only the visible live frame is repainted.
39
40## Theme files and reload
41
42User themes live under:
43
44```text
45$ZUT_HOME/themes/*.json
46```
47
48Extension-owned themes are loaded in place from:
49
50```text
51$ZUT_HOME/extensions/<extension>/theme.json
52$ZUT_HOME/extensions/<extension>/themes/theme.json
53<project>/.zut/extensions/<extension>/theme.json
54<project>/.zut/extensions/<extension>/themes/theme.json
55```
56
57An active custom file is polled every 500 ms. A valid complete edit applies
58without restarting zut. Invalid JSON, invalid colors, unsupported syntax
59styles, and oversized files leave the last valid revision active. Brief atomic
60rename gaps are tolerated; a file that stays missing resets the saved choice to
61`auto` and shows a status message.
62
63## Minimal files
64
65```json
66{
67  "name": "pink-accent",
68  "colors": { "accent": 204 }
69}
70```
71
72Shared overrides can appear at the top level or directly in `colors`.
73Mode-specific overrides go under `colors.dark` and `colors.light`; zut uses a
74reported color scheme when available, and a background-luminance fallback
75otherwise.
76
77```json
78{
79  "name": "split-accent",
80  "colors": {
81    "dark": { "accent": 204 },
82    "light": { "accent": 161 }
83  }
84}
85```
86
87```json
88{
89  "name": "spinner-only",
90  "spinner_frames": ["◢", "◣", "◤", "◥"],
91  "spinner_interval_ms": 120
92}
93```
94
95## Color values
96
97Every semantic color accepts one of:
98
99```json
100254
101"#42454b"
102{ "mode": "256", "index": 254 }
103{ "mode": "ansi", "index": 100 }
104{ "mode": "rgb", "r": 66, "g": 69, "b": 75 }
105```
106
107Numeric values are literal xterm-256 indexes. ANSI values are literal ANSI SGR
108colors. RGB values use truecolor when available, otherwise zut quantizes them
109to the active terminal capability. `auto`-generated colors are distinct:
110they retain terminal-default or terminal-palette-slot provenance and therefore
111change with the terminal palette.
112
113Color roles are `fg`, `muted`, `accent`, `background`, `user`,
114`user_bubble_bg`, `user_bubble_fg`, `assistant`, `tool`, `tool_out`, `error`,
115`warning`, `spinner`, `thinking_max` (or `thinkingMax`), `selection_bg`, and
116`selection_fg`. `background` intentionally paints the full zut row; omit it
117to retain terminal background ownership.
118
119`spinner_frames` contains 1–64 non-empty frames. `spinner_interval_ms` must be
120between 10 and 10000. Theme files are limited to 1 MiB.
121
122## Syntax
123
124Custom `syntax` entries use Chroma style entries, for example:
125
126```json
127{
128  "colors": {
129    "dark": {
130      "syntax": {
131        "keyword": "#f05b8d bold",
132        "literal_string": "#58c760",
133        "comment": "#a1a1a1 italic"
134      }
135    }
136  }
137}
138```
139
140In `auto`, zut keeps Chroma for lexing but emits its own exact terminal SGR
141sequences. Keywords, names, strings, errors, numbers, comments, and plain text
142therefore retain terminal ANSI-slot identity instead of being remapped through
143the xterm color cube.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close