Skip to main content

Event

Enum Event 

Source
pub enum Event {
Show 22 variants DocumentOpened { id: DocumentId, path: Option<PathBuf>, version: u64, text: String, }, DocumentClosed { id: DocumentId, }, BeforeSave { id: DocumentId, path: PathBuf, }, DocumentSaved { id: DocumentId, path: PathBuf, }, DocumentChanged { id: DocumentId, path: Option<PathBuf>, version: u64, edits: Vec<AppliedEdit>, }, SelectionsChanged { id: DocumentId, version: u64, selections: SelectionSet, }, ModalModeChanged { from: String, to: String, }, BeforeQuit, OptionChanged { name: String, old: Option<String>, new: String, }, MajorEntered { buffer: BufferId, major: String, }, MajorExiting { buffer: BufferId, major: String, }, MinorActivated { buffer: BufferId, minor: String, }, MinorDeactivated { buffer: BufferId, minor: String, }, Plugin { name: String, payload: Vec<u8>, }, PluginCrashed { plugin: u32, func: String, kind: String, }, PrePluginLoaded { name: String, }, PluginLoaded { name: String, id: u32, }, PluginUnloaded { name: String, id: u32, }, ModeEnablementRequested { mode: String, enabled: bool, }, BufferOptionOverrideRequested { buffer: BufferId, option: String, }, BackgroundTaskFinished { source: String, scope: Option<String>, label: String, outcome: TaskOutcome, }, FilesChanged { plugin: u32, paths: Vec<PathBuf>, },
}
Expand description

One editor-core state transition, as published on the event bus.

See the module docs for how this relates to typed events and the plugin boundary; each variant says when it fires, who publishes it, and what its fields carry.

Variants§

§

DocumentOpened

Fired when a document buffer opens. Subscribers (the LSP attach driver, future plugin hooks, project-watcher, completion warmer) react asynchronously; the publisher (Editor::publish_document_opened_for_active, run at boot for the initial document and after each :e <path> open) returns immediately. The event-driven design keeps the UI thread off the LSP initialize round-trip – aligned with paramount goal #4 (asynchronicity).

path is None for unsaved scratch buffers (no LSP attach work to drive). text carries the buffer’s initial content so subscribers don’t have to reach back through a document handle on the publish path – LSP hands it straight to didOpen.

Caveat: the current publisher builds id from the raw value of the buffer-registry id (DocumentId::new(buffer_id.0)), whereas every other document event carries the document’s own DocumentId. The two number spaces are not guaranteed to agree.

Fields

§id: DocumentId

The opened document (see the caveat above).

§path: Option<PathBuf>

Its file path; None for a scratch buffer.

§version: u64

The document’s text version at open — the version LSP’s didOpen starts from.

§text: String

The full initial content.

§

DocumentClosed

A document was closed. Subscribers drop per-document state keyed by id (the LSP references provider, multibuffer excerpts, diff and VCS caches all do).

Note: the variant is subscribed to and mirrored in WIT, but no production code path publishes it yet.

Fields

§id: DocumentId

The closed document.

§

BeforeSave

Fired before Self::DocumentSaved. Observation-only in v1; future revisions may carry a payload that handlers can mutate (formatters rewriting buffer content) or veto (return Err to abort the save).

Published by the host’s save paths (:w and background saves) immediately before the write.

Fields

§id: DocumentId

The document about to be written.

§path: PathBuf

Where it is about to be written.

§

DocumentSaved

A document was written to disk successfully (after Self::BeforeSave; a failed write publishes nothing further). Published by the host’s save paths, including background saves of buffers the user is not looking at.

Fields

§id: DocumentId

The saved document.

§path: PathBuf

The path actually written.

§

DocumentChanged

A document’s text changed. Published by the host after each applied edit (and by lattice-multibuffer when an edit through a multibuffer lands in its source document). LSP’s didChange, the multibuffer’s excerpt refresh and the diff subsystem feed on it.

Fields

§id: DocumentId

The changed document.

§path: Option<PathBuf>

The buffer’s filesystem path, if it has one. Carried so subscribers can resolve URIs without holding their own DocumentId -> path map. None for scratch / unsaved buffers.

§version: u64

The document’s whole version after the change (see the module docs on versions).

§edits: Vec<AppliedEdit>

The edits, in the order they were applied; each one’s ranges are in the coordinates of the buffer as the previous one left it. Today’s publishers send one edit per event.

§

SelectionsChanged

The selection set of a document changed — visual extension, a selection-changing effect, gv. Published by Editor::publish_selections_changed. Carries the complete new set, not a delta.

Fields

§id: DocumentId

The document whose selections changed.

§version: u64

The document’s whole version after the change.

§selections: SelectionSet

The full new selection set.

§

ModalModeChanged

Fired when the modal state transitions (Normal -> Insert, Insert -> Normal, …). Carries the previous and next state as opaque labels; the App owns the ModalState type so the protocol layer keeps it as String.

Published by the host’s modal-state setter, only on a real transition. The labels are the Debug rendering of the host’s ModalState ("Normal", "Insert", …).

Fields

§from: String

The state being left.

§to: String

The state being entered.

§

BeforeQuit

Fired before the editor exits. Observation-only in v1; the veto path (a handler returning Err to abort quit) layers on once the bus grows the Before-event mutation semantics.

§

OptionChanged

Fired after a typed-options registry value changes (DESIGN.md §5.12). Carries the option’s canonical name plus the formatted old / new value strings – string-formatted (rather than Box<dyn Any>) because most subscribers just react to the change signal and don’t need the typed value. Subscribers that need the typed value re-read through the registry (config.with(handle, |v| ...)).

old is None for the very first publish after registration (when the option is initialised to its default and no prior value exists); subsequent edits always carry both sides.

Published by lattice_config::ConfigRegistry through its injected publisher, after the write and outside the registry lock (so a handler may read other options).

Fields

§name: String

The option’s canonical name (tabstop, not ts).

§old: Option<String>

The previous value, formatted; None on the first publish.

§new: String

The new value, formatted as :set would print it.

§

MajorEntered

A major mode became the active major on buffer (published after the mode’s on_activate resolved, so subscribers see a consistent state). major is the major mode’s canonical name (e.g. rust-mode) – carried as a String so the protocol layer stays free of the ModeId type, mirroring Self::ModalModeChanged.

This is the event minor-mode activation triggers filter on: EventFilter.major_modes matches against major (mode-architecture.md §7.4). Published by the mode dispatcher’s cascade task (MA.1); supersedes the prior typed ModeEvent::MajorEntered so the EF.1 filter machinery applies.

Fields

§buffer: BufferId

The buffer the major mode is now active on.

§major: String

The major mode’s canonical name.

§

MajorExiting

The active major mode on buffer is about to be deactivated (published before the mode’s Guard drops, so subscribers can inspect what’s being torn down). Pairs with Self::MajorEntered for minor-mode teardown. major is the canonical name of the major being torn down.

Fields

§buffer: BufferId

The buffer the major mode is leaving.

§major: String

The major mode’s canonical name.

§

MinorActivated

A minor mode was activated on buffer (published after its on_activate resolved). minor is the minor mode’s canonical name. The full observable mode-lifecycle quartet (MajorEntered/MajorExiting/MinorActivated/MinorDeactivated) lives on this Event enum (design.md §5.10.1) so hooks / EventFilter apply uniformly; only the internal ModeActivationFailed / OptionConflict cascade signals stay on the typed lattice_mode::ModeEvent bus.

Fields

§buffer: BufferId

The buffer the minor mode is now active on.

§minor: String

The minor mode’s canonical name.

§

MinorDeactivated

A minor mode was deactivated on buffer (published before its Guard drops). minor is the minor mode’s canonical name.

Fields

§buffer: BufferId

The buffer the minor mode is leaving.

§minor: String

The minor mode’s canonical name.

§

Plugin

A plugin-DEFINED event (PH7.8b). Unlike every arm above – each a closed, host-owned editor-core transition – this arm is the OPEN escape hatch a runtime-loaded plugin publishes through (host-services emit-event). The host is a thin router: name is the plugin’s event identifier (declared via register-event, surfaced in the runtime event registry, event_registry); payload is opaque MessagePack the plugin owns and the host NEVER interprets – the boundary discipline the plugin host rests on. Every plugin event shares this one variant + EventKind::Plugin; subscribers filter by name inside their handler (the bus discriminates only to Plugin, not per-name), so a new plugin event needs no enum/WIT change.

Fields

§name: String

The plugin-declared event name (my-plugin.file-indexed).

§payload: Vec<u8>

Opaque MessagePack bytes, owned and interpreted only by plugins.

§

PluginCrashed

A plugin instance crashed (a lifecycle / callback export trapped: fuel exhaustion, epoch deadline, a guest panic, or any wasm trap) and was quarantined by the host (PH7.12). Unlike Self::Plugin – the OPEN escape hatch a live plugin publishes through – this is a CLOSED, host-owned lifecycle transition the host itself originates, mirroring the mode-lifecycle quartet (Self::MinorDeactivated et al.): the host is the sole publisher, and subscribers (a future crash-notification surface, the Phase-8 plugin manager’s reload/health UI) filter it by kind, not by string-matching a name.

Fired exactly once per instance – on the first trap that trips quarantine. A component trap taints its instance irrecoverably (wasmtime offers no rollback), so the instance is dead-until-reinstantiation: every later call short-circuits without re-entering the dead Store, and no further PluginCrashed fires until a reload (PH7.12b) mints a fresh instance. The guarantee is isolation: the editor, actor, other plugins, LSP, and UI are untouched.

plugin is the host-issued numeric plugin id (the same id inside SourceLayer::Plugin(id)); func is the export that trapped ("on-event" / "spec" / "generate" / "apply-motion" / …); kind is a stable machine label ("fuel" / "epoch" / "trap") – a String (not the host’s TrapKind) so the protocol layer stays free of the plugin-host type, mirroring Self::ModalModeChanged.

Host-internal: refused at the plugin boundary, never delivered to a guest.

Fields

§plugin: u32

The host-issued numeric id of the quarantined plugin instance.

§func: String

The export that trapped ("on-event", "spec", …).

§kind: String

Why: "fuel", "epoch" or "trap".

§

PrePluginLoaded

A named plugin is ABOUT to run the load-time exports that read its own options (OA.14d). Published by the loader mid-load: after the plugin’s config seam drained — so every option it declares EXISTS and can be set — and before every seam that consumes one.

It exists because Self::PluginLoaded is too late for a value the plugin reads at load. org derives its per-keyword theme elements and its generated highlight-query rules from org.todo-keywords inside register-theme-elements; a handler that runs after the load sets an option nothing will read again until a restart.

name is the manifest id, and it is carried rather than left implicit so a handler discriminates: config for a plugin you know is legible, config invited to run for every plugin on the disk is not.

Delivery is awaited. The loader publishes this via EventBus::publish_awaited and does not continue the load until every guest handler has returned — an unawaited publish would leave the handler racing the very export it exists to precede. It is the one event with that property; everything else on the bus is fire-and-forget.

Fields

§name: String

The loading plugin’s manifest id. (No numeric id: guests receive the name only.)

§

PluginLoaded

A plugin finished loading (CI.1): every seam drained, its modes / options / commands all registered. Published by the loader at load_discovered completion. UNLIKE Self::PluginCrashed, this IS delivered to guests — an init.rs subscribes (filtered by name) to run deferred config against a now-present plugin (with-eval-after-load; config-and-init.md). name is the manifest id; id the host-issued numeric plugin id.

Fields

§name: String

The plugin’s manifest id.

§id: u32

The host-issued numeric plugin id.

§

PluginUnloaded

A plugin was unloaded (CI.1): teardown reversed its contributions (:plugin-unload / crash-teardown). Delivered to guests so a handler can tear down its own dependent setup. Fields mirror Self::PluginLoaded.

Fields

§name: String

The plugin’s manifest id.

§id: u32

The host-issued numeric plugin id it had while loaded.

§

ModeEnablementRequested

A request to enable/disable a minor mode globally (CI.4) — the guest-to-Editor bridge for enable-mode / disable-mode. A plugin (init.rs) calls the modes-seam enable-mode from an on-plugin-loaded handler; the host publishes THIS, and the Editor (which owns the mode registry + the open-buffer set + the activator) flips the enablement and re-activates open buffers. Host-internal — NOT delivered back to guests (like Self::PluginCrashed). mode is the mode id.

Fields

§mode: String

The minor mode’s id.

§enabled: bool

true to enable globally, false to disable.

§

BufferOptionOverrideRequested

A request to set an option for ONE buffer — the guest-to-Editor bridge for set-option-in-buffer, and the peer of Self::ModeEnablementRequested in both shape and reason.

The config seam’s set-option writes the GLOBAL layer (it is the :set path). A handler that wants “wrap in org buffers” cannot use it: it would wrap everything, and nothing would unwrap on leaving org. The buffer-local layer is what expresses that, and it lives on the Editor (buffer_local_overrides) rather than in the ConfigRegistry the plugin host holds — hence the bridge.

Host-internal, NOT delivered back to guests: a plugin observing every other plugin’s option writes is a surveillance seam nobody asked for, and option-changed already reports the outcome.

Fields

§buffer: BufferId

The buffer the override applies to.

§option: String

name=value in :set syntax, parsed by the same parse_for_buffer_local the :setlocal path uses — so a guest cannot express anything :setlocal could not, and a bad value is rejected with the same message.

§

BackgroundTaskFinished

MG.41g: a long-running background operation finished.

The decoupling seam between producers of async work (magit’s git invocations, LSP requests, a plugin’s task) and whatever reports completion. Producers publish this and never mention notifications; the notification layer is one subscriber, so the policy — which levels surface, whether to notify at all, rate limiting — lives in one place and is configurable later without touching a single producer.

Replaces threading a NotificationStoreHandle into every spawner, which was opt-in and therefore already forgotten in five of magit’s ten (spawn_git, the generic one, among them).

Published today by magit’s git spawners; lattice-notify is the subscriber that turns it into a notification. Not yet mirrored in WIT, so it is not delivered to guests.

Fields

§source: String

Subsystem that ran it — "magit", "lsp", a plugin id. Lets a subscriber filter without parsing label.

§scope: Option<String>

NC.2: what the work was done in — a repository name, a project, a server. None when the work has no such place.

A field, not part of label, so every producer’s scope lands in the same place on screen: several notifications at once are told apart by reading one column, not by parsing each producer’s own phrasing.

§label: String

What was done, as an imperative phrase naming its object: "push main → origin/main", "drop stash@{2}". The outcome is appended by whoever reports it, so the label must read correctly before “failed” as well as before a summary.

§outcome: TaskOutcome

How it ended.

§

FilesChanged

OR.2: files under a directory a plugin asked the host to watch (host-services.watch) changed on disk.

Addressed, not broadcast. plugin is the host-issued numeric id of the plugin whose watch produced this, and the event-delivery actor drops any delivery whose plugin is not its own. The bus is a broadcast and a watch is a capability: a plugin granted fs:read over one directory must not learn which files under another plugin’s watched directory changed, and it would if this rode Self::Plugin — every EventKind::Plugin subscriber sees every plugin event. The id never crosses to a guest, because by the time it does it is always the guest’s own.

Many paths, one event. A git pull that rewrites two hundred files produces one delivery carrying two hundred paths, not two hundred deliveries: the host coalesces a burst behind a quiet window before publishing. A consumer re-reads what changed, so ordering within the batch carries no meaning and the paths are deduplicated and sorted.

Published by lattice-plugin-host’s watch host.

Fields

§plugin: u32

The host-issued numeric plugin id that armed the watch.

§paths: Vec<PathBuf>

Absolute paths that changed, created or were removed. A removal is reported as a change — the consumer stats the path — because an index that cannot see deletions offers destinations that no longer exist.

Implementations§

Source§

impl Event

Source

pub fn kind(&self) -> EventKind

Project the event to its EventKind discriminator. Used by the runtime event bus’s filter dispatch to bucket subscriptions without string-matching variant names.

Trait Implementations§

Source§

impl Clone for Event

Source§

fn clone(&self) -> Event

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Event

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Event

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for Event

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl Freeze for Event

§

impl RefUnwindSafe for Event

§

impl Send for Event

§

impl Sync for Event

§

impl Unpin for Event

§

impl UnsafeUnpin for Event

§

impl UnwindSafe for Event

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.