aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_config.py
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-14 16:38:26 +0200
committeruser <user@clank>2026-08-14 16:38:26 +0200
commit6548577400ab6833b9424de056c6da6079ed6ff4 (patch)
treeb2900cbb0e272f18024d95596153da42f6196c24 /tests/test_config.py
parentsl0ppty: a collapsed pane is drawn as a pane, closed (diff)
downloadslosh-6548577400ab6833b9424de056c6da6079ed6ff4.tar.gz
slosh-6548577400ab6833b9424de056c6da6079ed6ff4.tar.xz
slosh-6548577400ab6833b9424de056c6da6079ed6ff4.zip
sl0ppty: a status line along the bottom
The strip along the top answers "which tab" and "how many panes" — questions about what you could switch to. Nothing answered "what am I looking at", and three of the states a pane can be in were discoverable only by being surprised by them. So the bottom line is about the focused pane and deliberately repeats nothing from the top: the session it lives in, the tab, what the pane calls itself (its purpose if it declared one, otherwise its title), and on the right, the state worth knowing — scrolled back and how far, on an alternate screen, not started yet, or exited. Right side budgeted first, the same rule the tab strip and the pane frame already use, so a long name cannot push the state off the end. The session name had to be plumbed in: the server knows it because it opened the socket under that name, and the app had no reason to until now. Reserving a row is not free and three tests noticed, which is the correct number to notice. Two were arithmetic — a chrome budget written as rows-5 and a six-row session whose pane no longer had room for a frame at all. The third was more useful: test_tiny_panes_have_no_targets asserted "no border hit that is one row tall and under four wide", which is a description of the shape a collapsed header used to have rather than of the thing being tested, and it started catching the perfectly legitimate side border of a pane that was merely short. It now says what it means — no split targets on a *header* row — and is both stricter and immune to the layout getting a row shorter again.
Diffstat (limited to '')
-rw-r--r--tests/test_config.py60
1 files changed, 60 insertions, 0 deletions
diff --git a/tests/test_config.py b/tests/test_config.py
index 49ef7be..96e7b57 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -191,6 +191,63 @@ def test_reload():
os.unlink(path)
+def test_status_line_reserves_a_row_at_the_bottom():
+ on = cfg("")
+ off = cfg("status_line false\n")
+ heights = {}
+ for name, path in (("on", on), ("off", off)):
+ with Session(SH, cols=50, rows=12, config=path) as s:
+ s.settle()
+ heights[name] = s.pane()["h"]
+ check("turning the status line off gives the row back to the panes",
+ heights["off"] == heights["on"] + 1, str(heights))
+ os.unlink(on)
+ os.unlink(off)
+
+
+def test_status_line_says_what_you_are_looking_at():
+ lay = tempfile.NamedTemporaryFile("w", suffix=".kdl", delete=False)
+ lay.write('layout {\n tab name="api" purpose="project:api.a1" {\n'
+ ' pane purpose="agent:main"\n'
+ ' pane suspended=true command="top"\n }\n}\n')
+ lay.close()
+ with Session(SH, cols=90, rows=18, layout=lay.name) as s:
+ s.settle(20)
+ bottom = s.snapshot().text[-2]
+ check("it names the tab and the focused pane",
+ "api" in bottom and "agent:main" in bottom, repr(bottom))
+ # The top strip already answers "which tab" and "how many panes";
+ # the bottom is about the pane, so it must not just repeat that.
+ check("and does not repeat the pane count from the top strip",
+ "panes" not in bottom, repr(bottom))
+
+ ids = [p["id"] for p in s.panes()]
+ s.api("focus", id=ids[1])
+ s.settle(20)
+ check("a pane that has not started says so",
+ "not started" in s.snapshot().text[-2],
+ repr(s.snapshot().text[-2]))
+ os.unlink(lay.name)
+
+
+def test_status_line_reports_scrollback():
+ noisy = ["/bin/sh", "-c",
+ 'printf "\\033]2;p\\007"; i=0; while [ $i -lt 200 ]; do '
+ 'echo "line $i"; i=$((i+1)); done; stty raw -echo; cat']
+ with Session(noisy, cols=90, rows=18) as s:
+ s.settle(30)
+ check("nothing is said while you are in the present",
+ "scrolled" not in s.snapshot().text[-2],
+ repr(s.snapshot().text[-2]))
+ p = s.pane()
+ for _ in range(6):
+ s.send(rf"\e[<64;{p['content_x'] + 2};{p['content_y'] + 2}M")
+ s.settle(30)
+ check("looking at the past is said out loud",
+ "scrolled" in s.snapshot().text[-2],
+ repr(s.snapshot().text[-2]))
+
+
if __name__ == "__main__":
test_geometry()
test_status_bar_off()
@@ -199,4 +256,7 @@ if __name__ == "__main__":
test_min_pane_drives_collapse()
test_fail_open()
test_reload()
+ test_status_line_reserves_a_row_at_the_bottom()
+ test_status_line_says_what_you_are_looking_at()
+ test_status_line_reports_scrollback()
sys.exit(report())