feat: the page bar becomes a control, and [/] reach the modes about the document
Three tickets on one subject: paging.
improvise-rw6l — clicking a page chip opens a menu of that axis's items, with
a down-arrow saying so. Almost nothing had to be derived: `PageAxis::items` was
already projected and `ModelCommand::SetPageSelection` was already on the wire.
The one gap was that `RenderPageAxis` dropped the names, keeping the position
and count improvise-p1ym needed for `[`/`]`. `items` is relayed INSIDE `cycle`
rather than beside it, so there is one predicate and not two: a Filter axis has
no cycle, therefore no arrow, no menu, no items, and composes nothing if a click
reaches it — all four off `PageAxis::cycle`, the one home of gotcha 27's split.
improvise-771e — the browser tile bar said "Quarter Pag". `short_label` is three
characters so the TUI aligns in a fixed-width terminal (gotcha 26); a browser has
no column to fit. `render.rs` asks `plain_label` instead; `short_label` is
untouched. Note what pinned the truncation was `harness/tests/drill.spec.js`,
not `tests/grid_frame_agreement.rs`, which does not mention the tile bar.
improvise-wiew — `[`/`]` move from Normal onto a new `document_keymap` between
the global and the modes whose subject IS the document (Normal, the three
panels, TileSelect; RecordsNormal through Normal). Help and the import wizard
take the global directly. Per the user's ruling: an overlay has a subject of its
own, and these are the first shared keys that MUTATE the document — under the
help overlay that is an invisible change to the grid it is covering.
Boundary crossings to flag, both outside the brief's stated write scope and
neither a wire change:
- `resolve.rs` gains `Click::PageItem` and `lib.rs` a `click_page_item`
binding. Composing the command anywhere else would put a derivation in the
page, which design-principles §5 forbids; `Command`/`ModelCommand` are
untouched.
- `improvise-command/src/command/keymap.rs` gains three tests. The two
existing guards were the mechanism that forced the wiew argument, so they
had to be answered where they live.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
@@ -1487,6 +1487,69 @@ agreement, and it is what `no_mode_binds_a_panel_toggle_of_its_own` now keeps.
|
||||
is the thing being removed, and two equal-but-separate globals would satisfy
|
||||
any value comparison.
|
||||
|
||||
### The layer below it: `document_keymap` (improvise-wiew)
|
||||
|
||||
The global above is **all seventeen modes**, and that answer is unchanged. What
|
||||
changed is that a second shared layer now sits between it and some of them.
|
||||
|
||||
The user asked for `[`/`]` "probably in the global keymap", and then answered
|
||||
the question that left open himself: *"the help display (and import wizard,
|
||||
etc.) shouldn't respond to these keys, but the 'normal' modes like
|
||||
categories/tiles/formulas/etc. should."*
|
||||
|
||||
The distinction is **is the document the subject right now**, and it is genuinely
|
||||
a new one rather than the global's argument applied again. Every key the global
|
||||
binds — `?`, `:`, the three panel toggles — is a **UI** action: it opens a room,
|
||||
it does not change the document. `page-next`/`page-prev` resolve to
|
||||
`ModelCommand::SetPageSelection`, which is `EffectKind::Model(LayoutGeometry)`.
|
||||
They are the first shared keys that *mutate*, and under the Help overlay that is
|
||||
a mutation the user cannot see, because the overlay is covering the grid it
|
||||
just moved.
|
||||
|
||||
So the chain is three deep:
|
||||
|
||||
```
|
||||
global ? : and the panel toggles — every mode
|
||||
└── document [ ] — Normal, the three
|
||||
├── Normal panels, TileSelect; RecordsNormal
|
||||
│ └── RecordsNormal through Normal
|
||||
├── FormulaPanel / CategoryPanel / ViewPanel
|
||||
└── TileSelect
|
||||
├── Help global only
|
||||
├── ImportWizard global only
|
||||
└── the text-entry modes and SearchMode, unchanged
|
||||
```
|
||||
|
||||
**The name is the guard.** Nothing in the code stops the next person parenting
|
||||
Help to this layer; what stops them is that it is called `document_keymap` and
|
||||
not `common` or `shared`, so its name answers "should my new mode inherit it?"
|
||||
A name describing *who* inherits a layer invites everything to join, and the
|
||||
distinction dies within two waves.
|
||||
|
||||
**RecordsNormal inherits it once, through Normal.** It already parents Normal,
|
||||
so it reaches the layer transitively; parenting it directly as well would be a
|
||||
second edge with nothing keeping the two in step. That is asserted on the chain
|
||||
identity rather than on behaviour, because a duplicated edge answers `page-next`
|
||||
correctly on the day it is added and only diverges later.
|
||||
|
||||
**The layer owes the same Char-only constraint as the global**, and for the
|
||||
identical reason: it is reached by *fallthrough*, so a non-Char binding on it
|
||||
would fire while a descendant's `AnyChar` was typing. No descendant binds
|
||||
`AnyChar` today — which is exactly why the constraint is written down as a test
|
||||
rather than left to the arrangement. An unconstrained shared layer is where the
|
||||
next "just put it in the shared one" lands.
|
||||
|
||||
**Two things that cost nothing and were checked anyway.** Text entry is
|
||||
untouched: the fallback order is `exact → Char(NONE) → AnyChar → Any → parent`,
|
||||
so a text-entry mode's `AnyChar` answers `[` before any parent is consulted, and
|
||||
typing a bracket into a category name still types it. And `prefix_keymaps_are_flat`
|
||||
is about the *sub-keymaps a prefix opens*, not about inheritance depth, so a
|
||||
third level of parents violates nothing it asserts.
|
||||
|
||||
The browser follows for free: `resolve.rs` dispatches on the command **name**,
|
||||
so every mode that now reaches `page-next` composes it in a browser too, with no
|
||||
second table to update. That is the whole point of one shared keymap.
|
||||
|
||||
### `TextEntry` — the spine, welded
|
||||
|
||||
Every text-entry mode has the same spine: characters append to one named
|
||||
|
||||
Reference in New Issue
Block a user