Expand description
foldable-view-mode — the one place <Tab> folds the block at point.
§Why a shared minor and not a chord per view
A grouped, read-only view folds by blocks, and cycling the block at the cursor is a property of that class of view rather than of any one of them. By the “shared behaviour is a minor mode, never a copied keymap” standing rule the chord belongs here once.
It did not start that way, and the shape of the drift is the argument.
As of 2026-09-01 magit-nav-mode bound both chords, and its own module
doc already stated the generalisation — “navigating sections and folding
are meaningful wherever there are sections” — while scoping it to magit.
org-agenda-mode then grew an independent copy. Meanwhile project
search, the LSP references view, *problems* and *compilation* had
neither chord: four foldable grouped views with no way to collapse a
block, and nobody noticed, because a gap in a copied set does not announce
itself. That is the same failure refreshable-view-mode closed for gr,
one chord later.
§The split
Exactly refreshable_view_mode’s:
<S-Tab>is owned outright. Cycling every fold in the buffer is generic — magit’saction:magit-cycle-sectionsbody was literallyEffect::AppAction(AppEffect::CycleFoldsGlobal), the same expression this mode’s own action evaluates to. There is nothing per-view to declare, so there is no declaration.<Tab>is a target, not a body. A view that wants the plain cycle-the-fold-at-cursor namesFOLD_TOGGLE_DEFAULT_ACTION; a view with a genuine specialisation names its own action. Magit’s is real: on a status file line the first press expands the diff so<Tab>and=agree, and everywhere else it is the plain toggle.
Resolution is host-side (Editor::resolve_fold_toggle_action) because it
needs the buffer’s active-mode set, which lives on the editor rather than
in the ServiceRegistry — the same reason the refresh resolution lives
there.
§Activation
Automatic: a mode returning Some from Mode::fold_toggle_action pulls
this minor in through the implies cascade. One line per view, and no second
thing to remember — forgetting it would kill the chord exactly as silently
as the copied keymaps did.
ActivationPolicy::Manual so it never auto-attaches to ordinary buffers.
<Tab> in a document buffer is the terminal alias for <C-i>,
jump-list-forward, and must stay that way. Taking it costs that motion in
the views that opt in, which is the deliberate trade: in a grouped
read-only view you navigate with <CR> and ]], and folding a block is
the thing you reach for.
Structs§
- Foldable
View Mode foldable-view-modeminor. Two keymap entries, no per-buffer resources (Guard = ()), and no<Tab>handler — that body belongs to each view.
Constants§
- FOLD_
TOGGLE_ DEFAULT_ ACTION - The body a view names when it wants the ordinary behaviour: cycle the fold containing the cursor. Named explicitly rather than defaulted so that “this view folds” is a statement the view makes, not one it falls into.
- VIEW_
FOLD_ CYCLE_ ACTION <S-Tab>. Owned outright — see the module doc.- VIEW_
FOLD_ TOGGLE_ ACTION - The canonical command name
<Tab>resolves to. The host intercepts this id, resolves the active modes’ declared fold-toggle action, and dispatches that.
Functions§
- register_
foldable_ view_ actions - Register the three action names.
- register_
foldable_ view_ mode - Register
FoldableViewModeinregistry. Called byregister_foundation_modes; it must be registered for the implies cascade to pull it in (an unregistered shared minor is logged atdebug!and the chord simply does not bind).