lattice_host/activator.rs
1//! M.2.b.2 (2026-06-01): `impl ModeActivator for Editor`.
2//!
3//! Synchronous activation surface for extension crates
4//! (`lattice-multibuffer` today; future in-tree provider crates
5//! shipped within it). Thin wrappers over the existing fat helpers
6//! (`activate_major_for_buffer_kind`, `activate_mode_by_id`) —
7//! both already run the full cascade (major → default minor → auto
8//! minors → recompute options + completion → maybe-auto-LSP) and
9//! return a `Vec<RendererSignal>`.
10//!
11//! The trait surface returns `()`, keeping `RendererSignal` out of
12//! `lattice-mode`. Signals are enqueued into
13//! `Editor::pending_renderer_signals`; the App's dispatch loop
14//! drains via [`Editor::drain_pending_renderer_signals`] after the
15//! extension-crate call frame returns.
16//!
17//! See `docs/dev/architecture/multibuffer-views.md` §3.7.
18
19use std::sync::Arc;
20
21use lattice_core::{BufferFlags, BufferId, BufferKind};
22use lattice_mode::{ModeActivator, ModeId, ServiceRegistry};
23
24use crate::editor::Editor;
25
26impl ModeActivator for Editor {
27 /// MR.6: the buffer a provider view is being opened over.
28 ///
29 /// The active *document* buffer, which is what the trigger was
30 /// pressed in — the same id `transient_open_context` reports and the
31 /// same one the chord dispatcher hands an action handler.
32 fn active_buffer(&self) -> Option<BufferId> {
33 Some(self.document_buffer_id)
34 }
35
36 fn activate_major_for_kind(&mut self, buffer: BufferId, kind: BufferKind) {
37 let signals = self.activate_major_for_buffer_kind(buffer, kind);
38 self.enqueue_renderer_signals(signals);
39 }
40
41 fn activate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId) {
42 let signals = self.activate_mode_by_id(buffer, mode);
43 self.enqueue_renderer_signals(signals);
44 }
45
46 fn deactivate_minor_by_id(&mut self, buffer: BufferId, mode: ModeId) {
47 let signals = self.deactivate_mode_by_id(buffer, mode);
48 self.enqueue_renderer_signals(signals);
49 }
50
51 /// The real create-and-activate seam (`ensure_named_synthetic_document`
52 /// inserts the buffer + runs the major's `on_activate` by id). This
53 /// is why buffer creation lives here on the `&mut`-backed
54 /// `ModeActivator` and not on the `&self` `BufferStore`.
55 fn ensure_named_document(&mut self, name: &str, major: ModeId, flags: BufferFlags) -> BufferId {
56 self.ensure_named_synthetic_document(name, major, flags)
57 }
58
59 fn services(&self) -> Arc<ServiceRegistry> {
60 Arc::clone(&self.services)
61 }
62
63 /// Forward to the host's single write chokepoint, so a provider crate
64 /// records what its buffer is about without depending on `lattice-host`.
65 fn set_buffer_scope_dir(&mut self, buffer: BufferId, dir: std::path::PathBuf) {
66 Editor::set_buffer_scope_dir(self, buffer, dir);
67 }
68
69 /// K.4.6 (2026-06-02): forward to the editor's
70 /// `VirtualRowProviderRegistry`. The virtual-rows worker
71 /// (`crate::virtual_rows_worker`) picks up new providers on
72 /// its next wake; the registry itself is already shared
73 /// (`Arc<VirtualRowProviderRegistry>`), so registration is
74 /// observable to the worker without further plumbing.
75 /// Returns `false` if a provider with the same `ProviderId`
76 /// already exists in `buffer`'s scope — matches the
77 /// underlying registry's no-replacement contract.
78 fn register_virtual_row_provider(
79 &mut self,
80 buffer: BufferId,
81 provider: Arc<dyn lattice_cells::VirtualRowProvider>,
82 ) -> bool {
83 self.virtual_row_providers.register(buffer, provider)
84 }
85}