diff options
| author | user <user@clank> | 2026-08-13 22:07:45 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-13 22:07:45 +0200 |
| commit | a8ea4e888938e562885b1a0f009f5743939a879b (patch) | |
| tree | 2ae5df21d4919cfe128830376b55dca814418496 /docs | |
| parent | checks: ignore __pycache__ (the up check imports a sibling check) (diff) | |
| download | sl0ppi-a8ea4e888938e562885b1a0f009f5743939a879b.tar.gz sl0ppi-a8ea4e888938e562885b1a0f009f5743939a879b.tar.xz sl0ppi-a8ea4e888938e562885b1a0f009f5743939a879b.zip | |
sl0p: keep a templated tab's purpose, so runtime tabs get a status bar
Clicking the bar's `+` made a tab with no status bar. The button only exposed
it: pressing `n` in TAB mode did the same, in any `sl0ppi up` session.
The chain: a generated layout had no default_tab_template, so a tab created at
runtime had nothing to take a bar from. It had none because
parse_tab_node_with_template read a tab node's name, cwd and focus but never
its `purpose` -- so templating erased the purpose that IS identity here
(`sl0ppi ls` finds project tabs by it), and the CLI worked around that by
inlining the template into every tab instead of emitting it.
Fixed at the root: a templated tab keeps its own purpose, and the CLI emits
`default_tab_template` again. The generated layout also shrinks -- one copy of
the bar's configuration instead of one per tab.
The two properties trade off against each other, so sl0ppi-up-live.py now
asserts both at once: `sl0ppi ls` still sees a tab per project, and every tab
including one created at runtime has exactly one status bar. Confirmed by
reverting each half separately: without the parser fix the tabs lose their
purpose and `ls` shows "alpha —"; without the CLI change the runtime tab has
zero bars, which is the reported bug.
Two measurement traps cost an hour here and are now written down: counting bars
by grepping dump-layout also counts the template and every swap layout ("4 bars
for 3 tabs"), and list-panes stops reporting borderless plugin panes for a tab
once a client has rendered it.
Also in here, from the same session:
- the split button check found buttons by searching for " + " on any row with a
frame glyph, which matches the stack list's "+N more" once two panes sit side
by side, and then reports the product broken. It now requires the frame
corner the button is drawn against.
- the checks killed their sessions but did not delete them, so each run left an
"EXITED - attach to resurrect" entry: 35 had quietly filled the session
picker. They now delete-session by name.
- and the trap that cost the user their running client: I killed a bare
`sl0ppij` because "there are no user sessions on this box". That was a guess,
not evidence, and wrong. A check's processes always carry that run's own
socket dir or `attach sl0ptest-...`; a bare `sl0ppij` with a cwd in the repo
is a human's. Written into the handover next to the `pkill -f` trap, which is
the same mistake in a different costume.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/HANDOVER.md | 24 | ||||
| -rw-r--r-- | docs/roadmap.md | 66 |
2 files changed, 84 insertions, 6 deletions
diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md index 641ac12..1e3fe96 100644 --- a/docs/HANDOVER.md +++ b/docs/HANDOVER.md @@ -167,9 +167,11 @@ bar. See `docs/roadmap.md` for each with its measurements. fails. - **Single-line KDL needs `;` between nodes.** `tab x { pane }` will not parse; emit multi-line. -- **A tab template destroys tab purposes** — identity is a tab `purpose`, and - templating replaces the tab's root layout. That is why `sl0ppi` inlines the - template into each tab instead of emitting `default_tab_template`. +- **A tab template used to destroy tab purposes** — `parse_tab_node_with_template` + never read `purpose` off the tab node, so the template's (none) won. Fixed; + `sl0ppi` emits `default_tab_template` again, which is also what gives a tab + created at runtime a status bar. If you ever revert that line, the CLI has to + go back to inlining, and runtime tabs lose their bar. - **The tab test harness does no rendering**, so `panes_to_hide` is always empty and stack-related bugs cannot be reproduced in it. Use a scripted pty. - **`action list-panes` hides borderless plugin panes once a client attaches.** @@ -189,9 +191,19 @@ bar. See `docs/roadmap.md` for each with its measurements. - **The pane's geometry is not where its frame is drawn.** With a gap, the frame is inset from the allocation: use `Pane::frame_rect()` for anything the user can see, `position_and_size()` only for the layout solver. -- **Clean up test sessions.** A background-created session I left behind is what - produced a "MY FOCUS" bug report from the user. The live checks now reap their - own servers; anything else you spawn by hand, kill by pid via `comm`. +- **Never kill a `sl0ppij` you cannot PROVE is yours.** I killed the user's live + client on the reasoning "there are no user sessions on this box" -- a guess, + not evidence, and wrong. The evidence was right there and said the opposite: a + check's processes always carry that run's own socket dir + (`--server /tmp/sl0p-<run>/...`) or `attach sl0ptest-...`, while a bare + `sl0ppij` with a cwd in the repo is a human's. If the args do not contain your + own temp dir, it is not yours. +- **Clean up test sessions, and DELETE them.** A background-created session I + left behind is what produced a "MY FOCUS" bug report from the user, and + `kill-session` alone leaves them listed as "EXITED - attach to resurrect": + 35 of mine had silently filled the session picker before I noticed. The live + checks now `delete-session` their own session by name; anything you spawn by + hand, clean up the same way. - **`send_cli_scroll_up_action` flakes** (scrolled 1 line where the snapshot has 2), seen once in ~10 full runs. It is the CLI-action raciness already tracked above, not a rendering bug -- re-run before chasing it. diff --git a/docs/roadmap.md b/docs/roadmap.md index 068129f..675f82d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -355,6 +355,42 @@ render half a box. That one function also returns where the content line starts, and click routing reads it — which is why a click on the new box's border hits nothing instead of the widget underneath. +### A tab made at runtime had no status bar + +Reported as "creating a new tab with the icon from the status bar created a tab +without statusbar" -- but the button was innocent: the `n` keybinding did it +too. A generated session had no `default_tab_template`, so there was nothing for +a runtime tab to take a bar from. + +The reason it had none was the trap recorded below: templating a tab dropped its +`purpose`, and purpose is identity, so the CLI inlined the template into every +tab instead. That trap turned out to be one missing line in the fork -- +`parse_tab_node_with_template` read `name`, `cwd`, `focus` and +`split_direction` off the tab node but never `purpose`, so the template's (None) +won. It now keeps the tab's own, and both properties hold at once: + +| | inlined (before) | templated (before) | templated (now) | +|---|---|---|---| +| tab keeps `purpose` | yes | **no** | yes | +| runtime tab gets a bar | **no** | yes | yes | + +So `sessionLayoutKdl` emits `default_tab_template` again, and the generated +layout shrank further: one copy of the bar's configuration for the session +rather than one per tab. `singleTabLayoutKdl` still inlines -- that layout is +handed to a session that already has a template, and emitting another would give +the new tab two bars. + +`sl0ppi-up-live.py` checks both halves, because fixing either one alone +regresses the other: every tab (including one made at runtime) has exactly one +bar, and `sl0ppi ls` still finds a tab per project. Confirmed by reverting each +half in turn and watching the matching assertion fail. + +Counting bars needs care: `dump-layout` includes the template itself and every +swap layout, so grepping it reports definitions as if they were panes -- that +cost an hour of chasing a doubled bar that did not exist. Count panes per tab +from `list-panes`, and do it BEFORE any client attaches (see the trap about what +that hides). + ### `sl0ppi up` and the generated layout Making the bar a `pane_template` broke `sl0ppi up` outright: @@ -385,6 +421,36 @@ attached it stops reporting the borderless plugin pane, which had me believing the bar was gone in cases where it was on screen the whole time. `dump-layout` and the screen agree; `list-panes` does not. +### A tab made at runtime now gets a status bar + +Clicking the bar's `+` (and pressing `n` in TAB mode) produced a tab with no +status bar in `sl0ppi up` sessions. The button only made it visible: a generated +layout had no `default_tab_template`, so there was nothing for a new tab to take +a bar from. + +The reason it had none was `parse_tab_node_with_template`, which read a tab +node's `name`, `cwd` and `focus` but not its `purpose` -- so templating a tab +erased the purpose that is the CLI's notion of identity, and the CLI worked +around it by inlining the template into every tab. That is now fixed at the +root (`sl0p_a_templated_tab_keeps_its_own_purpose`), and the CLI emits the +template again: + +| | inlined (before) | template (now) | +|---|---|---| +| tab keeps `purpose=` | yes | yes | +| runtime `new-tab` has a bar | **no** | yes | +| copies of the bar's config in the layout | one per tab | one | + +Both halves are checked by `sl0ppi-up-live.py`, because they trade off against +each other: it asserts `sl0ppi ls` still sees a tab per project AND that every +tab, including one created at runtime, has exactly one status bar. + +Count bars per tab from `list-panes`, not by grepping `dump-layout`: that dump +also contains the template itself and every swap layout, so substring counting +there reports "4 bars for 3 tabs" and sends you looking for a doubling bug that +does not exist. And do it before any client attaches, because `list-panes` stops +reporting borderless plugin panes for a tab a client has rendered. + ### Still open on the bar Content and further click targets: a close-`x` per tab, session name → session |
