pub struct LspSupervisor { /* private fields */ }Expand description
One LSP subsystem per editor instance.
Implementations§
Source§impl LspSupervisor
impl LspSupervisor
Sourcepub fn new(logger: LspLogger) -> Self
pub fn new(logger: LspLogger) -> Self
Construct an empty supervisor with shared logger +
diagnostics layer. Use add_config to populate the
config registry.
Sourcepub fn set_event_bus(&mut self, bus: Arc<EventBus>)
pub fn set_event_bus(&mut self, bus: Arc<EventBus>)
Install the editor event bus. Must be called once at
startup before any buffer opens; after the call every
actor spawned by the supervisor gets a per-actor fan-in
task (see crate::fan_in) that turns
Event::DocumentChanged into crate::actor::ServerHandle::record_edit
without ever taking the supervisor’s mutex.
Calling twice replaces the bus reference; existing actors keep their original fan-in subscriptions (we don’t re-spawn them on bus swap because that would race with in-flight events).
Sourcepub fn set_apply_edit_bus(&mut self, bus: ApplyEditBus)
pub fn set_apply_edit_bus(&mut self, bus: ApplyEditBus)
Install the apply-edit bus (Phase 4.3). The App calls
this once at startup with the sender side of the channel
it created; every actor spawned after this point gets a
clone and forwards inbound workspace/applyEdit
requests through it. Calling twice replaces the bus;
any actors already spawned keep their original clone
(we don’t track them for retro-fitting in v1).
Sourcepub fn set_configuration_bus(&mut self, bus: ConfigurationBus)
pub fn set_configuration_bus(&mut self, bus: ConfigurationBus)
Install the configuration bus (Phase 4.1 follow-up).
Same shape as Self::set_apply_edit_bus: cloned into
every actor spawned after the call so server-initiated
workspace/configuration requests reach the App’s
drain. None falls back to per-item null replies.
Sourcepub fn set_show_document_bus(&mut self, bus: ShowDocumentBus)
pub fn set_show_document_bus(&mut self, bus: ShowDocumentBus)
4.4.b: install the show-document bus. Cloned into every actor spawned (or restarted) after this call. The App calls this once at startup with the sender side of the channel whose receiver it holds.
Sourcepub fn set_show_message_request_bus(&mut self, bus: ShowMessageRequestBus)
pub fn set_show_message_request_bus(&mut self, bus: ShowMessageRequestBus)
4.4.b: install the show-message-request bus.
Sourcepub fn logger(&self) -> &LspLogger
pub fn logger(&self) -> &LspLogger
Borrow the shared logger (so callers can register their own subsystem-level events).
Sourcepub fn diagnostics(&self) -> &DiagnosticsLayer
pub fn diagnostics(&self) -> &DiagnosticsLayer
Borrow the shared diagnostics layer.
Sourcepub fn add_config(&mut self, config: ServerConfig)
pub fn add_config(&mut self, config: ServerConfig)
Add a server config to the registry. The App calls this for every builtin + user-override config at startup.
Sourcepub fn set_configs<I: IntoIterator<Item = ServerConfig>>(&mut self, configs: I)
pub fn set_configs<I: IntoIterator<Item = ServerConfig>>(&mut self, configs: I)
Set the registry from an iterator (e.g. the curated builtins). Replaces any prior contents.
Sourcepub fn configs(&self) -> &[Arc<ServerConfig>]
pub fn configs(&self) -> &[Arc<ServerConfig>]
All registered configs (read-only; for :lsp-status).
Sourcepub fn has_server_for_path(&self, path: &Path) -> bool
pub fn has_server_for_path(&self, path: &Path) -> bool
True iff at least one configured server’s file_patterns
matches path. M.5.2 uses this from the App’s
MajorEntered hook to decide whether to auto-activate
lsp-mode on the buffer; if no server cares about the
path, there’s nothing to gate on.
Sourcepub fn running_actors(&self) -> Vec<(ActorKey, ServerHandle)>
pub fn running_actors(&self) -> Vec<(ActorKey, ServerHandle)>
Every actor currently running. Used by :lsp-status.
Sourcepub fn all_running_handles(&self) -> Vec<ServerHandle>
pub fn all_running_handles(&self) -> Vec<ServerHandle>
Snapshot of every running actor’s ServerHandle. Used by
workspace-scoped LSP requests (e.g. workspace/symbol)
that fan out across every server, not just servers
attached to one buffer.
Sourcepub fn buffer_count_for(&self, key: &ActorKey) -> usize
pub fn buffer_count_for(&self, key: &ActorKey) -> usize
Number of buffers currently attached to the actor at
key. Cheap walk over attachments; used by
:lsp-server-log to surface per-server buffer counts in
the picker margin.
Sourcepub async fn open_buffer(
&mut self,
path: PathBuf,
text: String,
) -> LspResult<Vec<ServerHandle>>
pub async fn open_buffer( &mut self, path: PathBuf, text: String, ) -> LspResult<Vec<ServerHandle>>
Open a buffer. Walks the config registry, spawns
matching actors as needed, attaches the buffer to each,
and emits didOpen per server. Returns the list of
attached ServerHandles – the App stores this so
feature dispatch knows where to issue requests.
path is the buffer’s filesystem path; text is the
initial buffer text.
Sourcepub fn attach_handle(
&mut self,
uri: Uri,
workspace_root: PathBuf,
server_id: String,
language_id: String,
text: String,
handle: ServerHandle,
) -> LspResult<()>
pub fn attach_handle( &mut self, uri: Uri, workspace_root: PathBuf, server_id: String, language_id: String, text: String, handle: ServerHandle, ) -> LspResult<()>
Attach a buffer to a pre-built ServerHandle. Used by:
- Tests – the in-process
MockServerreturns a handle that the supervisor wouldn’t normally spawn. - Custom transports (future) – a TCP / named-pipe
server that bypasses
ChildTransport.
Identical effect to the actor-spawning branch of
open_buffer: registers the actor under
(workspace_root, server_id), builds a DocSync,
emits didOpen, records the attachment, and starts the
diagnostics pump if it isn’t already running.
Sourcepub fn close_buffer(&mut self, uri: &Uri) -> LspResult<()>
pub fn close_buffer(&mut self, uri: &Uri) -> LspResult<()>
Close a buffer. Flushes pending changes per attached
server, sends didClose, and drops the URI from
attachments + the diagnostics layer.
Sourcepub fn record_edit(&mut self, uri: &Uri, edit: &Edit) -> LspResult<()>
pub fn record_edit(&mut self, uri: &Uri, edit: &Edit) -> LspResult<()>
Forward an edit to every attached actor’s mailbox.
Not on the editor’s hot path. Production edits flow
through the editor event bus to a per-actor fan-in (see
crate::fan_in), which means the UI thread never
takes the supervisor mutex on a keystroke. This method
remains for tests + admin tooling that drive the
supervisor directly without standing up an event bus.
Sourcepub fn flush(&mut self, uri: &Uri) -> LspResult<()>
pub fn flush(&mut self, uri: &Uri) -> LspResult<()>
Force-flush queued changes for uri across every
attached server, bypassing the per-actor debounce. Used
before synchronous requests that require the server to
have seen the latest text – notably willSaveWaitUntil
and :lsp-flush.
Sourcepub fn flush_all(&mut self) -> LspResult<()>
pub fn flush_all(&mut self) -> LspResult<()>
Force-flush every open URI’s queued changes across every
attached server. Used at editor shutdown so each server
sees a coherent final state before didClose. Per-edit
flushing is debounced inside each actor; this is the
only “drain everything now” affordance.
Sourcepub fn servers_for(&self, uri: &Uri) -> Vec<ServerHandle>
pub fn servers_for(&self, uri: &Uri) -> Vec<ServerHandle>
Every server attached to uri. The App walks this list
to dispatch features (hover, goto-definition, …).
Sourcepub fn attached_buffer_count(&self) -> usize
pub fn attached_buffer_count(&self) -> usize
Number of currently-attached buffers.
Sourcepub fn running_actor_count(&self) -> usize
pub fn running_actor_count(&self) -> usize
Number of currently-running actors.
Sourcepub async fn restart_server(
&mut self,
server_id: &str,
) -> LspResult<RestartReport>
pub async fn restart_server( &mut self, server_id: &str, ) -> LspResult<RestartReport>
4.4.d: force-restart every actor with id server_id.
Steps:
- Prune restart history outside the private
RESTART_WINDOW. - If
history.len() >= MAX_RESTARTS, refuse (caller surfaces the cooldown to the user). - Sleep
compute_restart_backoff(history.len()). - For every
(workspace, server_id)actor pair: shut down the existing handle, drop the fan-in subscription, spawn a fresh actor with the same config, restart the diagnostics pump + fan-in. - Replay
didOpenfor every URI that pointed at the old actor so the new actor sees the same workspace state. - Push
Instant::now()to history.
Replayed didOpen uses each tracked URI’s last-known
text; today the supervisor doesn’t keep that text (each
actor’s DocSync owns the mirror), so the replay uses
the empty string and the App is expected to re-send the
full buffer via the next didChange debounce. Future
revision can snapshot text into RestartReport and let
the App ferry it back via record_edit proactively.
Returns the list of (workspace, server_id) keys that
were re-spawned and the URIs that need re-opening.
Source§impl LspSupervisor
impl LspSupervisor
Sourcepub fn spawn(self, runtime_handle: &Handle) -> LspSupervisorHandle
pub fn spawn(self, runtime_handle: &Handle) -> LspSupervisorHandle
Consume the configured supervisor and start the supervisor
task on runtime_handle. Returns the
LspSupervisorHandle App-side code uses for the rest of
the editor’s lifetime.
After this call, all mutating operations route through the
returned handle’s mailbox; reads come from the wait-free
ArcSwap<SupervisorSnapshot>. The LspSupervisor itself
is owned exclusively by the spawned task – no Arc, no
Mutex, no contention possible with the UI thread.
Configuration calls (set_event_bus, set_apply_edit_bus,
set_configuration_bus, add_config, set_configs) must
happen before spawn – the post-spawn handle does not
expose them. This matches the editor’s actual lifecycle:
the App configures the supervisor at startup before any
buffer opens.
runtime_handle is mandatory: the supervisor’s command-
mailbox semantics only make sense against a live tokio
task, and a missing runtime is a programming error.
Production callers (App::new →
build_lsp_subsystem) pass the editor’s shared LSP
runtime handle (runtime::lsp_runtime()); tests that
exercise the write path build an ad-hoc runtime via
tokio::runtime::Builder and pass its handle. Earlier
revisions used tokio::runtime::Handle::try_current()
with a silent fallback that dropped cmd_rx; that path
surfaced as LspError::ActorGone on every write whenever
the caller didn’t happen to be inside a tokio context,
which proved to be a real footgun (e.g. App::new runs
before runtime::run has entered any context).
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for LspSupervisor
impl !UnwindSafe for LspSupervisor
impl Freeze for LspSupervisor
impl Send for LspSupervisor
impl Sync for LspSupervisor
impl Unpin for LspSupervisor
impl UnsafeUnpin for LspSupervisor
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more