pub trait ModeActivator {
// Required methods
fn activate_major_for_kind(&mut self, buffer: BufferId, kind: BufferKind);
fn activate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId);
fn ensure_named_document(
&mut self,
name: &str,
major: ModeId,
flags: BufferFlags,
) -> BufferId;
fn services(&self) -> Arc<ServiceRegistry> ⓘ;
// Provided methods
fn deactivate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId) { ... }
fn active_buffer(&self) -> Option<BufferId> { ... }
fn register_virtual_row_provider(
&mut self,
buffer: BufferId,
provider: Arc<dyn VirtualRowProvider>,
) -> bool { ... }
fn set_buffer_scope_dir(&mut self, buffer: BufferId, dir: PathBuf) { ... }
}Expand description
Activation surface implemented by lattice-host::Editor and
consumed by extension crates that need to drive activation
without holding a typed &mut Editor.
All three methods run synchronously on the App thread (caller
owns &mut Self). The implementor is responsible for routing
the cascade’s renderer signals into its own pending-signals
queue — extension crates never see RendererSignal, keeping
host-layer types out of lattice-mode.
Failures (mode not registered, missing capability, conflict)
are logged + swallowed by the impl (matching the existing
Editor::activate_* helpers’ shape). Callers that need to
observe activation outcome subscribe to
crate::ModeEvent on the event bus.
Required Methods§
Sourcefn activate_major_for_kind(&mut self, buffer: BufferId, kind: BufferKind)
fn activate_major_for_kind(&mut self, buffer: BufferId, kind: BufferKind)
Activate the major mode bound to kind on buffer. Uses
the crate::ModeRegistry::find_major_for_kind lookup
(populated by Mode::target_buffer_kind declarations)
to resolve the mode id. No-ops if a major is already
active on the buffer (idempotency / preserve-intent).
Sourcefn activate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId)
fn activate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId)
Activate a minor mode by id on buffer. The mode must
be registered. Idempotent: re-activating an already-active
minor is a no-op.
Sourcefn ensure_named_document(
&mut self,
name: &str,
major: ModeId,
flags: BufferFlags,
) -> BufferId
fn ensure_named_document( &mut self, name: &str, major: ModeId, flags: BufferFlags, ) -> BufferId
Find-or-create a synthetic named Document buffer and
activate major on it by id (no on-disk language detection),
returning its [BufferId]. This is the reliable, &mut-backed
creation seam a mode / provider uses to provision its own
buffer — the creation of a mode-owned buffer is the mode’s
responsibility, triggered through here.
Unlike crate::BufferStore (whose &self handle can only
find an existing buffer — activating a mode mutates the mode
registry / active-modes / options cache and needs &mut), this
method actually creates: the host impl mints the BufferId,
spawns an empty Document, registers it with flags, seeds
mode-locals, and runs major’s on_activate — so any drain /
subscription the mode establishes there is live by the time this
returns. Idempotent: a second call with the same name returns
the existing id without re-activating (the drain from the first
activation stays put).
Sourcefn services(&self) -> Arc<ServiceRegistry> ⓘ
fn services(&self) -> Arc<ServiceRegistry> ⓘ
Cheap-clone handle to the App’s ServiceRegistry. Used
by extension-crate trigger functions that need to look up
service handles (BufferStoreHandle, per-provider
services, the per-extension-crate registries) without
fighting the borrow checker against the &mut Self
activator borrow.
Provided Methods§
Sourcefn deactivate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId)
fn deactivate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId)
Deactivate a minor mode by id on buffer. Idempotent: a mode
that is not active is a no-op.
PD.4: the symmetric half of Self::activate_minor_by_id, and
it exists because a re-triggered provider view reuses its buffer.
A view that was read-only for one query and is editable for the
next has to be able to say so — without this, “open the staged
diff, then open the working-tree diff” would leave the second one
unwritable, and the cause would be invisible because the buffer
looks identical.
Default impl is a no-op so test activators that do not model
mode state stay valid; the host impl forwards to
Editor::deactivate_mode_by_id.
Sourcefn active_buffer(&self) -> Option<BufferId>
fn active_buffer(&self) -> Option<BufferId>
The buffer that is active right now (MR.6).
A provider view is opened over something — the file you were
reading, the magit buffer you pressed a chord in — and what it
should show usually depends on which. ProviderViewOpener
received the services and the trigger’s arguments but no way to
name that buffer, so magit’s project diff had to fall back to the
process’s working directory and showed the wrong repository’s
changes for anyone with two checkouts open.
The peer of TransientContext::buffer and
ExCommandContext::buffer_id, and generic for the same reason:
“which buffer did this come from” is a question every
context-varying surface asks, not a magit one.
Default None so test activators that model no pane tree stay
valid; the host impl returns its active document buffer.
Sourcefn register_virtual_row_provider(
&mut self,
buffer: BufferId,
provider: Arc<dyn VirtualRowProvider>,
) -> bool
fn register_virtual_row_provider( &mut self, buffer: BufferId, provider: Arc<dyn VirtualRowProvider>, ) -> bool
Register a virtual-row provider against
buffer. Used by extension crates that contribute virtual
rows for their own buffer kinds (multibuffer excerpt
headers — MultibufferHeaderProvider; future fold-range
providers, diff-hunk overlays, LSP code-lens, …). The
host-side impl forwards to
Editor::virtual_row_providers.register(buffer, provider);
the worker picks the provider up on its next wake (K.4.6, 2026-06-02).
Returns true on registration, false if a provider with
the same ProviderId was already registered in the same
buffer scope (no replacement — caller unregisters first
via the existing registry handle). The default impl
returns false so test activators that don’t wire the
virtual-row pipeline behave as no-ops; production impls
(Editor) override.
Paramount-#2 anchor: every mode contributing to a buffer
registers its own virtual rows via this seam, matching
the mode-owns-its-surface principle (keymaps via
register_<mode>_keymap, virtual rows via this method,
future status-line items via similar). WIT plugin path
inherits the trait surface.
Sourcefn set_buffer_scope_dir(&mut self, buffer: BufferId, dir: PathBuf)
fn set_buffer_scope_dir(&mut self, buffer: BufferId, dir: PathBuf)
Record the directory buffer is about
(BufferScopeDir).
A provider calls this from its trigger, where it has already resolved
the directory — a magit repository’s workdir, an oil listing’s dir, a
scan root. Project resolution (:files, :search) then answers for
that buffer instead of falling through to the working directory.
Pass the directory, not a project root: the host resolves the project from it through the ordinary resolver, so a provider never has to learn what a project is and the two cannot be recorded inconsistently.
Default impl is a no-op so test activators stay valid; the host
forwards to Editor::set_buffer_scope_dir.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".