Skip to main content

lattice_mode/
lib.rs

1//! The mode system's foundation: the `Mode` trait, the mode registry, the
2//! per-buffer set of active modes, and the typed lifecycle events — plus the
3//! generic host seams a mode uses to own its whole surface (action handlers,
4//! services, inbound wakes, buffer creation) and the foundation modes that
5//! have no other owning crate.
6//!
7//! The major / minor mode system is the primary customization mechanism
8//! (DESIGN.md §5.8, `docs/dev/architecture/mode-architecture.md`). A buffer
9//! has exactly one **major** mode (content-type identity: `rust-mode`,
10//! `help-mode`'s markdown major, `messages-mode`) and any number of **minor**
11//! modes layered over it (`line-numbers-mode`, `table-mode`,
12//! `emacs-keys-mode`). A mode contributes declaratively — option overrides,
13//! a keymap layer, completion sources, gutter signs, action handlers — and
14//! imperatively through one lifecycle hook whose returned Guard is the only
15//! cleanup path.
16//!
17//! ## What this crate owns
18//!
19//! - **The contract.** [`Mode`] (and its object-safe adapter [`DynMode`]),
20//!   [`ModeId`], [`ModeKind`], [`ActivationPolicy`], [`EditableTail`],
21//!   [`CapabilitySet`], [`ModeContext`], [`LifecycleFuture`] and
22//!   [`ModeActivationError`].
23//! - **Activation.** [`ModeRegistry`] registers modes and drives activation /
24//!   deactivation against a buffer's [`ActiveModes`], stashing each
25//!   activation's Guard in a [`GuardStoreHandle`]. Observable transitions
26//!   (`MajorEntered` / `MinorActivated` / …) ride the protocol `Event` enum;
27//!   internal failures ride [`ModeEvent`].
28//! - **The host seams a mode needs to own its surface without depending on
29//!   the host.** [`ServiceRegistry`] (typed services),
30//!   [`ActionHandlerRegistry`] (chord bodies), [`ModeActivator`] and
31//!   [`BufferStore`] (buffer creation / lookup), [`SubsystemBoot`] (a
32//!   subsystem's one-line `install`), [`inbound`] and
33//!   [`TickCallbackRegistry`] (off-keystroke results that wake the editor),
34//!   [`idle_gate`] (armed deadlines), [`ProviderViewRegistry`] (open a
35//!   provider's view), [`ForegroundCancel`], and the producer registries
36//!   for plugin-backed content ([`MediaSourceRegistry`],
37//!   [`ContextSourceRegistry`], [`GutterDecorationSourceRegistry`],
38//!   [`ScannedExcerptSourceRegistry`], [`BufferScopeSourceRegistry`]).
39//! - **Shared render-facing vocabularies** a mode writes without seeing a
40//!   renderer: gutter signs ([`SignRegistry`], [`GutterDecoration`]), the
41//!   modeline element model ([`ModelineService`],
42//!   [`ModelineElementUpdate`]), async highlight / inlay hand-off
43//!   ([`PendingSyntheticHighlights`], [`PendingInlays`]), buffer-locals
44//!   ([`BufferLocals`]).
45//! - **Foundation modes** ([`modes`], registered by
46//!   [`register_foundation_modes`]): `text-mode`, `help-mode`,
47//!   `hover-mode`, `messages-mode`, `image-mode`, the completion and display
48//!   minors, `table-mode`, `surround-mode`, `which-key-mode`, and the shared
49//!   minors that own one chord for a whole class of view
50//!   ([`RefreshableViewMode`] `gr`, [`FoldableViewMode`] `<Tab>`,
51//!   [`ReplMode`], [`EmacsKeysMode`]). Feature-crate modes live with their
52//!   feature (`lattice-lsp`, `lattice-listing`, `lattice-magit`, …).
53//!
54//! ## What it must not depend on, and why
55//!
56//! Nothing above it: not `lattice-host`, no renderer (`lattice-ui-tui`,
57//! `lattice-ui-gpui`), no feature crate. Every feature crate depends on this
58//! one to declare its modes, and the host depends on every feature crate, so
59//! a dependency upward is a cycle — and, more to the point, it is the
60//! structural guarantee that a mode can own its keymap, handler bodies,
61//! buffers and async wakes **without an `Editor::` method or a host `Action`
62//! variant** (the mode-ownership acid test). Where a mode needs the host, the
63//! host implements a trait defined here ([`ModeActivator`], [`BufferStore`],
64//! [`SubsystemBoot`]) or registers a service. Its own dependencies are the
65//! substrate below: protocol, core, grammar, keymap, config, completion,
66//! runtime, cells.
67//!
68//! ## Example: a minimal minor mode
69//!
70//! ```
71//! use lattice_core::BufferKind;
72//! use lattice_mode::{
73//!     ActivationPolicy, LifecycleFuture, Mode, ModeContext, ModeId, ModeKind, ModeRegistry,
74//!     OptionOverrideSet,
75//! };
76//!
77//! /// Wraps long lines in prose buffers.
78//! struct ProseMode;
79//!
80//! impl Mode for ProseMode {
81//!     type Guard = (); // nothing to clean up
82//!     fn id(&self) -> ModeId {
83//!         ModeId::new("prose-mode")
84//!     }
85//!     fn kind(&self) -> ModeKind {
86//!         ModeKind::Minor
87//!     }
88//!     fn options(&self) -> OptionOverrideSet {
89//!         lattice_config::overrides! { lattice_config::Wrap = true, }
90//!     }
91//!     fn activation_policy(&self) -> ActivationPolicy {
92//!         ActivationPolicy::Majors(vec![ModeId::new("markdown-mode")])
93//!     }
94//!     fn on_activate(&self, _ctx: ModeContext) -> LifecycleFuture<'_, ()> {
95//!         Box::pin(async { Ok(()) })
96//!     }
97//! }
98//!
99//! let mut registry = ModeRegistry::new();
100//! let id = registry.register(ProseMode).unwrap();
101//! // The host's minor resolver asks this when a buffer enters a major.
102//! assert_eq!(registry.auto_activatable_minors("markdown-mode", BufferKind::Document), vec![id]);
103//! assert!(registry.auto_activatable_minors("rust-mode", BufferKind::Document).is_empty());
104//! ```
105//!
106//! The [`Mode`] docs carry the full lifecycle (registration → activation →
107//! deactivation) as a runnable example; [`SubsystemBoot`] shows a whole
108//! subsystem install with an off-thread producer.
109//!
110//! ## Design documents
111//!
112//! - `docs/dev/architecture/mode-architecture.md` — the mode model,
113//!   activation, Guards, option layering (§5–§9).
114//! - `docs/dev/architecture/boot-composition.md` — `SubsystemBoot`, the
115//!   inbound primitive and why the wake lives in the sender (§3).
116//! - `docs/dev/architecture/keymap-architecture.md` — keymap layers.
117//! - `docs/dev/architecture/modeline.md` — the modeline element model.
118//! - `docs/dev/architecture/cancellation.md` — [`ForegroundCancel`].
119
120#![warn(missing_docs)]
121
122// M.10.1 (2026-06-02): action-handler registry — mode-
123// contributed closures per `CommandId`. Required so modes own
124// BOTH chord choice (already done via `keymap()`) AND handler
125// body (this substrate), per `feedback_mode_owns_its_surface`
126// + `mode-architecture.md` §5.3. Host's chord-resolved-action
127// dispatcher consults via `lookup`; mode's `Guard` carries
128// `ActionHandlerRegistration` tokens whose `Drop` unregisters.
129pub mod action_handler_registry;
130pub mod activator;
131pub mod active;
132pub mod binding_mode;
133// OM.A1: the native seam a WASM agenda-row producer implements. Sibling of
134// `media_source` — async, host-driven off the keystroke path, once per file of
135// a project walk. The source declares which extensions it wants offered, which
136// is what keeps a filetype out of the host's walk.
137pub mod buffer_store;
138pub mod capability;
139pub mod context;
140pub mod scanned_excerpt_source;
141// TC.2: the native seam a WASM sticky-context producer implements. Sibling of
142// `decoration_source` — async, host-driven off the render path, result cached.
143pub mod context_source;
144pub mod contributions;
145pub mod decoration_source;
146pub mod media_source;
147pub mod operator_chord;
148// BC.5: `emacs-keys-mode` — a default-on universal builtin minor mode (the
149// `<C-x>` leader tribute). Moved here from `lattice-host`; registered with the
150// foundation modes. The host keeps only the keymap-layer push (config + the
151// live `KeymapHandle`).
152pub mod emacs_keys_mode;
153// CG.2 (2026-08-08): foreground cancellation as a registered service,
154// so a provider can enrol work from any `&self` context (action
155// handlers, event subscriptions) and not just where `&mut Editor` is
156// reachable. See `docs/dev/architecture/cancellation.md`.
157pub mod error;
158pub mod event;
159pub mod foldable_view_mode;
160pub mod foreground_cancel;
161pub mod guards;
162pub mod refreshable_view_mode;
163pub mod repl_mode;
164// Boot-composition BC.1: the generic *inbound* primitive — a channel whose
165// `send` wakes the editor (`async_landed`) and whose items drain per-tick
166// through a handler. Pairs with `tick_callback`; generalizes the I3
167// `ClaudeCodeInboundBus` + LSP's hand-rolled inbound buses. The wake is baked
168// into the sender so it cannot be forgotten (`boot-composition.md` §3).
169pub mod idle_gate;
170pub mod inbound;
171// K.3 (2026-06-07): `KeymapEntry` + `keymap_entry!` live in
172// `lattice-keymap::keymap_entry`. lattice-mode re-exports the MODULE and
173// the `#[macro_export]` macro with a single `pub use` — the name
174// `keymap_entry` resolves in both the type namespace (the module) and the
175// macro namespace, so `lattice_mode::keymap_entry! { … }` AND
176// `lattice_mode::keymap_entry::{KeymapEntry, default_keymap, …}` keep
177// working for callers in `lattice-multibuffer`, `lattice-host`, and
178// `lattice-ui-tui` WITHOUT duplicating the macro body. The macro's
179// `$crate` resolves to `lattice_keymap` regardless of the re-export path
180// (so callers need no direct `lattice-keymap` dep). See
181// `project_keymap_entry_macro_dual_copy` — the former duplicate is gone.
182pub use lattice_keymap::keymap_entry;
183pub mod locals;
184pub mod mode;
185pub mod modeline;
186// MG.2: pending synthetic-buffer highlights service, shared between
187// lattice-host (drain) and lattice-magit (async refresh tasks).
188pub mod modes;
189pub mod pending_inlays;
190pub mod pending_synthetic_highlights;
191pub mod plugin_meta_sink;
192// PV.1 (2026-08-12): the generic provider-view seam — one host primitive
193// for "open the multibuffer view a provider owns", replacing the
194// per-provider `AppEffect` variant + host arm + plugin-boundary arm.
195pub mod provider_view;
196pub mod registry;
197pub mod services;
198// DB.5 (design.md §9.1): the generic `Startup` boot-completion typed event.
199// Declared here (alongside `ModeEvent`) so subsystem `install(&mut boot)`
200// fns can subscribe without a `lattice-host` dependency.
201pub mod startup;
202// IDE-protocol I1.1: the one generic host primitive — a per-tick drain
203// closure registry. Generalizes the host's hardcoded `drain_<x>` methods
204// so a mode owns its channel + drain body (`feedback_mode_owns_its_surface`).
205pub mod tick_callback;
206// Boot-composition BC.3b: the capability surface a subsystem's `install(boot)`
207// wires against. Lives here (below every subsystem crate) so subsystems name
208// the capability, not the host's concrete `BootContext` (which would cycle).
209pub mod subsystem_boot;
210
211pub use crate::action_handler_registry::{
212    ActionContext, ActionHandler, ActionHandlerContribution, ActionHandlerRegistration,
213    ActionHandlerRegistry, ActionHandlerRegistryHandle,
214};
215pub use crate::activator::{ModeActivator, VirtualRowRegistrar};
216pub use crate::active::ActiveModes;
217pub use crate::binding_mode::BindingMode;
218pub use crate::buffer_store::{BufferStore, BufferStoreHandle};
219pub use crate::capability::CapabilitySet;
220pub use crate::context::ModeContext;
221pub use crate::context_source::{
222    AsyncContextSource, ContextFuture, ContextSourceRegistry, ContextSourceRegistryHandle,
223};
224pub use crate::contributions::{
225    BUILTIN_SIGN_COLUMNS,
226    BuiltinSignIds,
227    CompilationSeverityData,
228    DIAGNOSTIC_ERROR_PRIORITY,
229    DIAGNOSTIC_HINT_PRIORITY,
230    DIAGNOSTIC_INFO_PRIORITY,
231    DIAGNOSTIC_WARNING_PRIORITY,
232    DIFF_SIGN_PRIORITY,
233    DecorationCtx,
234    DecorationProvider,
235    DiagnosticGlyphs,
236    GutterDecoration,
237    GutterDiffKind,
238    GutterSeverityLevel,
239    Keymap,
240    KeymapBinding,
241    SIGN_COLUMN_DIFF,
242    SIGN_COLUMN_MARK,
243    SignDefinition,
244    SignId,
245    SignRegistry,
246    SignRegistryHandle,
247    Subscription, // MO.4.c: real RAII type; use in mode Guards
248    register_builtin_signs,
249    winning_sign,
250};
251pub use crate::decoration_source::{
252    AsyncGutterDecorationSource, DecorationEpoch, DecorationEpochHandle, DecorationFuture,
253    GutterDecorationSourceRegistry, GutterDecorationSourceRegistryHandle,
254};
255pub use crate::error::ModeActivationError;
256pub use crate::event::ModeEvent;
257pub use crate::guards::{GuardStore, GuardStoreHandle};
258pub use crate::locals::{
259    BufferLocal, BufferLocals, BufferScopeDir, BufferScopeSource, BufferScopeSourceRegistry,
260    BufferScopeSourceRegistryHandle, LocalDescriptor,
261};
262pub use crate::media_source::{
263    AsyncMediaSource, MediaBlockRequest, MediaFuture, MediaSourceRegistry,
264    MediaSourceRegistryHandle,
265};
266pub use crate::mode::{
267    ActivationPolicy, DynMode, EditableTail, LifecycleFuture, Mode, ModeId, ModeKind,
268};
269pub use crate::modes::{
270    ActiveCompletionSources, BufferWordsMode, CompletionMode, CompletionPopupMode, HelpMode,
271    HoverMode, MessagesMode, PathCompletionMode, TextMode, register_foundation_modes,
272    register_help_mode_actions,
273};
274pub use crate::operator_chord::{OperatorChordWirer, OperatorChordWirerHandle};
275// TB.1: `table-mode` — the shared pipe-table minor. Re-exported beside the
276// other shared minors so boot reaches it by the same path.
277pub use crate::modes::table::mode::{TableMode, register_table_actions, register_table_mode};
278pub use crate::plugin_meta_sink::{PluginMetaSink, PluginMetaSinkHandle};
279pub use crate::provider_view::{
280    ProviderViewOpener, ProviderViewOutcome, ProviderViewRegistry, ProviderViewRegistryHandle,
281};
282pub use crate::scanned_excerpt_source::{
283    ClockSpan, RowAnnotation, ScanBeginFuture, ScanDescribeFuture, ScanFuture, ScanResult,
284    ScannedExcerpt, ScannedExcerptSource, ScannedExcerptSourceRegistry,
285    ScannedExcerptSourceRegistryHandle,
286};
287pub use crate::services::ServiceRegistry;
288pub use crate::startup::Startup;
289pub use crate::subsystem_boot::SubsystemBoot;
290pub use crate::tick_callback::{
291    TickCallback, TickCallbackRegistration, TickCallbackRegistry, TickCallbackRegistryHandle,
292};
293pub use lattice_keymap::KeymapEntry;
294// BC.5: the host pushes the `<C-x>` leader layer (it owns the `KeymapHandle` +
295// config), calling `emacs_keys_layer_bindings`; `EmacsKeysMode::mode_id` keys
296// the layer + the K.1.c per-keystroke gate.
297pub use crate::emacs_keys_mode::{EmacsKeysMode, emacs_keys_layer_bindings};
298pub use crate::repl_mode::{ReplMode, register_repl_mode, register_repl_mode_actions};
299// RV.1: the one place `gr` means "refresh this view" — the chord lives
300// here, each view's mode declares its own `refresh_action()` target.
301pub use crate::refreshable_view_mode::{
302    RefreshableViewMode, VIEW_REFRESH_ACTION, register_refreshable_view_actions,
303    register_refreshable_view_mode,
304};
305// OA.4b: the one place `<Tab>` folds the block at point — the chord lives
306// here, each view's mode declares its own `fold_toggle_action()` target.
307pub use crate::foldable_view_mode::{
308    FOLD_TOGGLE_DEFAULT_ACTION, FoldableViewMode, VIEW_FOLD_CYCLE_ACTION, VIEW_FOLD_TOGGLE_ACTION,
309    register_foldable_view_actions, register_foldable_view_mode,
310};
311// ML.0a: configurable-modeline element model + descriptor registry.
312pub use crate::foreground_cancel::{ForegroundCancel, ForegroundCancelHandle};
313pub use crate::modeline::{
314    ElementContent, ElementId, HoverSpec, Interaction, ModelineElement, ModelineElementUpdate,
315    ModelineKey, ModelineRegistry, ModelineRole, ModelineService, ModelineServiceHandle,
316    ModelineSnapshot, Scope, Span, Zone,
317};
318pub use crate::pending_inlays::{InlayRow, PendingInlays, PendingInlaysHandle};
319pub use crate::pending_synthetic_highlights::{
320    HighlightsOp, PendingSyntheticHighlights, PendingSyntheticHighlightsHandle,
321};
322// M.4 dep-inversion: layer-input types live in `lattice-config`
323// now. Re-exported here for compatibility -- callers that
324// imported from `lattice_mode` keep working.
325pub use crate::registry::{ModeRegistry, ModeRegistryHandle, RegistrationError};
326pub use lattice_config::{OptionOverride, OptionOverrideSet, OverridePriority};