Repository navigation
feat: pin rows to the top, and a Nerd Font icon set (v1.0.0) - #21
Merged
Merged
Conversation
Pinning (`p`) Rows sort by urgency, which is right for "who needs me" and wrong for watching two or three specific agents while the fleet churns underneath them. `p` lifts a row into a block at the top, so `1`-`9` and `g` become stable addresses for the agents you chose. The block is group zero: it heads its own run in every mode, urgency included, because rows lifted out of rank order with nothing to explain them read as a sort fault. A pinned row leaves its project or session group and stops being counted in that heading, and group rank is computed from unpinned members only, so pinning a group's only blocked agent lets that group fall back to where its remaining members put it. Pins are keyed by AgentId, never by index, and dropped with their row: pane ids are recycled and a pin that outlived its agent would transfer to whoever got that pane next. The set is shared through a `pins` file next to the status records, so a pin set in one session shows in every panel and survives a reload. That prune is scoped to sessions this panel can see, or it would unpin another panel's row on the next write. `q hide` gave up its footer slot to `p pin`; Esc still hides. Icons Every glyph moves behind one table with two sets, selected by the `icons` config key: `nerd` (default) and `unicode` (the old glyphs). This also removes a duplicated icon_for in tour.rs that had already drifted. Several glyphs were chosen by rendering candidates side by side at 14px rather than by name: cod-bell_dot collapsed into a smudge, cod-fold drew an X that read as a failure next to the real one, and a bell in the notified gutter put two bells on one row when the status was also a bell. The last of those is now covered by an exhaustive collision test, since the hand-listed pairs it replaced are exactly what let it through. Three tests pin the constraint the layout rests on: one char per glyph, nothing above the BMP, nothing double-width. That is what excludes nf-md-* and emoji, and it is why this is width-neutral rather than a rendering change. Demo A second GIF, demo/v1-pinning-and-icons.gif, covers just these two features for the release notes; the full tour keeps its own pacing. Both are staged through the panel's own row builders, so they cannot drift from what it draws. Captions are gone and the frame unit is now 22ms (~45fps), with the canvas no longer reserving a caption band. Verified in a throwaway Zellij session: `p` draws the block and writes the file, a seeded file is adopted by a panel that never pinned anything, and the baseline v0.13.1 wasm side by side still draws the old glyphs.
mohseenrm
force-pushed
the
feat/pinning-and-icons
branch
from
September 25, 2026 05:42
0efb27b to
40c6edf
Compare
mohseenrm
marked this pull request as ready for review
September 25, 2026 05:44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pinning (
p)Rows sort by urgency, which is right for "who needs me" and wrong for the other thing the panel gets used for: watching two or three specific agents while the rest of the fleet churns. Those agents had no fixed address, and 1-9 landed on whoever was loudest.
plifts a row into a block at the top, above everything else, whatever its status. Inside the block urgency still decides, so pinning changes which rows are on top, not how they rank among themselves.The design rule that settles every grouping interaction: the pinned block is group zero. Computed before grouping, own heading in every mode, and its rows are invisible to the grouping below.
workingrow above an unpinnedfailedone reads as a sort bug.api (1), not(2). A heading whose number exceeds the rows beneath it would be worse than no heading.Persistence. Pins are keyed by
AgentId, never by index, and dropped with their row, because pane ids are recycled and a pin that outlived its agent would transfer to whoever got that pane next. The set is shared through apinsfile next to the status records, written atomically and read back by the existing scan, so a pin set in one session shows in every panel and survives a reload. That prune is scoped to sessions the panel can actually see, or adopting the shared set would unpin another panel's row on the next write.q hidegave up its footer slot top pin. Esc still hides, and it is the key people try unprompted.Icons
Every glyph moves behind one table (
src/icons.rs) with two sets, chosen by a newiconsconfig key:nerd(default) andunicode(exactly today's glyphs). This also deletes a duplicatedicon_forintour.rsthat had already drifted from the real one.Codepoints came from Nerd Fonts' own
glyphnames.jsonv3.5.1, searched by name across all 10,995 glyphs rather than picked from memory. Several were then changed after rendering them at 14px, which is the part no test can do:cod-bell_dotforwaitingcollapsed into a smudge; it isfa-bullseyenow.cod-foldforcompactdrew an X and read as a failure next to the real one; it iscod-archive.oct-dot_fill, and covered by an exhaustive collision test, since the hand-listed pairs it replaced are exactly what let that through.The constraint everything was picked against:
style::chars()counts characters and the layout assumes one char is one cell. Three tests enforce it - one char per glyph, nothing above the BMP, nothing double-width. That rules outnf-md-*(two UTF-16 units) and emoji (East-Asian-Wide), and it is why this is width-neutral rather than a rendering change.Demo
A second GIF,
demo/v1-pinning-and-icons.gif(189 KB), covers just these two features for the release notes; the full tour keeps its own pacing. Both are staged through the panel's own row builders - no recorder, no live session - so they cannot drift from what the panel draws. Captions are gone, the frame unit is 22ms (~45fps), and the canvas no longer reserves a caption band.Verification
./scripts/check.shgreen (all 8 checks: fmt, clippy-D warnings, 437 unit tests, hook e2e, installer e2e, live Zellij e2e, wasm build, shellcheck).Also verified in a throwaway Zellij session, isolated from config and spool:
pdrew thepinned (1)heading, put the pin glyph in the gutter, and wrotepins.pagain cleared all three.pinsfile was adopted by a panel that had never pinned anything, which is the cross-session sharing path end to end.▶,◌) where this build drew the new ones.One bug caught by a test while writing it: pin lines parse with
rsplit_once(' '), notsplit_whitespace, because a session name may contain spaces and the pane id is the only field that never does.