Expand description
What is on screen: two independent axes, with presets on top.
§Two axes, not four modes
The set of views a reader asked for was “default, all-ignored, vendor, all”, and those four names mix two things that vary independently:
- Tier — whether a claim is one a rule named (
Tier::Named) or one only the gitignore fallback found (Tier::Ignored). “all-ignored” is a statement about this axis and nothing else. - Kind — the closed vocabulary #623 established and #652 extended at both ends, ordered
by what it costs to lose:
Kind::Unrecoverable,Kind::Dependencies,Kind::Build,Kind::Cache,Kind::Noise. “vendor” is a statement about this one.
Modelled as four opaque modes, “show me every cache that a rule named” is not expressible and never becomes expressible without a fifth mode. Modelled as two axes it already is, and the presets are a convenience over the top rather than the vocabulary itself.
§The presets are a path through the lattice, one axis per step
f/F walk default → dependencies → all-ignored → all, and each step moves exactly one
axis while carrying the other forward — so all-ignored is “what I am looking at, plus
the gitignored tier” rather than a jump back to everything. That is what makes four names
four distinct views. See Preset for the table.
§Expressible has to mean expressible BY A READER
Two axes inside a struct that no key can move is a model with a claim it cannot cash. So the
presets are shortcuts and the axes have keys of their own: t moves the tier axis on its
own, and one key per Kind toggles that member of the other. Every combination of the two
is reachable — “every cache a rule named” is f to default, then d and b — and none of
them had to be anticipated as a mode.
§default narrows, so the header says what it left out
A run opens on Preset::Default, which shows what rules named and hides the gitignore
fallback. That is a filter that is on without having been asked for, which is the shape the
age floor was resolved against — “silently keeps” is “silently deletes” seen from the other
side. What makes it honest rather than silent is that the count it hides is on the header,
beside the number it qualifies, from the first frame. See super::state::View::out_of_view.
§Gitignored FILES are a third axis, not a third tier
A gitignored file is claimed by tier two, so the obvious home for it is a third value on the
tier axis — and that does not survive the presets. Every step of f’s cycle moves exactly
one axis, and all would then have to widen the tier axis and the kind axis in one step
to reach files. The / pattern already had this shape and was settled the same way: it
decides what is on screen, it is orthogonal to both axes, and no preset touches it.
So files get an axis and a key of their own, i, and the request’s actual sentence — that
ignored files be includable and excludable independently of ignored directories — falls
out of that rather than being arranged for. It starts off, because a real ~/repos
holds tens of thousands of them; what makes that honest is the same thing that makes
default honest, a count of what is out of view on the header from the first frame.
§The pattern is part of the lens
/’s regex is a third thing that decides whether a claim is on screen, so it lives here
rather than beside here. That matters because a mark stores the lens it was made
through (super::state::View), and a mark made under /nx has to keep meaning
/nx when the pattern is cleared, exactly as a mark made under Dependencies keeps meaning
Dependencies.
Structs§
- Kinds
- Which kinds are on screen.
- Lens
- Everything that decides whether a claim is on screen.
- Tiers
- Which tiers are on screen. Both axes are sets, which is what makes an unanticipated combination expressible without a new mode.