summaryrefslogtreecommitdiff
path: root/helix-lsp/src/lib.rs
diff options
context:
space:
mode:
authorJan Hrastnik2021-06-19 12:51:53 +0000
committerJan Hrastnik2021-06-19 12:51:53 +0000
commitcdd9347457f0608346894cd0aab35b412cb59a7b (patch)
tree468078c37311cb1c7f9e7d4bd8a03c493d25e669 /helix-lsp/src/lib.rs
parent97323dc2f90f81afc82bd929d111abda540bebe5 (diff)
parent2cbec2b0470d0759578929b224c445b69617b6b6 (diff)
Merge remote-tracking branch 'origin/master' into line_ending_detection
Diffstat (limited to 'helix-lsp/src/lib.rs')
-rw-r--r--helix-lsp/src/lib.rs127
1 files changed, 121 insertions, 6 deletions
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index cff62492..49d5527f 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -13,7 +13,10 @@ use helix_core::syntax::LanguageConfiguration;
use std::{
collections::{hash_map::Entry, HashMap},
- sync::Arc,
+ sync::{
+ atomic::{AtomicUsize, Ordering},
+ Arc,
+ },
};
use serde::{Deserialize, Serialize};
@@ -182,6 +185,30 @@ pub mod util {
}
#[derive(Debug, PartialEq, Clone)]
+pub enum MethodCall {
+ WorkDoneProgressCreate(lsp::WorkDoneProgressCreateParams),
+}
+
+impl MethodCall {
+ pub fn parse(method: &str, params: jsonrpc::Params) -> Option<MethodCall> {
+ use lsp::request::Request;
+ let request = match method {
+ lsp::request::WorkDoneProgressCreate::METHOD => {
+ let params: lsp::WorkDoneProgressCreateParams = params
+ .parse()
+ .expect("Failed to parse WorkDoneCreate params");
+ Self::WorkDoneProgressCreate(params)
+ }
+ _ => {
+ log::warn!("unhandled lsp request: {}", method);
+ return None;
+ }
+ };
+ Some(request)
+ }
+}
+
+#[derive(Debug, PartialEq, Clone)]
pub enum Notification {
PublishDiagnostics(lsp::PublishDiagnosticsParams),
ShowMessage(lsp::ShowMessageParams),
@@ -230,9 +257,10 @@ impl Notification {
#[derive(Debug)]
pub struct Registry {
- inner: HashMap<LanguageId, Arc<Client>>,
+ inner: HashMap<LanguageId, (usize, Arc<Client>)>,
- pub incoming: SelectAll<UnboundedReceiverStream<Call>>,
+ counter: AtomicUsize,
+ pub incoming: SelectAll<UnboundedReceiverStream<(usize, Call)>>,
}
impl Default for Registry {
@@ -245,10 +273,18 @@ impl Registry {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
+ counter: AtomicUsize::new(0),
incoming: SelectAll::new(),
}
}
+ pub fn get_by_id(&mut self, id: usize) -> Option<&Client> {
+ self.inner
+ .values()
+ .find(|(client_id, _)| client_id == &id)
+ .map(|(_, client)| client.as_ref())
+ }
+
pub fn get(&mut self, language_config: &LanguageConfiguration) -> Result<Arc<Client>> {
if let Some(config) = &language_config.language_server {
// avoid borrow issues
@@ -256,16 +292,17 @@ impl Registry {
let s_incoming = &mut self.incoming;
match inner.entry(language_config.scope.clone()) {
- Entry::Occupied(language_server) => Ok(language_server.get().clone()),
+ Entry::Occupied(entry) => Ok(entry.get().1.clone()),
Entry::Vacant(entry) => {
// initialize a new client
- let (mut client, incoming) = Client::start(&config.command, &config.args)?;
+ let id = self.counter.fetch_add(1, Ordering::Relaxed);
+ let (mut client, incoming) = Client::start(&config.command, &config.args, id)?;
// TODO: run this async without blocking
futures_executor::block_on(client.initialize())?;
s_incoming.push(UnboundedReceiverStream::new(incoming));
let client = Arc::new(client);
- entry.insert(client.clone());
+ entry.insert((id, client.clone()));
Ok(client)
}
}
@@ -273,6 +310,84 @@ impl Registry {
Err(Error::LspNotDefined)
}
}
+
+ pub fn iter_clients(&self) -> impl Iterator<Item = &Arc<Client>> {
+ self.inner.values().map(|(_, client)| client)
+ }
+}
+
+#[derive(Debug)]
+pub enum ProgressStatus {
+ Created,
+ Started(lsp::WorkDoneProgress),
+}
+
+impl ProgressStatus {
+ pub fn progress(&self) -> Option<&lsp::WorkDoneProgress> {
+ match &self {
+ ProgressStatus::Created => None,
+ ProgressStatus::Started(progress) => Some(&progress),
+ }
+ }
+}
+
+#[derive(Default, Debug)]
+/// Acts as a container for progress reported by language servers. Each server
+/// has a unique id assigned at creation through [`Registry`]. This id is then used
+/// to store the progress in this map.
+pub struct LspProgressMap(HashMap<usize, HashMap<lsp::ProgressToken, ProgressStatus>>);
+
+impl LspProgressMap {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Returns a map of all tokens coresponding to the lanaguage server with `id`.
+ pub fn progress_map(&self, id: usize) -> Option<&HashMap<lsp::ProgressToken, ProgressStatus>> {
+ self.0.get(&id)
+ }
+
+ /// Returns last progress status for a given server with `id` and `token`.
+ pub fn progress(&self, id: usize, token: &lsp::ProgressToken) -> Option<&ProgressStatus> {
+ self.0.get(&id).and_then(|values| values.get(token))
+ }
+
+ /// Checks if progress `token` for server with `id` is created.
+ pub fn is_created(&mut self, id: usize, token: &lsp::ProgressToken) -> bool {
+ self.0
+ .get(&id)
+ .map(|values| values.get(token).is_some())
+ .unwrap_or_default()
+ }
+
+ pub fn create(&mut self, id: usize, token: lsp::ProgressToken) {
+ self.0
+ .entry(id)
+ .or_default()
+ .insert(token, ProgressStatus::Created);
+ }
+
+ /// Ends the progress by removing the `token` from server with `id`, if removed returns the value.
+ pub fn end_progress(
+ &mut self,
+ id: usize,
+ token: &lsp::ProgressToken,
+ ) -> Option<ProgressStatus> {
+ self.0.get_mut(&id).and_then(|vals| vals.remove(token))
+ }
+
+ /// Updates the progess of `token` for server with `id` to `status`, returns the value replaced or `None`.
+ pub fn update(
+ &mut self,
+ id: usize,
+ token: lsp::ProgressToken,
+ status: lsp::WorkDoneProgress,
+ ) -> Option<ProgressStatus> {
+ self.0
+ .entry(id)
+ .or_default()
+ .insert(token, ProgressStatus::Started(status))
+ }
}
// REGISTRY = HashMap<LanguageId, Lazy/OnceCell<Arc<RwLock<Client>>>