aboutsummaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-22 12:42:15 +0200
committeruser <user@clank>2026-09-22 12:42:15 +0200
commitfaa3fb6ee575a900abc574b0f9ed5ff291761837 (patch)
treece644998c144687e205d1f4e97e6f999de98723b /config
parenttabs: idle tabs you can actually read across the room (diff)
downloadslosh-faa3fb6ee575a900abc574b0f9ed5ff291761837.tar.gz
slosh-faa3fb6ee575a900abc574b0f9ed5ff291761837.tar.xz
slosh-faa3fb6ee575a900abc574b0f9ed5ff291761837.zip
theme: a name and a directory, not sixty colours in your config
Wearing a theme meant pasting its `theme { }` block into config.kdl, or including a path to a file you had copied there yourself. Both make the palette a literal in your config, and a literal is the one thing you cannot change cheaply: not from a script, not from a running session, not by a list of what is available, and never again from upstream -- the colours you pasted are the colours that theme had the day you pasted them. So a theme is a file in a directory now, and a config names it: theme_name "phosphor" theme { frame_focus "#00ff88" } // ...but that one colour is mine theme_name is applied after the includes and before everything the file says itself, which is the rule includes already follow and for the same reason: the loader reads a document by asking it for names rather than walking it in order, so "here" is not a position it could honour, and "what you asked for is the base, what you wrote is yours" is the rule worth having. Two directories, yours first: `themes/` beside the root config -- beside the file that was loaded, so a config somewhere else (SLOSH_CONFIG, or one handed to --check) takes its themes with it -- and then <prefix>/share/slosh/themes, compiled in from PREFIX. install(1) has been putting themes there all along and nothing could read them; now a shipped theme is nameable without being copied, and a file of yours with the same name shadows it, which is how a root-owned theme gets edited. A name, not a path. The directory is what makes a theme switchable, listable and shadowable, and a path silently does none of those, so `theme_name "../x.kdl"` is refused with a line pointing at `include`, which still works and is still the answer for a file somewhere a directory of names cannot reach. A theme that is not there is one complaint and no more (D9): the rest of the config applies, because losing your keybindings over a mistyped colour scheme would be the wrong trade. A theme file is read by the same loader, so it is watched like any other: saving one reloads the session wearing it, and the derivations (tab_status_fg, tab_idle_bg) run over the theme's own colours exactly as before. Switching without editing anything, over the socket a session already has: slosh -s main cmd theme # amber default* ... slosh -s main cmd '{"cmd":"theme","name":"amber"}' # now slosh -s main cmd '{"cmd":"theme","name":"amber","save":true}' The session holds the name over later reloads, so saving your config for an unrelated reason does not put the old colours back; `save` writes the theme_name line into the file, replacing the one already there and leaving every other line and comment alone -- dumping the whole config back over itself would reformat a hand-written file and drop its comments, which is not a fair price for changing a colour scheme. A name is tried on a throwaway config first, so a typo costs nothing. An empty name gives the answer back to the file. --dump-config stops writing colours: it writes the theme's name and the colours a config overrode by hand, so a dumped config keeps following its theme instead of freezing it. --dump-theme is the other half and is new: the resolved palette as a theme file, which is how you start one from the session in front of you rather than from an empty file. It is also what keeps contrib/themes/default.kdl honest -- that file is now the annotated reference (the commented palette moved there out of config.kdl, where it was 119 lines of colour in the middle of the prose), and a test compares it against the compiled-in one. While in there: tests/test_themes.py's "every theme sets every colour" guard had been grepping for `&c->`, the spelling before the colour table moved to offsetof, so it had been finding zero colours and passing for months. Fixed, with the derived and opt-in colours exempted for the reasons they are derived and opt-in, and with a check that the guard found a table at all.
Diffstat (limited to 'config')
-rw-r--r--config/config.kdl154
1 files changed, 32 insertions, 122 deletions
diff --git a/config/config.kdl b/config/config.kdl
index fc6fb3b..147b709 100644
--- a/config/config.kdl
+++ b/config/config.kdl
@@ -799,130 +799,40 @@ splash_ms 900
// ── theme ───────────────────────────────────────────────────────────────────
-// Every colour the compositor draws has its own name here. They started as six
-// names doing thirty jobs, which meant the split guide could not be recoloured
-// without also recolouring the focused frame, because they were the same
-// entry. Several still share a default: that says they look right together,
-// not that they are the same thing.
-theme {
- // What a cell's "terminal default" colour is taken to be when a shader has
- // to compute on it. See the shaders section above.
- default_fg "#ffffff"
- default_bg "#000000"
-
- // ── panes ───────────────────────────────────────────────────────────────
- frame_focus "#7aa2f7" // border of the focused pane
- frame_idle "#45454a" // border of every other pane
- title "#ffffff" // its title, and its OSC 5577 status text
- title_idle "#45454a" // the same, on a pane that is not focused
-
- // A pane's own OSC 5577 buttons.
- button_fg "#141418"
- button_bg "#7aa2f7"
- button_bg_idle "#55555c" // buttons on a pane that is not focused
-
- // ── things that appear under the pointer ────────────────────────────────
- guide "#7aa2f7" // split guide: armed edge, handle, its arrow, boundary
- resize "#7aa2f7" // the handle in the gap between two panes
- drop_target "#7aa2f7" // frame of a pane a drag could land on
-
- // ── a pane's scrollback indicator ───────────────────────────────────────
- scroll_fg "#141418"
- scroll_bg "#7aa2f7"
-
- // ── rows of a tab that has collapsed into a list ────────────────────────
- header "#45454a"
- header_hover "#7aa2f7" // the rule, under the pointer
- header_hover_title "#ffffff" // the name, under the pointer
-
- // ── the strip along the top ─────────────────────────────────────────────
- // The tab you are in is filled rather than merely bold: bold alone is easy
- // to miss on a strip of short labels. It keeps that fill while the pointer
- // is on it -- it is still the tab you are in -- so its hover lands on the
- // text instead.
- tab_active_fg "#141418"
- tab_active_bg "#7aa2f7"
- tab_active_hover_fg "#ffffff"
- // Brighter than the grey on idle frames and titles: a tab you are not in
- // is a place to go, and has to read from across the screen.
- tab_idle "#8a8a95"
- // Every other tab is a plate too, 43% of the way from the background to
- // the grey above: a tab with edges rather than a word floating on the
- // background, and something for the active fill to be brighter *than*.
- // That fraction is a contrast ratio in disguise -- about 1.9:1 against
- // the background whether the theme is dark or light. Unset, it is mixed
- // from those two, so a theme gets one in its own family without naming
- // it. Name your own background here for bare tabs.
- tab_idle_bg "#3b3b40"
- tab_hover "#7aa2f7"
- prefix_fg "#141418" // the "C-a" badge, while the prefix is pending
- prefix_bg "#7aa2f7"
- tab_count "#45454a" // panes in the whole session
-
- // ── the line along the bottom ───────────────────────────────────────────
- status "#45454a" // session, tab, pane, and the pane index
- status_state "#ffffff" // scrolled / alt screen / not started / exited
- hint "#ffffff" // what the pointer is on, in the middle
-
- // ── marks on a pane's frame ─────────────────────────────────────────────
- bell "#e0af68" // a pane rang and has not been looked at:
- // amber, not the accent -- attention, not focus
- dead "#ff875f" // its program exited: the line in its backlog,
- // and the words in its frame and the status line
- pane_button "#45454a" // the frame's own close/zoom/minimise marks
- pane_button_hover "#7aa2f7"
-
- // ── the row of minimised panes ──────────────────────────────────────────
- minbar "#45454a"
- minbar_hover "#7aa2f7"
-
- // ── modals: a surface that floats over the layout ───────────────────────
- // Named apart from the pane colours they resemble because a modal is a
- // different surface: opaque, on top of everything, and legible against a
- // background that has been dimmed underneath it. (The first version drew
- // the close button in the pane button colour on the finder background,
- // which are the same value — an invisible button until you hovered it.)
- modal_bg "#1c1c22" // a shade lighter than the dimmed screen
- modal_fg "#e8e8ea"
- modal_border "#7aa2f7"
- modal_title "#ffffff"
- modal_button "#8a8a95" // visible *without* the pointer on it
- modal_button_hover "#7aa2f7"
-
- // ── the pane finder ─────────────────────────────────────────────────────
- // The finder is a modal, so its box is the modal colours above; these are
- // the parts only it has. `finder_bg` is the query field and the row under
- // the pointer — a band that is not the box, so typing and hovering both
- // have somewhere to show.
- finder_fg "#ffffff"
- finder_bg "#45454a"
- finder_sel_fg "#141418"
- finder_sel_bg "#7aa2f7" // the row enter would take
-
- // ── scrollback search (the `/` bar) ────────────────────────────────
- // Every match on screen is tinted `search_*`; the one the bar is on gets
- // `search_cur_*` instead, so "this one" reads apart from "all of them".
- // Warm gold by default, because a match is a different thing from a
- // selection (finder) or focus (accent) and should not be mistaken for one.
- search_fg "#ffffff"
- search_bg "#4d4124" // the other matches
- search_cur_fg "#141418"
- search_cur_bg "#f2c97a" // the one ↑↓ and enter act on
-
- // ── the in-place editor a double-click opens on a pane title ────────────
- rename_fg "#141418"
- rename_bg "#7aa2f7"
+// A theme is a file of colours in a directory, named here rather than pasted
+// in. Named, because a name is a thing you can change: `theme_name` is one
+// line to edit, one `{"cmd":"theme","name":"amber"}` to switch while the
+// session runs, and one entry in a list a picker can show you. Sixty colours
+// pasted into this file are none of those things -- and they freeze the
+// palette at the moment you pasted them, so every later improvement to the
+// theme you copied from is one you never see.
+//
+// theme_name "phosphor"
- // ── announcements ───────────────────────────────────────────────────────
- toast_fg "#141418"
- toast_bg "#7aa2f7"
+// Where those files are looked for. Unset, it is `themes/` beside this file
+// (so ~/.config/slosh/themes for the usual config), and then the ones slosh
+// installed in <prefix>/share/slosh/themes -- a shipped theme is nameable
+// without being copied first, and a theme of yours with the same name shadows
+// it. Yours is searched first for exactly that reason.
+//
+// theme_dir "~/.config/slosh/themes"
- // The "2 clients" tag when several terminals share the session. Muted by
- // default -- standing information, not an announcement. attach_bg unset
- // means the terminal's own background.
- attach_fg "#45454a"
- // attach_bg "#141418"
-}
+// A theme file *is* a config file -- one `theme { }` block in it and nothing
+// else -- which is why `slosh --check` lints one, why saving one reloads the
+// session wearing it, and why `include` still works for a theme that lives
+// somewhere a directory of names cannot reach.
+//
+// The shipped `default` theme is the annotated reference: every colour with
+// what it is for, and it matches what no config at all gets you. To start one
+// from the session in front of you:
+//
+// slosh --dump-theme > ~/.config/slosh/themes/mine.kdl
+//
+// Anything written in a `theme { }` block here beats the named theme, colour
+// by colour, so "that one, but with my green frames" is two lines:
+//
+// theme_name "phosphor"
+// theme { frame_focus "#00ff88" }
// ── keys ────────────────────────────────────────────────────────────────────
//