diff options
Diffstat (limited to 'cli/lsp/client.rs')
-rw-r--r-- | cli/lsp/client.rs | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/cli/lsp/client.rs b/cli/lsp/client.rs new file mode 100644 index 000000000..102304879 --- /dev/null +++ b/cli/lsp/client.rs @@ -0,0 +1,228 @@ +use std::future::Future; +use std::pin::Pin; +use std::sync::Arc; + +use deno_core::anyhow::anyhow; +use deno_core::error::AnyError; +use deno_core::futures::future; +use deno_core::serde_json; +use deno_core::serde_json::json; +use lspower::lsp; + +use crate::lsp::config::SETTINGS_SECTION; +use crate::lsp::repl::get_repl_workspace_settings; + +use super::lsp_custom; + +#[derive(Clone)] +pub struct Client(Arc<dyn ClientTrait>); + +impl std::fmt::Debug for Client { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("Client").finish() + } +} + +impl Client { + pub fn from_lspower(client: lspower::Client) -> Self { + Self(Arc::new(LspowerClient(client))) + } + + pub fn new_for_repl() -> Self { + Self(Arc::new(ReplClient)) + } + + pub async fn publish_diagnostics( + &self, + uri: lsp::Url, + diags: Vec<lsp::Diagnostic>, + version: Option<i32>, + ) { + self.0.publish_diagnostics(uri, diags, version).await; + } + + pub async fn send_registry_state_notification( + &self, + params: lsp_custom::RegistryStateNotificationParams, + ) { + self.0.send_registry_state_notification(params).await; + } + + pub async fn configuration( + &self, + items: Vec<lsp::ConfigurationItem>, + ) -> Result<Vec<serde_json::Value>, AnyError> { + self.0.configuration(items).await + } + + pub async fn show_message( + &self, + message_type: lsp::MessageType, + message: impl std::fmt::Display, + ) { + self + .0 + .show_message(message_type, format!("{}", message)) + .await + } + + pub async fn register_capability( + &self, + registrations: Vec<lsp::Registration>, + ) -> Result<(), AnyError> { + self.0.register_capability(registrations).await + } +} + +type AsyncReturn<T> = Pin<Box<dyn Future<Output = T> + 'static + Send>>; + +trait ClientTrait: Send + Sync { + fn publish_diagnostics( + &self, + uri: lsp::Url, + diagnostics: Vec<lsp::Diagnostic>, + version: Option<i32>, + ) -> AsyncReturn<()>; + fn send_registry_state_notification( + &self, + params: lsp_custom::RegistryStateNotificationParams, + ) -> AsyncReturn<()>; + fn configuration( + &self, + items: Vec<lsp::ConfigurationItem>, + ) -> AsyncReturn<Result<Vec<serde_json::Value>, AnyError>>; + fn show_message( + &self, + message_type: lsp::MessageType, + text: String, + ) -> AsyncReturn<()>; + fn register_capability( + &self, + registrations: Vec<lsp::Registration>, + ) -> AsyncReturn<Result<(), AnyError>>; +} + +#[derive(Clone)] +struct LspowerClient(lspower::Client); + +impl ClientTrait for LspowerClient { + fn publish_diagnostics( + &self, + uri: lsp::Url, + diagnostics: Vec<lsp::Diagnostic>, + version: Option<i32>, + ) -> AsyncReturn<()> { + let client = self.0.clone(); + Box::pin(async move { + client.publish_diagnostics(uri, diagnostics, version).await + }) + } + + fn send_registry_state_notification( + &self, + params: lsp_custom::RegistryStateNotificationParams, + ) -> AsyncReturn<()> { + let client = self.0.clone(); + Box::pin(async move { + client + .send_custom_notification::<lsp_custom::RegistryStateNotification>( + params, + ) + .await + }) + } + + fn configuration( + &self, + items: Vec<lsp::ConfigurationItem>, + ) -> AsyncReturn<Result<Vec<serde_json::Value>, AnyError>> { + let client = self.0.clone(); + Box::pin(async move { + client + .configuration(items) + .await + .map_err(|err| anyhow!("{}", err)) + }) + } + + fn show_message( + &self, + message_type: lsp::MessageType, + message: String, + ) -> AsyncReturn<()> { + let client = self.0.clone(); + Box::pin(async move { client.show_message(message_type, message).await }) + } + + fn register_capability( + &self, + registrations: Vec<lsp::Registration>, + ) -> AsyncReturn<Result<(), AnyError>> { + let client = self.0.clone(); + Box::pin(async move { + client + .register_capability(registrations) + .await + .map_err(|err| anyhow!("{}", err)) + }) + } +} + +#[derive(Clone)] +struct ReplClient; + +impl ClientTrait for ReplClient { + fn publish_diagnostics( + &self, + _uri: lsp::Url, + _diagnostics: Vec<lsp::Diagnostic>, + _version: Option<i32>, + ) -> AsyncReturn<()> { + Box::pin(future::ready(())) + } + + fn send_registry_state_notification( + &self, + _params: lsp_custom::RegistryStateNotificationParams, + ) -> AsyncReturn<()> { + Box::pin(future::ready(())) + } + + fn configuration( + &self, + items: Vec<lsp::ConfigurationItem>, + ) -> AsyncReturn<Result<Vec<serde_json::Value>, AnyError>> { + let is_global_config_request = items.len() == 1 + && items[0].scope_uri.is_none() + && items[0].section.as_deref() == Some(SETTINGS_SECTION); + let response = if is_global_config_request { + vec![serde_json::to_value(get_repl_workspace_settings()).unwrap()] + } else { + // all specifiers are enabled for the REPL + items + .into_iter() + .map(|_| { + json!({ + "enable": true, + }) + }) + .collect() + }; + Box::pin(future::ready(Ok(response))) + } + + fn show_message( + &self, + _message_type: lsp::MessageType, + _message: String, + ) -> AsyncReturn<()> { + Box::pin(future::ready(())) + } + + fn register_capability( + &self, + _registrations: Vec<lsp::Registration>, + ) -> AsyncReturn<Result<(), AnyError>> { + Box::pin(future::ready(Ok(()))) + } +} |