Expand description
AppEffect – the typed App-side effects produced by free-form
CommandKind::Action registrations.
Background: the keymap-bound Action enum in lattice-ui-tui
historically encoded the App’s response to non-grammar chords
(<Esc>, o, <C-w>v, …). Slice 8.i (see
docs/dev/notes/8i-approach.md) retires
the per-binding Action bridge and routes those chords through
the unified dispatcher’s CommandKind::Action branch instead.
Action-kind registry entries return Effect::AppAction(AppEffect);
the App’s apply_effect then matches on the inner AppEffect
variant.
Why a sibling type to Effect rather than a flat extension:
Effect’s existing variants describe core / dispatcher-native work (Edits,SelectionChange,Yank,EnterMode,Substitute, …) and ex-command-emitted App work (SaveBuffer,OpenBuffer,LspRestart, …). Both are produced by code paths that resolve a typed grammar concern into a typed effect.AppEffectis for chord bindings that historically had no grammar concept attached –<Esc>exits Visual,<C-w>vsplits a pane,oopens a line below. Treating those as first-class “free-form actions” keeps the dispatcher contract (“everything returns Effect”) honest without fusing two conceptually different surfaces into one giant enum.
Applied host-side by Editor::apply_app_effect (reached from the
crate::Effect::AppAction arm of handle_effect), so every variant
acts on the focused buffer / active pane at apply time unless it names a
buffer. Several variants are now fallback shells: the chord is owned by
a mode whose ActionHandlerRegistry closure intercepts it before the
arm runs, and the arm is a no-op kept so the registered action id
resolves. Those variants say so.
Enums§
- AppEffect
- Variants are added incrementally during slice 8.i as each
historical
Actionvariant is promoted from the legacybind_legacybridge to a typedCommandInvocation. - Error
Target - CM.2 (2026-07-22): which error entry a
AppEffect::ErrorNavshould resolve to. Carried in the AppEffect so the whole:cnext/:cprev/:cc/:cfirst/:clast/]q/[qfamily shares a single host handler (Editor::do_error_nav). The error list is core substrate (like the jump ring), so a host AppEffect variant is the right carrier — not a provider-specific one. - HScroll
- Manual horizontal-scroll commands (HS.2), the vim
z{l,h,L,H,s,e}family. Carried byAppEffect::HorizontalScroll; the host handler mutatesleftcoland keeps the cursor inside the new window.wrap-off only (no-op under wrap, like the cursor-follow clamp). Seedocs/dev/architecture/horizontal-scroll.md. - Insert
Line Edit - App-side typed effect produced by a
CommandKind::Actiondispatch (DESIGN.md §5.2.1, see alsodocs/dev/notes/8i-approach.md). - Pane
Direction <C-w>h/j/k/lcardinal navigation. Geometry-aware: walks the tree to find the spatial neighbour of the active pane.- Scroll
Pos - Vim’s
zz/zt/zbtarget positions: where in the viewport the cursor’s current line should sit after the scroll. App-side concept hosted alongsideViewportPosfor the same dependency reason. Slice 8.i.2.c hoist. - Viewport
Pos - Vim’s
H/M/Ltarget positions: where in the visible viewport the cursor lands. App-side concept hosted here soAppEffect::JumpViewport(ViewportPos)can carry the typed payload withoutlattice-ui-tuihaving to dance through a dependency cycle. Slice 8.i.2.c hoist; the App’s previouscrate::app::ViewportPosbecomes apub usere-export of this type.