diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index a1c1134a..41c38fd9 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -153,7 +153,7 @@ impl Client { timeout(Duration::from_secs(2), rx.recv()) .await .map_err(|_| Error::Timeout)? // return Timeout - .unwrap() // TODO: None if channel closed + .ok_or(Error::StreamClosed)? } } diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index eeb2cdbb..af8c9005 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -13,7 +13,10 @@ use helix_core::syntax::LanguageConfiguration; use thiserror::Error; -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::{hash_map::Entry, HashMap}, + sync::Arc, +}; use serde::{Deserialize, Serialize}; @@ -29,6 +32,10 @@ pub enum Error { Parse(#[from] serde_json::Error), #[error("request timed out")] Timeout, + #[error("server closed the stream")] + StreamClosed, + #[error("LSP not defined")] + LspNotDefined, #[error(transparent)] Other(#[from] anyhow::Error), } @@ -173,7 +180,7 @@ type LanguageId = String; use futures_util::stream::select_all::SelectAll; pub struct Registry { - inner: HashMap>>, + inner: HashMap>, pub incoming: SelectAll>, } @@ -192,35 +199,29 @@ impl Registry { } } - pub fn get(&mut self, language_config: &LanguageConfiguration) -> Option> { - // TODO: propagate the error + pub fn get(&mut self, language_config: &LanguageConfiguration) -> Result> { if let Some(config) = &language_config.language_server { // avoid borrow issues let inner = &mut self.inner; let s_incoming = &mut self.incoming; - let language_server = inner - .entry(language_config.scope.clone()) // can't use entry with Borrow keys: https://github.com/rust-lang/rfcs/pull/1769 - .or_insert_with(|| { - // TODO: lookup defaults for id (name, args) - + match inner.entry(language_config.scope.clone()) { + Entry::Occupied(language_server) => Ok(language_server.get().clone()), + Entry::Vacant(entry) => { // initialize a new client - let (mut client, incoming) = - Client::start(&config.command, &config.args).ok()?; - + let (mut client, incoming) = Client::start(&config.command, &config.args)?; // TODO: run this async without blocking - futures_executor::block_on(client.initialize()).unwrap(); - + futures_executor::block_on(client.initialize())?; s_incoming.push(UnboundedReceiverStream::new(incoming)); + let client = Arc::new(client); - Some(Arc::new(client)) - }) - .clone(); - - return language_server; + entry.insert(client.clone()); + Ok(client) + } + } + } else { + Err(Error::LspNotDefined) } - - None } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index b69ae22f..7af19a9b 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -155,7 +155,7 @@ impl Editor { let language_server = doc .language .as_ref() - .and_then(|language| self.language_servers.get(language)); + .and_then(|language| self.language_servers.get(language).ok()); if let Some(language_server) = language_server { doc.set_language_server(Some(language_server.clone())); @@ -196,7 +196,7 @@ impl Editor { let language_server = doc .language .as_ref() - .and_then(|language| language_servers.get(language)); + .and_then(|language| language_servers.get(language).ok()); if let Some(language_server) = language_server { tokio::spawn(language_server.text_document_did_close(doc.identifier())); }