diff options
| author | user <user@clank> | 2026-08-14 19:14:29 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-14 19:14:29 +0200 |
| commit | e75eecfc64adbf5fae0f4ddc3eca1dae41028fa2 (patch) | |
| tree | 21b114e4b5a517b9762e25a3057504b69c9e38c8 /tests | |
| parent | sl0ppty: give the scroll arrow room to breathe (diff) | |
| download | slosh-e75eecfc64adbf5fae0f4ddc3eca1dae41028fa2.tar.gz slosh-e75eecfc64adbf5fae0f4ddc3eca1dae41028fa2.tar.xz slosh-e75eecfc64adbf5fae0f4ddc3eca1dae41028fa2.zip | |
sl0ppty: one theme name per decision, and a tab you can see
The count, since it was asked: no hardcoded colours at all in the drawing code.
Every colour already came from the config. The problem was the other way round
— six names were serving about thirty decisions, so the names were the thing
that was hardcoded. frame_focus was the focused frame *and* the split guide
*and* the resize handle *and* the tab hover *and* a collapsed row under the
pointer. Recolouring one recoloured five.
There are thirty-five entries now, one per surface, each documented in
config.kdl by being its own default. Several still share a value: that is a
statement that they look right together, not that they are the same thing, and
the difference only matters the first time someone wants to change one of them.
The tab you are in is filled rather than merely bold, which was the ask. Bold
alone is easy to miss on a strip of short labels, and it was the only thing
distinguishing the tab you were in from the four you were not.
That immediately raised a question the old scheme could not ask: what does
hovering the active tab look like, when it already has the strongest treatment
on the strip? Keeping its fill and brightening its text, because it is still
the tab you are in and clicking it does nothing. My first version gave it no
hover at all, which reads as the hover being broken rather than as the click
being pointless.
Three surfaces were still borrowing a name that did not describe them: the
in-place rename editor was wearing the button colours, a pane's OSC status text
and a suspended pane's hint were wearing the frame's. They have their own now.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_config.py | 58 | ||||
| -rw-r--r-- | tests/test_tabs.py | 47 |
2 files changed, 90 insertions, 15 deletions
diff --git a/tests/test_config.py b/tests/test_config.py index 7566b76..44447e0 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -9,12 +9,17 @@ import os import subprocess import sys import tempfile +import time from harness import Session, check, report, BIN SH = ["/bin/sh", "-c", 'printf "\\033]2;cfg\\007"; stty raw -echo; cat'] +def hover(s, x, y): + s.send(rf"\e[<35;{x + 1};{y + 1}M") + + def cfg(text): f = tempfile.NamedTemporaryFile("w", suffix=".kdl", delete=False) f.write(text) @@ -317,6 +322,57 @@ def test_status_pad_holds_both_bars_off_the_edge(): +def test_every_surface_has_its_own_theme_name(): + """The point of splitting six names into thirty-five: recolouring one + surface must not recolour another that happened to share an entry.""" + conf = cfg('theme {\n' + ' guide "#00ff00"\n' + ' tab_active_bg "#0000ff"\n' + ' status "#ff8800"\n' + ' header "#ff00ff"\n' + '}\n') + with Session(SH, cols=80, rows=16, config=conf) as s: + s.settle(20) + snap = s.snapshot() + + tab = [h for h in snap.hits if h["action"].startswith("tab:")][0] + check("tab_active_bg fills the tab you are in", + (snap.style_at(tab["x"] + 1, tab["y"]) or {}).get("bg") == "#0000ff", + str(snap.style_at(tab["x"] + 1, tab["y"]))) + check("status colours the bottom line", + (snap.style_at(4, snap.rows - 2) or {}).get("fg") == "#ff8800", + str(snap.style_at(4, snap.rows - 2))) + + # ...and the frame, which shares a *default* with guide, did not move. + p = s.pane() + check("the focused frame keeps its own colour", + (snap.style_at(p["x"], p["y"] + 1) or {}).get("fg") == "#ff5fd7", + str(snap.style_at(p["x"], p["y"] + 1))) + + # The guide is the one that used to be the same entry as the frame. + hover(s, p["x"], p["y"] + 3) + time.sleep(0.35) + s.settle(40) + snap = s.snapshot() + check("and the split guide takes the colour named for it", + (snap.style_at(p["x"], p["y"] + 3) or {}).get("fg") == "#00ff00", + str(snap.style_at(p["x"], p["y"] + 3))) + os.unlink(conf) + + +def test_an_unknown_theme_name_is_refused_not_ignored(): + conf = cfg('theme {\n frame_focus "not-a-colour"\n}\n') + with Session(SH, cols=60, rows=12, config=conf) as s: + s.settle(20) + check("a bad colour costs a warning, not a terminal", s.alive(), "") + p = s.pane() + check("and the compiled-in default is kept", + (s.snapshot().style_at(p["x"], p["y"] + 1) or {}).get("fg") + == "#ff5fd7", + str(s.snapshot().style_at(p["x"], p["y"] + 1))) + os.unlink(conf) + + if __name__ == "__main__": test_geometry() test_status_bar_off() @@ -330,4 +386,6 @@ if __name__ == "__main__": test_status_line_reports_scrollback() test_the_two_pane_counts_answer_different_questions() test_status_pad_holds_both_bars_off_the_edge() + test_every_surface_has_its_own_theme_name() + test_an_unknown_theme_name_is_refused_not_ignored() sys.exit(report()) diff --git a/tests/test_tabs.py b/tests/test_tabs.py index 8f98af3..2b5b6d6 100644 --- a/tests/test_tabs.py +++ b/tests/test_tabs.py @@ -174,9 +174,10 @@ def test_json_api(): # ---- hovering the strip ---------------------------------------------------- -STRIP_HOT = "#ff5fd7" # pointer is here -STRIP_ON = "#ffffff" # this is the tab you are in -STRIP_OFF = "#45454a" +ACCENT = "#ff5fd7" # the fill of the tab you are in, and hover on the rest +INK = "#141418" # text on that fill +BRIGHT = "#ffffff" # that text while the pointer is on it +DIM = "#45454a" # a tab you are not in def two_tab_layout(): @@ -200,6 +201,10 @@ def fg_of(snap, h): return (snap.style_at(h["x"] + 1, h["y"]) or {}).get("fg") +def bg_of(snap, h): + return (snap.style_at(h["x"] + 1, h["y"]) or {}).get("bg") + + def attrs_of(snap, h): return (snap.style_at(h["x"] + 1, h["y"]) or {}).get("attrs", []) @@ -211,14 +216,18 @@ def test_hovering_the_strip_lights_what_is_under_the_pointer(): hits = strip_hits(s.snapshot()) check("the strip has two tabs and a +tab", len(hits) == 3, str(hits)) + active_id = "tab:" + str(s.tabs()[0]["id"]) for target, h in hits.items(): hover(s, h["x"] + 1, h["y"]) snap = s.snapshot() + # The tab you are in keeps its fill and brightens its text; the + # others have no fill to keep and take the accent. + want = BRIGHT if target == active_id else ACCENT check(f"hovering {target} lights it", - fg_of(snap, h) == STRIP_HOT, str(fg_of(snap, h))) - others = [fg_of(snap, o) for k, o in hits.items() if k != target] - check(f"and nothing else on the strip", - all(c != STRIP_HOT for c in others), str(others)) + fg_of(snap, h) == want, f"{fg_of(snap, h)} wanted {want}") + others = [(k, fg_of(snap, o)) for k, o in hits.items() if k != target] + check("and nothing else on the strip", + all(c in (INK, DIM) for _, c in others), str(others)) os.unlink(lay) @@ -232,16 +241,24 @@ def test_weight_says_active_and_colour_says_pointer(): active = hits["tab:" + str(s.tabs()[0]["id"])] snap = s.snapshot() - check("the active tab is bold and white while untouched", - fg_of(snap, active) == STRIP_ON and "bold" in attrs_of(snap, active), - f"{fg_of(snap, active)} {attrs_of(snap, active)}") + check("the tab you are in is filled, not merely bold", + fg_of(snap, active) == INK and bg_of(snap, active) == ACCENT, + f"{fg_of(snap, active)} on {bg_of(snap, active)}") + check("and still bold", "bold" in attrs_of(snap, active), + str(attrs_of(snap, active))) + + inactive = [h for k, h in hits.items() + if k.startswith("tab:") and h is not active][0] + check("a tab you are not in has no fill at all", + bg_of(snap, inactive) is None and fg_of(snap, inactive) == DIM, + f"{fg_of(snap, inactive)} on {bg_of(snap, inactive)}") hover(s, active["x"] + 1, active["y"]) snap = s.snapshot() - check("hovering it changes its colour", - fg_of(snap, active) == STRIP_HOT, str(fg_of(snap, active))) - check("but it keeps the weight that says you are in it", - "bold" in attrs_of(snap, active), str(attrs_of(snap, active))) + check("hovering it brightens the text", + fg_of(snap, active) == BRIGHT, str(fg_of(snap, active))) + check("but it keeps the fill that says you are in it", + bg_of(snap, active) == ACCENT, str(bg_of(snap, active))) os.unlink(lay) @@ -263,7 +280,7 @@ def test_leaving_the_strip_puts_it_out_and_hover_switches_nothing(): hover(s, p["content_x"] + 2, p["content_y"] + 1) snap = s.snapshot() check("nothing on the strip is lit once the pointer leaves it", - all(fg_of(snap, h) != STRIP_HOT for h in hits.values()), + all(fg_of(snap, h) in (INK, DIM) for h in hits.values()), str([fg_of(snap, h) for h in hits.values()])) # ...but clicking still switches. |
