on master help sign in
Handle language server termination (#4797)
8be2d1dMichael Davis
helix-lsp/src/lib.rs+7
@@ -282,6 +282,8 @@ impl MethodCall {
282pub enum Notification {
282pub enum Notification {
283 // we inject this notification to signal the LSP is ready
283 // we inject this notification to signal the LSP is ready
284 Initialized,
284 Initialized,
285+ // and this notification to signal that the LSP exited
286+ Exit,
285 PublishDiagnostics(lsp::PublishDiagnosticsParams),
287 PublishDiagnostics(lsp::PublishDiagnosticsParams),
286 ShowMessage(lsp::ShowMessageParams),
288 ShowMessage(lsp::ShowMessageParams),
287 LogMessage(lsp::LogMessageParams),
289 LogMessage(lsp::LogMessageParams),
@@ -294,6 +296,7 @@ impl Notification {
294
296
295 let notification = match method {
297 let notification = match method {
296 lsp::notification::Initialized::METHOD => Self::Initialized,
298 lsp::notification::Initialized::METHOD => Self::Initialized,
299+ lsp::notification::Exit::METHOD => Self::Exit,
297 lsp::notification::PublishDiagnostics::METHOD => {
300 lsp::notification::PublishDiagnostics::METHOD => {
298 let params: lsp::PublishDiagnosticsParams = params.parse()?;
301 let params: lsp::PublishDiagnosticsParams = params.parse()?;
299 Self::PublishDiagnostics(params)
302 Self::PublishDiagnostics(params)
@@ -350,6 +353,10 @@ impl Registry {
350 .map(|(_, client)| client.as_ref())
353 .map(|(_, client)| client.as_ref())
351 }
354 }
352
355
356+ pub fn remove_by_id(&mut self, id: usize) {
357+ self.inner.retain(|_, (client_id, _)| client_id != &id)
358+ }
359+
353 pub fn restart(
360 pub fn restart(
354 &mut self,
361 &mut self,
355 language_config: &LanguageConfiguration,
362 language_config: &LanguageConfiguration,
helix-lsp/src/transport.rs+20
@@ -250,6 +250,26 @@ impl Transport {
250 }
250 }
251 };
251 };
252 }
252 }
253+ Err(Error::StreamClosed) => {
254+ // Hack: inject a terminated notification so we trigger code that needs to happen after exit
255+ use lsp_types::notification::Notification as _;
256+ let notification =
257+ ServerMessage::Call(jsonrpc::Call::Notification(jsonrpc::Notification {
258+ jsonrpc: None,
259+ method: lsp_types::notification::Exit::METHOD.to_string(),
260+ params: jsonrpc::Params::None,
261+ }));
262+ match transport
263+ .process_server_message(&client_tx, notification)
264+ .await
265+ {
266+ Ok(_) => {}
267+ Err(err) => {
268+ error!("err: <- {:?}", err);
269+ }
270+ }
271+ break;
272+ }
253 Err(err) => {
273 Err(err) => {
254 error!("err: <- {:?}", err);
274 error!("err: <- {:?}", err);
255 break;
275 break;
helix-term/src/application.rs+26
@@ -871,6 +871,32 @@ impl Application {
871 Notification::ProgressMessage(_params) => {
871 Notification::ProgressMessage(_params) => {
872 // do nothing
872 // do nothing
873 }
873 }
874+ Notification::Exit => {
875+ self.editor.set_status("Language server exited");
876+
877+ // Clear any diagnostics for documents with this server open.
878+ let urls: Vec<_> = self
879+ .editor
880+ .documents_mut()
881+ .filter_map(|doc| {
882+ if doc.language_server().map(|server| server.id())
883+ == Some(server_id)
884+ {
885+ doc.set_diagnostics(Vec::new());
886+ doc.url()
887+ } else {
888+ None
889+ }
890+ })
891+ .collect();
892+
893+ for url in urls {
894+ self.editor.diagnostics.remove(&url);
895+ }
896+
897+ // Remove the language server from the registry.
898+ self.editor.language_servers.remove_by_id(server_id);
899+ }
874 }
900 }
875 }
901 }
876 Call::MethodCall(helix_lsp::jsonrpc::MethodCall {
902 Call::MethodCall(helix_lsp::jsonrpc::MethodCall {