Expand description
The mode system’s foundation: the Mode trait, the mode registry, the
per-buffer set of active modes, and the typed lifecycle events — plus the
generic host seams a mode uses to own its whole surface (action handlers,
services, inbound wakes, buffer creation) and the foundation modes that
have no other owning crate.
The major / minor mode system is the primary customization mechanism
(DESIGN.md §5.8, docs/dev/architecture/mode-architecture.md). A buffer
has exactly one major mode (content-type identity: rust-mode,
help-mode’s markdown major, messages-mode) and any number of minor
modes layered over it (line-numbers-mode, table-mode,
emacs-keys-mode). A mode contributes declaratively — option overrides,
a keymap layer, completion sources, gutter signs, action handlers — and
imperatively through one lifecycle hook whose returned Guard is the only
cleanup path.
§What this crate owns
- The contract.
Mode(and its object-safe adapterDynMode),ModeId,ModeKind,ActivationPolicy,EditableTail,CapabilitySet,ModeContext,LifecycleFutureandModeActivationError. - Activation.
ModeRegistryregisters modes and drives activation / deactivation against a buffer’sActiveModes, stashing each activation’s Guard in aGuardStoreHandle. Observable transitions (MajorEntered/MinorActivated/ …) ride the protocolEventenum; internal failures rideModeEvent. - The host seams a mode needs to own its surface without depending on
the host.
ServiceRegistry(typed services),ActionHandlerRegistry(chord bodies),ModeActivatorandBufferStore(buffer creation / lookup),SubsystemBoot(a subsystem’s one-lineinstall),inboundandTickCallbackRegistry(off-keystroke results that wake the editor),idle_gate(armed deadlines),ProviderViewRegistry(open a provider’s view),ForegroundCancel, and the producer registries for plugin-backed content (MediaSourceRegistry,ContextSourceRegistry,GutterDecorationSourceRegistry,ScannedExcerptSourceRegistry,BufferScopeSourceRegistry). - Shared render-facing vocabularies a mode writes without seeing a
renderer: gutter signs (
SignRegistry,GutterDecoration), the modeline element model (ModelineService,ModelineElementUpdate), async highlight / inlay hand-off (PendingSyntheticHighlights,PendingInlays), buffer-locals (BufferLocals). - Foundation modes (
modes, registered byregister_foundation_modes):text-mode,help-mode,hover-mode,messages-mode,image-mode, the completion and display minors,table-mode,surround-mode,which-key-mode, and the shared minors that own one chord for a whole class of view (RefreshableViewModegr,FoldableViewMode<Tab>,ReplMode,EmacsKeysMode). Feature-crate modes live with their feature (lattice-lsp,lattice-listing,lattice-magit, …).
§What it must not depend on, and why
Nothing above it: not lattice-host, no renderer (lattice-ui-tui,
lattice-ui-gpui), no feature crate. Every feature crate depends on this
one to declare its modes, and the host depends on every feature crate, so
a dependency upward is a cycle — and, more to the point, it is the
structural guarantee that a mode can own its keymap, handler bodies,
buffers and async wakes without an Editor:: method or a host Action
variant (the mode-ownership acid test). Where a mode needs the host, the
host implements a trait defined here (ModeActivator, BufferStore,
SubsystemBoot) or registers a service. Its own dependencies are the
substrate below: protocol, core, grammar, keymap, config, completion,
runtime, cells.
§Example: a minimal minor mode
use lattice_core::BufferKind;
use lattice_mode::{
ActivationPolicy, LifecycleFuture, Mode, ModeContext, ModeId, ModeKind, ModeRegistry,
OptionOverrideSet,
};
/// Wraps long lines in prose buffers.
struct ProseMode;
impl Mode for ProseMode {
type Guard = (); // nothing to clean up
fn id(&self) -> ModeId {
ModeId::new("prose-mode")
}
fn kind(&self) -> ModeKind {
ModeKind::Minor
}
fn options(&self) -> OptionOverrideSet {
lattice_config::overrides! { lattice_config::Wrap = true, }
}
fn activation_policy(&self) -> ActivationPolicy {
ActivationPolicy::Majors(vec![ModeId::new("markdown-mode")])
}
fn on_activate(&self, _ctx: ModeContext) -> LifecycleFuture<'_, ()> {
Box::pin(async { Ok(()) })
}
}
let mut registry = ModeRegistry::new();
let id = registry.register(ProseMode).unwrap();
// The host's minor resolver asks this when a buffer enters a major.
assert_eq!(registry.auto_activatable_minors("markdown-mode", BufferKind::Document), vec![id]);
assert!(registry.auto_activatable_minors("rust-mode", BufferKind::Document).is_empty());The Mode docs carry the full lifecycle (registration → activation →
deactivation) as a runnable example; SubsystemBoot shows a whole
subsystem install with an off-thread producer.
§Design documents
docs/dev/architecture/mode-architecture.md— the mode model, activation, Guards, option layering (§5–§9).docs/dev/architecture/boot-composition.md—SubsystemBoot, the inbound primitive and why the wake lives in the sender (§3).docs/dev/architecture/keymap-architecture.md— keymap layers.docs/dev/architecture/modeline.md— the modeline element model.docs/dev/architecture/cancellation.md—ForegroundCancel.
Re-exports§
pub use crate::action_handler_registry::ActionContext;pub use crate::action_handler_registry::ActionHandler;pub use crate::action_handler_registry::ActionHandlerContribution;pub use crate::action_handler_registry::ActionHandlerRegistration;pub use crate::action_handler_registry::ActionHandlerRegistry;pub use crate::action_handler_registry::ActionHandlerRegistryHandle;pub use crate::activator::ModeActivator;pub use crate::activator::VirtualRowRegistrar;pub use crate::active::ActiveModes;pub use crate::buffer_store::BufferStore;pub use crate::buffer_store::BufferStoreHandle;pub use crate::capability::CapabilitySet;pub use crate::context::ModeContext;pub use crate::context_source::AsyncContextSource;pub use crate::context_source::ContextFuture;pub use crate::context_source::ContextSourceRegistry;pub use crate::context_source::ContextSourceRegistryHandle;pub use crate::contributions::BUILTIN_SIGN_COLUMNS;pub use crate::contributions::BuiltinSignIds;pub use crate::contributions::CompilationSeverityData;pub use crate::contributions::DIAGNOSTIC_ERROR_PRIORITY;pub use crate::contributions::DIAGNOSTIC_HINT_PRIORITY;pub use crate::contributions::DIAGNOSTIC_INFO_PRIORITY;pub use crate::contributions::DIAGNOSTIC_WARNING_PRIORITY;pub use crate::contributions::DIFF_SIGN_PRIORITY;pub use crate::contributions::DecorationCtx;pub use crate::contributions::DecorationProvider;pub use crate::contributions::DiagnosticGlyphs;pub use crate::contributions::GutterDecoration;pub use crate::contributions::GutterDiffKind;pub use crate::contributions::GutterSeverityLevel;pub use crate::contributions::SIGN_COLUMN_DIFF;pub use crate::contributions::SIGN_COLUMN_MARK;pub use crate::contributions::SignDefinition;pub use crate::contributions::SignId;pub use crate::contributions::SignRegistry;pub use crate::contributions::SignRegistryHandle;pub use crate::contributions::Subscription;pub use crate::contributions::register_builtin_signs;pub use crate::contributions::winning_sign;pub use crate::decoration_source::AsyncGutterDecorationSource;pub use crate::decoration_source::DecorationEpoch;pub use crate::decoration_source::DecorationEpochHandle;pub use crate::decoration_source::DecorationFuture;pub use crate::decoration_source::GutterDecorationSourceRegistry;pub use crate::decoration_source::GutterDecorationSourceRegistryHandle;pub use crate::error::ModeActivationError;pub use crate::event::ModeEvent;pub use crate::guards::GuardStore;pub use crate::guards::GuardStoreHandle;pub use crate::locals::BufferLocal;pub use crate::locals::BufferLocals;pub use crate::locals::BufferScopeDir;pub use crate::locals::BufferScopeSource;pub use crate::locals::BufferScopeSourceRegistry;pub use crate::locals::BufferScopeSourceRegistryHandle;pub use crate::locals::LocalDescriptor;pub use crate::media_source::AsyncMediaSource;pub use crate::media_source::MediaBlockRequest;pub use crate::media_source::MediaFuture;pub use crate::media_source::MediaSourceRegistry;pub use crate::media_source::MediaSourceRegistryHandle;pub use crate::mode::ActivationPolicy;pub use crate::mode::DynMode;pub use crate::mode::EditableTail;pub use crate::mode::LifecycleFuture;pub use crate::mode::Mode;pub use crate::mode::ModeKind;pub use crate::modes::ActiveCompletionSources;pub use crate::modes::BufferWordsMode;pub use crate::modes::CompletionMode;pub use crate::modes::CompletionPopupMode;pub use crate::modes::HelpMode;pub use crate::modes::HoverMode;pub use crate::modes::MessagesMode;pub use crate::modes::PathCompletionMode;pub use crate::modes::TextMode;pub use crate::modes::register_foundation_modes;pub use crate::modes::register_help_mode_actions;pub use crate::operator_chord::OperatorChordWirer;pub use crate::operator_chord::OperatorChordWirerHandle;pub use crate::modes::table::mode::TableMode;pub use crate::modes::table::mode::register_table_actions;pub use crate::modes::table::mode::register_table_mode;pub use crate::plugin_meta_sink::PluginMetaSink;pub use crate::plugin_meta_sink::PluginMetaSinkHandle;pub use crate::provider_view::ProviderViewOpener;pub use crate::provider_view::ProviderViewOutcome;pub use crate::provider_view::ProviderViewRegistry;pub use crate::provider_view::ProviderViewRegistryHandle;pub use crate::scanned_excerpt_source::ClockSpan;pub use crate::scanned_excerpt_source::RowAnnotation;pub use crate::scanned_excerpt_source::ScanBeginFuture;pub use crate::scanned_excerpt_source::ScanDescribeFuture;pub use crate::scanned_excerpt_source::ScanFuture;pub use crate::scanned_excerpt_source::ScanResult;pub use crate::scanned_excerpt_source::ScannedExcerpt;pub use crate::scanned_excerpt_source::ScannedExcerptSource;pub use crate::scanned_excerpt_source::ScannedExcerptSourceRegistry;pub use crate::scanned_excerpt_source::ScannedExcerptSourceRegistryHandle;pub use crate::services::ServiceRegistry;pub use crate::startup::Startup;pub use crate::subsystem_boot::SubsystemBoot;pub use crate::tick_callback::TickCallback;pub use crate::tick_callback::TickCallbackRegistration;pub use crate::tick_callback::TickCallbackRegistry;pub use crate::tick_callback::TickCallbackRegistryHandle;pub use crate::emacs_keys_mode::EmacsKeysMode;pub use crate::emacs_keys_mode::emacs_keys_layer_bindings;pub use crate::repl_mode::ReplMode;pub use crate::repl_mode::register_repl_mode;pub use crate::repl_mode::register_repl_mode_actions;pub use crate::refreshable_view_mode::RefreshableViewMode;pub use crate::refreshable_view_mode::VIEW_REFRESH_ACTION;pub use crate::refreshable_view_mode::register_refreshable_view_actions;pub use crate::refreshable_view_mode::register_refreshable_view_mode;pub use crate::foldable_view_mode::FOLD_TOGGLE_DEFAULT_ACTION;pub use crate::foldable_view_mode::FoldableViewMode;pub use crate::foldable_view_mode::VIEW_FOLD_CYCLE_ACTION;pub use crate::foldable_view_mode::VIEW_FOLD_TOGGLE_ACTION;pub use crate::foldable_view_mode::register_foldable_view_actions;pub use crate::foldable_view_mode::register_foldable_view_mode;pub use crate::foreground_cancel::ForegroundCancel;pub use crate::foreground_cancel::ForegroundCancelHandle;pub use crate::modeline::ElementContent;pub use crate::modeline::ElementId;pub use crate::modeline::HoverSpec;pub use crate::modeline::Interaction;pub use crate::modeline::ModelineElement;pub use crate::modeline::ModelineElementUpdate;pub use crate::modeline::ModelineKey;pub use crate::modeline::ModelineRegistry;pub use crate::modeline::ModelineRole;pub use crate::modeline::ModelineService;pub use crate::modeline::ModelineServiceHandle;pub use crate::modeline::ModelineSnapshot;pub use crate::modeline::Scope;pub use crate::modeline::Span;pub use crate::modeline::Zone;pub use crate::pending_inlays::InlayRow;pub use crate::pending_inlays::PendingInlays;pub use crate::pending_inlays::PendingInlaysHandle;pub use crate::pending_synthetic_highlights::HighlightsOp;pub use crate::pending_synthetic_highlights::PendingSyntheticHighlights;pub use crate::pending_synthetic_highlights::PendingSyntheticHighlightsHandle;pub use crate::registry::ModeRegistry;pub use crate::registry::ModeRegistryHandle;pub use crate::registry::RegistrationError;
Modules§
- action_
handler_ registry - Action-handler registry — mode-contributed closures
per
CommandId(M.10.1). - activator
ModeActivator: synchronous activation surface for extension crates that create buffers and need their major / minor modes activated on the host side.- active
ActiveModes: the major + ordered minors set per buffer.- binding_
mode - Re-export shim —
BindingModenow lives inlattice-keymap. - buffer_
store BufferStore: host primitive for mode-owned buffer lifecycles.- capability
CapabilitySet: typed bitfield describing what a buffer can offer. Modes declare what they require viacrate::Mode::required_capabilities; the registry validates the buffer satisfies all required bits before activation.- context
ModeContext: the handle passed tocrate::Mode::on_activate.- context_
source - The native seam for an async producer of structural context scopes (TC.2).
- contributions
- Declarative contributions on
crate::Mode. - decoration_
source - The async gutter-decoration producer seam (PL8.E).
- emacs_
keys_ mode emacs-keys-mode— a default-on builtin minor mode contributing an emacs-style<C-x>leader (a tribute layer). Design:docs/dev/architecture/emacs-keys.md; sequencing:docs/dev/operations/slice-plans/emacs-keys.md.- error
- Errors surfaced by the registry’s activation / deactivation path.
- event
- Typed internal mode-dispatch signals.
- foldable_
view_ mode foldable-view-mode— the one place<Tab>folds the block at point.- foreground_
cancel - The foreground-cancellation seam, as a registered service (CG.2).
- guards
GuardStore: type-erased storage for per-(buffer, mode)Guards returned byMode::on_activate.- idle_
gate - Idle-gate registry — the generic armed-deadline primitive (WK.3).
- inbound
- Boot-composition BC.1: the generic inbound primitive.
- keymap_
entry - Static keymap catalog +
keymap_entry!macro (DESIGN.md §5.2.3). - locals
- Buffer-local mode-internal state — Shape A from
mode-architecture.md§9.4 (M.3.2.a). - media_
source - The registry of inline-media producers (IM.6b).
- mode
- The
Modetrait, plusModeId,ModeKind, and theLifecycleFuturetype alias. - modeline
- Modeline element model + descriptor registry (slice ML.0a).
- modes
- Foundation modes that ship with
lattice-mode. - operator_
chord - Wiring a plugin-registered operator’s chord into the grammar (CM.2).
- pending_
inlays - Mode-published inline virtual text (DL.3b).
- pending_
synthetic_ highlights - Pending synthetic-buffer highlights mechanism (MG.2).
- plugin_
meta_ sink PluginMetaSink— the generic seam the plugin loader writes plugin provenance through (PL8.B).- provider_
view - The provider-view seam — one generic host primitive for “open the multibuffer view a provider owns” (PV.1, 2026-08-12).
- refreshable_
view_ mode refreshable-view-mode— the one placegrmeans “refresh this view”.- registry
ModeRegistry: register modes, look them up, drive activation / deactivation against a per-bufferActiveModesand an App-ownedGuardStoreHandle.- repl_
mode repl-mode— a builtin minor mode contributing the REPL input surface.- scanned_
excerpt_ source - OM.A1 — the registry of agenda-row producers.
- services
ServiceRegistry: typed lookup for subsystem handles that modes need access to from their lifecycle hooks (Phase 3 of the mode-architectureModeContextextension).- startup
- The generic boot-completion signal (design.md §9.1) (DB.5).
- subsystem_
boot SubsystemBoot— the capability surface a subsystem wires against at boot.- tick_
callback - IDE-protocol I1.1: tick-callback registry — the one generic host primitive the Claude Code IDE peer needs.
Macros§
- keymap_
entry - Construct a
KeymapEntrywith the row’s source location captured at the macro invocation site. Forms:
Structs§
- Keymap
- A mode’s full keymap contribution.
- Keymap
Binding - One mode-contributed keymap binding.
- Keymap
Entry - One row in the catalog. Ordering of fields matches the rendering
order in
:describe-keyso reading one field at a time still tells a coherent story. - ModeId
- Canonical identity of a mode. Interned-string for
Copy + Eq + Hashat zero allocation cost on the hot path. - Option
Override - One option-value override from a single layer producer (a mode, a buffer-local set, a modal-state hook).
- Option
Override Set - A set of
OptionOverrides contributed by one layer producer (typically the return value ofMode::options()).
Enums§
- Binding
Mode - Where a binding takes effect. Multi-key sequences (e.g.
gg) resolve atomically; intermediate single-key prefixes (g,z) get their own descriptor entries so:describe-key gexplains the pending substate. - Override
Priority - Tie-break priority for two layer entries that target the same option.