Skip to content

+ Pinned columns in the window, a refresh picker in both front-ends, and a column copy - #86

Merged
Hawkynt merged 5 commits into
mainfrom
pinned-columns-and-refresh-picker
Aug 21, 2026
Merged

+ Pinned columns in the window, a refresh picker in both front-ends, and a column copy#86
Hawkynt merged 5 commits into
mainfrom
pinned-columns-and-refresh-picker

Conversation

@Hawkynt

@Hawkynt Hawkynt commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Six boxes in §11, §12, §57 and §94, and the two defects that looking at the
pictures turned up.

§11 — freeze and pin columns, in the window as well

The toolkit grew a horizontal offset and a Frozen flag on its columns, which
is the seam this row was refused for. The window keeps a count of leading
columns rather than a set of ticked ones, the same as the terminal: the list
draws its pinned run as the leading run and stops at the first column that is
not, so a pinned third column with two scrolling ones in front of it is a
layout nobody can draw. # moves the boundary in the terminal, Ctrl+Shift+P in
the window, and the count survives a restart on both sides.

Two defects came out of the first capture of it, neither of which any test
could have seen:

  • The header hit-test added the scroll offset to every x, so a click on a
    pinned caption picked whichever column had slid underneath it and a resize
    started there dragged the wrong boundary.
  • The list fills a row's ground once for the whole row and then draws the
    pinned columns in a second pass over the scrolled ones, so a pinned cell
    arrived with somebody else's value already in it and put its own on top.
    Every pinned cell in the first picture showed two values at once.

§12 — a refresh picker, and a difference between pausing and asking by hand

§12 has listed eight refresh settings from the beginning and neither front-end
could reach any of them: the terminal could pause, the window could not even do
that, and the rate was fixed for the life of the process. Both now have a
picker over one shared list of rates — View ▸ Refresh in the window, d in the
terminal, which is the letter every other terminal monitor binds a sampling
delay to.

Paused and by-hand are two entries. Both stop the tick; only the second is
remembered, because a monitor that opened paused because it was paused when it
was last closed is a monitor showing a table of nothing at all. The rate
underneath is kept either way. Neither disturbs the list — nothing is rebuilt
while the tick is off — and the terminal's loop reads the rate each time round,
so a rate chosen mid-wait shortens the wait that is running.

§11 — a column copy, and the full forensic set

A column copy was refused for want of a cell selection to take it from. There
is none in either front-end and none is needed: a column copy needs a column,
and both have had a column cursor since their headers grew gestures. Ctrl+Y in
the terminal, Ctrl+Shift+D in the window, over the ticked rows if any are
ticked and everything on screen otherwise.

The forensic set is the expert set plus the two halves it was missing — who a
process really is, and what it is doing to the disk. Deliberately the dearest
set in the file: the package, the digest and the descriptor count each cost a
reading the sampler does not otherwise take.

It is also twenty-five columns, which turned up the third defect. A set with
more columns than the terminal can hold even at their floor was reserving room
for the ones past the edge, and the columns that were drawn paid for it: the
process name came out six characters wide at a hundred and sixty columns, which
renders every row as kthrea. Room is kept only as far as the screen can
reach now; the rest is reached by scrolling sideways, which is what that scroll
is for. The name gets thirteen characters instead of six.

Verification

0 warnings, 1749 tests green, --self-test agrees with the runtime on all 37
checks. Frames captured at 80×24, 120×30 and 160×50, under a UTF-8 locale and
under LANG=C with TERM=dumb; the default frames are byte-identical to
before, and the picker fits inside eighty columns with nothing clipped. The
window was photographed with the forensic set pinned and scrolled to its far
end, which is the state a picture of the default six columns cannot show.

The benchmark's allocation gate reads 202 and 211 bytes a sample against a 512
floor. One earlier run read 724 against a 717 allowance while the capture
script's workload was still spawning processes — that allowance is
512 + 1024 × new processes per sample, and nothing in this branch is in the
sampling path.

Left open, and why

  • §57.2 friendly/tree/flat — friendly needs §13's notion of an application, and
    there is nothing to read one off.
  • §57.3 s as sort — a deliberate binding, documented as such, and keys.conf
    can swap it.
  • §83 application, publisher, aggregations — need §70's signature verification
    and §82's sums.
  • §83 package grouping switched on mid-session — reading a package costs a
    database lookup per image and the probe's expensive readings are chosen when
    it is built (§5.4). Making them switchable at run time is the probe's
    business, not the front-ends'.
  • §12 dead processes visible for one cycle — the styling and the palette exist
    on both sides, but a ghost row needs a record in the snapshot after the
    process has gone, which is the sampler's to provide.

Two things noticed and deliberately not touched, both pre-existing and both in
files this change has no business in:

  • The Working set header loses its W behind the CPU % header beside it at
    the widths this machine's settings file happens to hold. It is in the
    committed screenshot too, and it is the toolkit's header painter.
  • Start time at its registry width cuts the last digit off a full timestamp —
    2026-08-21 22:03:2. Visible only in the sets that carry the column, which
    is why nothing had photographed it. The width is in FieldRegistry.

…round

The toolkit grew a horizontal offset and a Frozen flag on its columns, which is
what the freeze/pin row of §11 was waiting for. The window keeps a count of
leading columns rather than a set of ticked ones, the same way the terminal
does: the list draws its pinned run as the leading run and stops at the first
column that is not, so a pinned third column with two scrolling ones in front
of it is a layout nobody can draw.

Two things had to be fixed to make the first picture of it true. A header
hit-test that added the scroll offset to every x picked whichever column had
slid under a pinned caption, so the mapping now asks where the pinned run ends
first. And the list fills a row background once for the whole row and then
draws the pinned columns in a second pass over the scrolled ones, so a pinned
cell arrived with somebody else's value already drawn in it and put its own on
top — every pinned cell in the first capture showed two values at once.

The count survives a restart on both sides, and the shoot log marks where the
pinned run ends so a reader can see which columns are held still rather than
only how many.
…ng and asking by hand

§12 has listed eight refresh settings since the beginning and neither front-end
had a way to reach any of them: the terminal could pause and the window could
not even do that, and the rate came from --interval or the settings file and
was fixed for the life of the process. Both now have a picker over one list of
rates, kept beside the settings that carry it so the window's menu and the
terminal's `d` cannot come to offer different ones.

Pausing and refreshing by hand are two entries rather than one. Both stop the
tick; only the second is remembered, because a monitor that opened paused
because it was paused when it was last closed is a monitor showing a table of
nothing at all. The rate underneath is kept either way, so switching the tick
back on returns to the rate somebody chose.

Neither stops the list holding still — nothing is rebuilt while the tick is
off, so the selection, the expanded nodes and the scroll position are where
they were left. The terminal's loop reads the rate each time round rather than
keeping the one it started with, and a rate chosen mid-wait shortens the wait
that is running: asking for a quarter of a second in the middle of a ten-second
wait and then watching nothing happen for ten seconds is how a picker gets a
reputation for not working.
…ing for columns it never drew

Three §11 rows that were each waiting on something small. The copy of a column
was refused for want of a cell selection to take it from; there is none in
either front-end and none is needed, because a column copy needs a column and
both have had a column cursor since their headers grew gestures. Which rows it
takes is the rule the row copy already follows: the ticked ones if any are
ticked, everything on screen otherwise.

The full forensic set is the expert set plus the two halves it was missing —
who a process really is, and what it is doing to the disk. It is deliberately
the dearest set in the file: the package, the digest and the descriptor count
each cost a reading the sampler does not otherwise take, and asking for a
forensic table is asking to pay for them.

It is also twenty-five columns, which is what turned up the third thing. A set
with more columns than the terminal can hold even at their floor was reserving
room for the ones past the edge, and the columns that were actually drawn paid
for them: the process name came out six characters wide at a hundred and sixty
columns, which renders every row as "kthrea". Room is now kept only as far as
the screen can reach — the rest is reached by scrolling sideways, which is what
that scroll is for. The name gets thirteen characters instead of six, and a
sweep over every width from forty to four hundred says nothing hangs off the
edge and no column vanishes.

The window's copies were untestable, because the toolkit's clipboard wants a
backend and a test has no display. Building the text is split from handing it
over, so what would go on the clipboard can now be read without one.
Six boxes in §11, §12, §57 and §94 that were describing the program as it stood
before the pinned columns, the refresh picker, the column copy and the forensic
set. The counting paragraph in §0 is deliberately left alone: it says of itself
that it goes stale the moment two branches are in flight against this file, and
it is right.
… sixty times

One stackalloc for the whole loop rather than one per width, which the analyser
is right about and an incremental build had been hiding.
@Hawkynt
Hawkynt merged commit e33cda1 into main Aug 21, 2026
11 checks passed
@Hawkynt
Hawkynt deleted the pinned-columns-and-refresh-picker branch August 21, 2026 20:27
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