on master help sign in
Don't panic on LSP not starting
960bc9fEgor Karavaev
helix-lsp/src/client.rs+1−1
@@ -153,7 +153,7 @@ impl Client {
153 timeout(Duration::from_secs(2), rx.recv())
153 timeout(Duration::from_secs(2), rx.recv())
154 .await
154 .await
155 .map_err(|_| Error::Timeout)? // return Timeout
155 .map_err(|_| Error::Timeout)? // return Timeout
156− .unwrap() // TODO: None if channel closed
156+ .ok_or(Error::StreamClosed)?
157 }
157 }
158 }
158 }
159
159
helix-lsp/src/lib.rs+22−21
@@ -13,7 +13,10 @@ use helix_core::syntax::LanguageConfiguration;
13
13
14use thiserror::Error;
14use thiserror::Error;
15
15
16+use std::{
16−use std::{collections::HashMap, sync::Arc};
17+ collections::{hash_map::Entry, HashMap},
18+ sync::Arc,
19+};
17
20
18use serde::{Deserialize, Serialize};
21use serde::{Deserialize, Serialize};
19
22
@@ -29,6 +32,10 @@ pub enum Error {
29 Parse(#[from] serde_json::Error),
32 Parse(#[from] serde_json::Error),
30 #[error("request timed out")]
33 #[error("request timed out")]
31 Timeout,
34 Timeout,
35+ #[error("server closed the stream")]
36+ StreamClosed,
37+ #[error("LSP not defined")]
38+ LspNotDefined,
32 #[error(transparent)]
39 #[error(transparent)]
33 Other(#[from] anyhow::Error),
40 Other(#[from] anyhow::Error),
34}
41}
@@ -173,7 +180,7 @@ type LanguageId = String;
173use futures_util::stream::select_all::SelectAll;
180use futures_util::stream::select_all::SelectAll;
174
181
175pub struct Registry {
182pub struct Registry {
176− inner: HashMap<LanguageId, Option<Arc<Client>>>,
183+ inner: HashMap<LanguageId, Arc<Client>>,
177
184
178 pub incoming: SelectAll<UnboundedReceiverStream<Call>>,
185 pub incoming: SelectAll<UnboundedReceiverStream<Call>>,
179}
186}
@@ -192,35 +199,29 @@ impl Registry {
192 }
199 }
193 }
200 }
194
201
195− pub fn get(&mut self, language_config: &LanguageConfiguration) -> Option<Arc<Client>> {
202+ pub fn get(&mut self, language_config: &LanguageConfiguration) -> Result<Arc<Client>> {
196− // TODO: propagate the error
197 if let Some(config) = &language_config.language_server {
203 if let Some(config) = &language_config.language_server {
198 // avoid borrow issues
204 // avoid borrow issues
199 let inner = &mut self.inner;
205 let inner = &mut self.inner;
200 let s_incoming = &mut self.incoming;
206 let s_incoming = &mut self.incoming;
201
207
202− let language_server = inner
203− .entry(language_config.scope.clone()) // can't use entry with Borrow keys: https://github.com/rust-lang/rfcs/pull/1769
208+ match inner.entry(language_config.scope.clone()) {
204− .or_insert_with(|| {
209+ Entry::Occupied(language_server) => Ok(language_server.get().clone()),
205− // TODO: lookup defaults for id (name, args)
210+ Entry::Vacant(entry) => {
206−
207 // initialize a new client
211 // initialize a new client
208− let (mut client, incoming) =
209− Client::start(&config.command, &config.args).ok()?;
212+ let (mut client, incoming) = Client::start(&config.command, &config.args)?;
210−
211 // TODO: run this async without blocking
213 // TODO: run this async without blocking
212− futures_executor::block_on(client.initialize()).unwrap();
214+ futures_executor::block_on(client.initialize())?;
213−
214 s_incoming.push(UnboundedReceiverStream::new(incoming));
215 s_incoming.push(UnboundedReceiverStream::new(incoming));
216+ let client = Arc::new(client);
215
217
216− Some(Arc::new(client))
218+ entry.insert(client.clone());
217− })
219+ Ok(client)
218− .clone();
220+ }
219−
221+ }
220− return language_server;
222+ } else {
223+ Err(Error::LspNotDefined)
221 }
224 }
222−
223− None
224 }
225 }
225}
226}
226
227
helix-view/src/editor.rs+2−2
@@ -155,7 +155,7 @@ impl Editor {
155 let language_server = doc
155 let language_server = doc
156 .language
156 .language
157 .as_ref()
157 .as_ref()
158− .and_then(|language| self.language_servers.get(language));
158+ .and_then(|language| self.language_servers.get(language).ok());
159
159
160 if let Some(language_server) = language_server {
160 if let Some(language_server) = language_server {
161 doc.set_language_server(Some(language_server.clone()));
161 doc.set_language_server(Some(language_server.clone()));
@@ -196,7 +196,7 @@ impl Editor {
196 let language_server = doc
196 let language_server = doc
197 .language
197 .language
198 .as_ref()
198 .as_ref()
199− .and_then(|language| language_servers.get(language));
199+ .and_then(|language| language_servers.get(language).ok());
200 if let Some(language_server) = language_server {
200 if let Some(language_server) = language_server {
201 tokio::spawn(language_server.text_document_did_close(doc.identifier()));
201 tokio::spawn(language_server.text_document_did_close(doc.identifier()));
202 }
202 }