Skip to content

fix(tui): scrollable inspect screen, masked secrets, working mouse wheel - #84

Merged
damusix merged 1 commit into
nextfrom
fix/inspect-scroll-masked-secrets
Sep 4, 2026
Merged

fix(tui): scrollable inspect screen, masked secrets, working mouse wheel#84
damusix merged 1 commit into
nextfrom
fix/inspect-scroll-masked-secrets

Conversation

@damusix

@damusix damusix commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Inspect built its context as a nested tree. Ink has no scroll offset, so a viewport can only draw a slice of a flat list — a tree cannot be sliced, and everything past the fold was unreachable while the screen's own footer got pushed off to make room. All four of its views (summary, expanded shapes, rendered SQL, render error) are now one element per visual line behind the same viewport the explore and SQL screens use.

Two non-obvious consequences: one row must stay one row, so cells truncate and free text is wrapped before Ink sees it; and the screen opens a single focus scope with skip rather than one per phase, because React runs a child's effects before its parent's, so a screen-level push lands above its own SearchableList and takes the keys the picker was mounted to receive.

$.secrets reported a key count, which cannot tell a stale password from a fresh one. Both secret tiers now show a partial reveal that narrows as the value shortens, with the length beside it as a number rather than encoded in the mask width. $.env gets the same treatment — it is all of process.env and nothing in the screen can tell which of its keys are credentials.

Second commit fixes mouse-wheel scrolling, which never worked in any viewport. Only SelectList and ResultTable consumed wheel notches, so the explore detail view, the full-text overlay and the row viewer ignored them too. Because the TUI runs in the alternate screen (no scrollback) and mouse tracking intercepts the notches a terminal would otherwise translate into arrow keys, enabling the mouse had actively removed the only wheel behaviour those panes had. useWheelScroll splits the wheel-only half out of useRowMouse, which needs row refs a viewport does not have.

Also fixes an error branch that could never render: a helper that failed to load showed as "Unknown phase".

Keyboard scrolling was verified working before any of this, so the wheel was the actual gap. The wheel test was confirmed non-vacuous by mutation.

https://claude.ai/code/session_01JGZ8ocdNed7TFFEbccQsW2

@damusix damusix changed the title fix(tui): scroll the inspect screen, mask secrets on it fix(tui): scrollable inspect screen, masked secrets, working mouse wheel Sep 4, 2026
Ink has no scroll offset, so a viewport can only draw a slice of a flat
list and a tree cannot be sliced. Inspect built its context as a nested
tree, so everything past the fold was unreachable and the screen's own
footer was what got pushed off to make room. All four views — summary,
expanded shapes, rendered SQL, render error — are now one element per
visual line behind `ScrollPane`.

One row must stay one row or the window arithmetic is wrong by the
difference. `wrap="truncate"` bounds a cell's width but not its height,
so `oneLine` flattens line breaks where text enters a one-row cell:
nothing here controls what it displays, and a secret can be a PEM key, an
environment variable can hold anything, and a helper's error message can
be a multi-line diagnostic.

The screen opens one focus scope with `skip` rather than one per phase.
React runs a child's effects before its parent's, so a screen-level push
lands above its own `SearchableList` and takes the keys the picker was
mounted to receive.

`$.secrets` reported a key count, which cannot answer what the screen is
opened to ask: a stale password and a fresh one are both `Object (7
keys)`. It shows a partial reveal instead, narrowing as the value
shortens, with the length beside it as a number rather than encoded in
the mask width. Banding counts code points, so a non-BMP character is
never sliced through a surrogate pair. `$.env` gets the same treatment —
it is the whole of `process.env` and nothing here can tell which keys are
credentials.

The mouse wheel now scrolls every viewport. It reached only `SelectList`
and `ResultTable`, the two `useRowMouse` callers, so the explore detail
view, the full-text overlay and the row viewer ignored it. That is worse
than unhandled: the TUI runs in the alternate screen, which has no
scrollback, and mouse tracking takes the notches a terminal would
otherwise translate into arrow keys — turning the mouse on is what
removed the only wheel behaviour those panes had. `useWheelScroll` is the
wheel-only half of `useRowMouse`, which needs row refs a viewport has
none of.

Also fixes an error branch that could never render: a helper that failed
to load set the error phase with a file selected, which required
`!selectedFile`, so the likeliest failure showed as "Unknown phase".

Claude-Session: https://claude.ai/code/session_01JGZ8ocdNed7TFFEbccQsW2
@damusix
damusix force-pushed the fix/inspect-scroll-masked-secrets branch from eb5efa7 to 353f076 Compare September 4, 2026 20:15
@damusix
damusix merged commit 37abd22 into next Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant