Skip to main content

Module lens

Module lens 

Source
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:

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.

Enums§

Preset
A named point on the two axes, which is what one key cycles through.
Tier
Which tier claimed a directory.