Expand description
Async runtime for lattice (DESIGN.md §5.2.1, §5.6.8, §5.7).
Sits between [lattice_core] (the synchronous data layer – Buffer,
Document, Edit) and lattice_ui_tui (rendering + input). Owns
three load-bearing async primitives:
-
Document actor (
actor): one tokio task per open document. The task owns the writable [lattice_core::Document]; mutations arrive via an unbounded mpsc mailbox. No callsite holds a lock on document state – exclusive access is statically guaranteed by the actor pattern. Audit slice 6 / H3 dropped the previous bounded-mailbox +RuntimeError::Busydesign after observing that App-side callers silently discarded the Busy variant under bursts; the unbounded channel makes “edit lands or actor is gone” the only outcome a caller can observe. -
Document snapshots (
snapshot): after every committed mutation the actor builds an immutableDocumentSnapshotand publishes it to a singlearc_swap::ArcSwapcell. Renderers read with one wait-free atomic load per visible document per frame and use that snapshot for the entire frame. There are no actor round-trips on the render hot path. (DESIGN.md §5.6.8.) -
Pending<T>(pending): every mutating call returns aPending– a typed handle wrapping a oneshot receiver. Callers that want the resultawait(or.blocking_recv()); callers that don’t (input loop, macro replay) drop it. This is the seam DESIGN.md §5.2.1 specifies.
§Why lattice-grammar stays sync
lattice_grammar::execute is a pure function from
(registry, document, cursor, invocation) to Effect. Async
coordination is a runtime concern, not a grammar concern – the
actor calls execute inside its own task, then publishes the
resulting snapshot. Grammar gets no tokio dependency, no async
signature, and no per-evaluator scheduling complexity.
§Tokio runtime
A single multi-threaded runtime is created lazily on first use
(shared_runtime) and shared across the process. Tests share
it but isolate at the actor-task level: each spawn_document
call creates a fresh task with its own mailbox + snapshot.
§Cancellation
RopeDocumentHandle::dispatch_with_cancel threads a
lattice_grammar::CancellationToken into the grammar
execute call. The caller (App) holds a clone and flips it
(e.g. on user Esc) to short-circuit a long-running motion or
operator. The plain RopeDocumentHandle::dispatch form uses a
no-op token; use it when no cancellation seam is required.
§What’s NOT here in v1
LatencyClassdeadline timers (DESIGN.md §5.2.5) – arrive whenCommandSpecgrows the field. v1 supports user-Esc cancellation only.- Veto / observation hook split (DESIGN.md §5.2.1, §5.10) – needs the event-bus primitive that doesn’t exist yet.
- Multi-document / cross-document atoms – one actor per document, but the App still tracks a single document.
Re-exports§
pub use actor::DocumentActor;pub use document::ActiveDocument;pub use document::DispatchEnv;pub use document::DisplayResolverHandle;pub use document::Document;pub use document::FoldResolverHandle;pub use document::IndentResolverHandle;pub use document::MarkResolverHandle;pub use document::ScopeResolverHandle;pub use document::ViewportResolverHandle;pub use events::EventAck;pub use events::EventBus;pub use events::EventFilter;pub use events::EventPredicate;pub use events::PluginEventSink;pub use events::SubscriptionId;pub use events::SubscriptionTarget;pub use glob::compile_glob_set;pub use handle::RopeDocumentHandle;pub use handle::spawn_document;pub use messages::MessagePushed;pub use messages::MessageRecord;pub use messages::MessagesRing;pub use messages_subscriber::MessagesFilterReloadError;pub use messages_subscriber::MessagesLayer;pub use messages_subscriber::boot_log_level;pub use messages_subscriber::boot_stderr_enabled;pub use messages_subscriber::install_messages_subscriber;pub use messages_subscriber::reload_messages_filter;pub use messages_subscriber::set_boot_log_level;pub use messages_subscriber::set_boot_stderr_enabled;pub use pending::InvocationId;pub use pending::Pending;pub use pending::RuntimeError;pub use runtime::block_on;pub use runtime::spawn_task;pub use snapshot::DocumentSnapshot;pub use snapshot::PublishedSnapshot;pub use snapshot::SnapshotCache;
Modules§
- actor
DocumentActor– the tokio task that owns one document’s writable state (DESIGN.md §5.7, §5.6.8).- document
- M.0 (2026-05-31):
Documenttrait — the handle-layer abstraction over a buffer that the rest of the editor talks to. - events
- In-process event bus (DESIGN.md §5.10).
- glob
- Shared glob-set compilation (EF.1).
- handle
RopeDocumentHandle– the public API for talking to a document actor. Cheap to clone (anmpsc::Sender+ anArc<PublishedSnapshot>); pass to any thread, hold for any lifetime, give to plugins.- messages
*messages*transcript types – one historical record per editor echo, a bounded ring of them, and a typedMessagePushedevent published whenever a new record lands.- messages_
subscriber MessagesLayer: atracing::Layerthat fans every event into the App’sMessagesRing+ publishes a typedMessagePushedon the editor event bus.- pending
Pending<T>– the typed handle returned by every mutating actor call (DESIGN.md §5.2.1).- runtime
- Tokio runtime singleton shared across the process.
- snapshot
DocumentSnapshot– immutable view of a document at one committed point in time (DESIGN.md §5.6.8).
Structs§
- Cancellation
Token - Cooperative cancellation handle. Cheap to clone (one Arc bump); safe to share across threads / tasks.