From 70fc5659734492b9c8d2a0a25a096a5e520e6cdc Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Wed, 18 Dec 2024 09:48:16 +0000 Subject: [PATCH] (lsp) rewrite LSP service using traits A dashmap of closures was silly. This is much cleaner --- Cargo.toml | 1 - crates/hdx/src/main.rs | 4 +- crates/hdx_lsp/src/handlers.rs | 145 ----- crates/hdx_lsp/src/jsonrpc/id.rs | 6 + crates/hdx_lsp/src/jsonrpc/message.rs | 49 +- crates/hdx_lsp/src/lib.rs | 6 +- crates/hdx_lsp/src/server.rs | 207 ++---- crates/hdx_lsp/src/server/handler.rs | 885 ++++++++++++++++++++++++++ crates/hdx_lsp/src/service.rs | 182 ++++++ 9 files changed, 1163 insertions(+), 322 deletions(-) delete mode 100644 crates/hdx_lsp/src/handlers.rs create mode 100644 crates/hdx_lsp/src/server/handler.rs create mode 100644 crates/hdx_lsp/src/service.rs diff --git a/Cargo.toml b/Cargo.toml index 300ba522..4e70229b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,6 @@ crossbeam-channel = { version = "0.5.13" } dashmap = { version = "6.1.0" } # Logging -log = { version = "0.4.22" } tracing = { version = "0.1.41" } tracing-subscriber = { version = "0.3.19" } console = { version = "0.15.8" } diff --git a/crates/hdx/src/main.rs b/crates/hdx/src/main.rs index f520a434..576eb803 100644 --- a/crates/hdx/src/main.rs +++ b/crates/hdx/src/main.rs @@ -1,7 +1,7 @@ use bumpalo::Bump; use clap::{crate_version, Parser, Subcommand}; use hdx_ast::css::StyleSheet; -use hdx_lsp::server_with_handlers; +use hdx_lsp::{LSPService, Server}; use hdx_parser::{CursorStream, ToCursors}; use miette::{GraphicalReportHandler, GraphicalTheme, NamedSource}; use std::io; @@ -141,7 +141,7 @@ fn main() { } } Commands::Lsp {} => { - let server = server_with_handlers(crate_version!()); + let server = Server::new(LSPService::new(crate_version!())); let stderr_log = fmt::layer().with_writer(io::stderr).with_filter(LevelFilter::TRACE); registry().with(stderr_log).with(server.tracer()).init(); let thread = server.listen_stdio().unwrap(); diff --git a/crates/hdx_lsp/src/handlers.rs b/crates/hdx_lsp/src/handlers.rs deleted file mode 100644 index a86d242f..00000000 --- a/crates/hdx_lsp/src/handlers.rs +++ /dev/null @@ -1,145 +0,0 @@ -use bumpalo::Bump; -use dashmap::DashMap; -use hdx_ast::css::{StyleSheet, Visitable}; -use hdx_highlight::{SemanticKind, SemanticModifier, TokenHighlighter}; -use hdx_parser::{Features, Parser}; -use itertools::Itertools; -use lsp_types::{ - notification::{DidChangeTextDocument, DidOpenTextDocument}, - request::{Initialize, SemanticTokensFullRequest}, - InitializeResult, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens, - SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, SemanticTokensResult, - SemanticTokensServerCapabilities, ServerCapabilities, ServerInfo, TextDocumentSyncCapability, TextDocumentSyncKind, - TextDocumentSyncOptions, TextDocumentSyncSaveOptions, Uri, WorkDoneProgressOptions, -}; -use std::{io, sync::Arc}; -use strum::VariantNames; -use tracing::trace; - -use crate::Server; - -pub fn server_with_handlers(version: &'static str) -> Server { - let files = Arc::new(DashMap::::new()); - let files_for_semantic_tokens = files.clone(); - let files_for_open_doc = files.clone(); - let files_for_change_doc = files.clone(); - Server::new() - .handle::(move |_| -> Result { - Ok(InitializeResult { - capabilities: ServerCapabilities { - // position_encoding: (), - text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { - open_close: Some(true), - change: Some(TextDocumentSyncKind::FULL), - will_save: Some(true), - will_save_wait_until: Some(false), - save: Some(TextDocumentSyncSaveOptions::Supported(false)), - })), - // notebook_document_sync: (), - // selection_range_provider: (), - // hover_provider: (), - // completion_provider: (), - // signature_help_provider: (), - // definition_provider: (), - // type_definition_provider: (), - // implementation_provider: (), - // references_provider: (), - // document_highlight_provider: (), - // document_symbol_provider: (), - // workspace_symbol_provider: (), - // code_action_provider: (), - // code_lens_provider: (), - // document_formatting_provider: (), - // document_range_formatting_provider: (), - // document_on_type_formatting_provider: (), - // rename_provider: (), - // document_link_provider: (), - // color_provider: (), - // folding_range_provider: (), - // declaration_provider: (), - // execute_command_provider: (), - // workspace: (), - // call_hierarchy_provider: (), - semantic_tokens_provider: Some(SemanticTokensServerCapabilities::SemanticTokensOptions( - SemanticTokensOptions { - work_done_progress_options: WorkDoneProgressOptions { work_done_progress: Some(false) }, - legend: SemanticTokensLegend { - token_types: SemanticKind::VARIANTS.iter().map(|v| SemanticTokenType::new(v)).collect(), - token_modifiers: SemanticModifier::VARIANTS - .iter() - .map(|v| SemanticTokenModifier::new(v)) - .collect(), - }, - range: Some(false), - full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), - }, - )), - // moniker_provider: (), - // linked_editing_range_provider: (), - // inline_value_provider: (), - // inlay_hint_provider: (), - // diagnostic_provider: (), - // inline_completion_provider: (), - // experimental: (), - ..Default::default() - }, - server_info: Some(ServerInfo { name: String::from("hdx-lsp"), version: Some(version.into()) }), - offset_encoding: None, - }) - }) - .handle::(move |params| -> Result, io::Error> { - let uri = params.text_document.uri; - let allocator = Bump::default(); - if let Some(source_text) = files_for_semantic_tokens.get(&uri) { - trace!("Asked for SemanticTokens"); - let result = - Parser::new(&allocator, source_text.as_str(), Features::default()).parse_entirely::(); - if let Some(stylesheet) = result.output { - trace!("Sucessfully parsed stylesheet: {:#?}", &stylesheet); - let mut highlighter = TokenHighlighter::new(); - stylesheet.accept(&mut highlighter); - let mut current_line = 0; - let mut current_start = 0; - let data = highlighter - .highlights() - .sorted_by(|a, b| Ord::cmp(&a.span(), &b.span())) - .map(|highlight| { - trace!("Highlight: {:?}", &highlight); - let span_contents = highlight.span().span_contents(source_text.as_str()); - let (line, start) = span_contents.line_and_column(); - let delta_line = line - current_line; - current_line = line; - let delta_start = if delta_line == 0 { start - current_start } else { start }; - current_start = start; - SemanticToken { - token_type: highlight.kind().bits() as u32, - token_modifiers_bitset: highlight.modifier().bits() as u32, - delta_line, - delta_start, - length: span_contents.size(), - } - }) - .collect(); - return Ok(Some(SemanticTokensResult::Tokens(SemanticTokens { result_id: None, data }))); - } else if !result.errors.is_empty() { - trace!("\n\nParse on {:?} failed. Saw error {:?}", &uri, result.errors); - } - } - Ok(None) - }) - .on::(move |params| -> Result<(), io::Error> { - let uri = params.text_document.uri; - let source_text = params.text_document.text; - files_for_open_doc.insert(uri, source_text); - Ok(()) - }) - .on::(move |params| -> Result<(), io::Error> { - let uri = params.text_document.uri; - let changes = params.content_changes; - if changes.len() == 1 && changes[0].range.is_none() { - let source_text = &changes[0].text; - files_for_change_doc.clone().insert(uri, source_text.into()); - } - Ok(()) - }) -} diff --git a/crates/hdx_lsp/src/jsonrpc/id.rs b/crates/hdx_lsp/src/jsonrpc/id.rs index ead25741..3b70a17f 100644 --- a/crates/hdx_lsp/src/jsonrpc/id.rs +++ b/crates/hdx_lsp/src/jsonrpc/id.rs @@ -16,6 +16,12 @@ pub enum Id { String(String), } +impl Default for Id { + fn default() -> Self { + Self::Number(0) + } +} + impl From<&str> for Id { fn from(value: &str) -> Self { Self::String(value.into()) diff --git a/crates/hdx_lsp/src/jsonrpc/message.rs b/crates/hdx_lsp/src/jsonrpc/message.rs index 27ebc4d7..56fe59d3 100644 --- a/crates/hdx_lsp/src/jsonrpc/message.rs +++ b/crates/hdx_lsp/src/jsonrpc/message.rs @@ -1,10 +1,12 @@ use httparse::{parse_headers, EMPTY_HEADER}; -use serde::{Deserialize, Serialize}; -use serde_json::to_string; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json::{from_value, to_string, to_value, Error, Value}; use std::io; use crate::{Notification, Request, Response}; +use super::{ErrorCode, Id}; + /// JSON RPC Message /// This represents a single message coming in or going out, that is /// compliant with the [JSON-RPC 2.0 spec](https://www.jsonrpc.org/specification). @@ -30,6 +32,49 @@ impl Message { false } } + + #[doc(hidden)] + #[inline] + pub fn is_initialize_request(&self) -> bool { + if let Message::Request(request) = self { + matches!(request.method.as_str(), "initialize") + } else { + false + } + } + + pub fn method(&self) -> Option<&str> { + match self { + Message::Request(Request { method, .. }) => Some(method), + Message::Notification(Notification { method, .. }) => Some(method), + _ => None, + } + } + + pub fn id(&self) -> Option { + match self { + Message::Request(Request { id, .. }) => Some(id.clone()), + Message::Notification(_) => None, + Message::Response(Response::Ok(id, _)) => Some(id.clone()), + Message::Response(Response::Err(id, _, _, _)) => Some(id.clone()), + } + } + + pub fn from_value(&self) -> Result { + match self { + Message::Request(Request { params, .. }) => from_value(params.clone()), + Message::Notification(Notification { params, .. }) => from_value(params.clone()), + Message::Response(Response::Ok(_, params)) => from_value(params.clone()), + Message::Response(Response::Err(_, _, _, params)) => from_value(params.clone()), + } + } + + pub fn from_result(id: Id, result: Result) -> Message { + match result { + Err(code) => Message::Response(Response::Err(id, code, "".into(), Value::Null)), + Ok(value) => Message::Response(Response::Ok(id, to_value(value).unwrap())), + } + } } impl Message { diff --git a/crates/hdx_lsp/src/lib.rs b/crates/hdx_lsp/src/lib.rs index efb2db23..e4bb5540 100644 --- a/crates/hdx_lsp/src/lib.rs +++ b/crates/hdx_lsp/src/lib.rs @@ -1,10 +1,10 @@ -mod handlers; mod jsonrpc; mod server; +mod service; #[doc(inline)] pub use jsonrpc::*; #[doc(inline)] pub use server::*; - -pub use handlers::*; +#[doc(inline)] +pub use service::*; diff --git a/crates/hdx_lsp/src/server.rs b/crates/hdx_lsp/src/server.rs index 1377137a..ac0e1749 100644 --- a/crates/hdx_lsp/src/server.rs +++ b/crates/hdx_lsp/src/server.rs @@ -7,19 +7,19 @@ //! use crossbeam_channel::{bounded, Receiver, Sender}; -use dashmap::DashMap; -use lsp_types::request::{Initialize, Request as RequestTrait}; -use serde_json::{from_value, to_value, Value}; use std::{ io, - sync::Arc, thread::{Builder, JoinHandle}, }; use tracing::{debug, trace, warn}; -use crate::{ErrorCode, TracingLayer}; +use crate::TracingLayer; -use super::{Message, Notification, Request, Response}; +use super::Message; + +mod handler; + +pub use handler::Handler; pub struct ThreadConnection { pub sender: JoinHandle>, @@ -37,142 +37,30 @@ pub struct Server { write_sender: Sender, write_receiver: Receiver, read_sender: Sender, - handler: JoinHandle>, + request_handler: JoinHandle>, read_receiver: Receiver, - request_handlers: Arc>, - notification_handlers: Arc>, -} - -struct RequestHandler { - handle: Box Response + Send + Sync>, -} - -impl RequestHandler { - fn new(handle: F) -> Self - where - T: lsp_types::request::Request, - F: Fn(T::Params) -> Result + Sized + Send + Sync + 'static, - { - Self { - handle: Box::new(move |request| { - trace!("Deserializing params ({:#?}) into value", &request.params); - let params = from_value(request.params.clone()); - if let Ok(params) = params { - trace!("Parsed params successfully, calling handler"); - let result = handle(params); - if let Ok(result) = result { - trace!("Handler returned good result, turning into generic value"); - return if let Ok(value) = to_value(result) { - trace!("Handler Responding {:?}, {:#?}", &request.id, &value); - Response::Ok(request.id.clone(), value) - } else { - trace!("Result failed to_value encode"); - Response::Err( - request.id.clone(), - ErrorCode::InternalError, - "failed to encode response".into(), - Value::Null, - ) - }; - } - } - trace!("Failed to deserialize params"); - Response::Err( - request.id.clone(), - ErrorCode::InvalidParams, - "could not parse params".into(), - Value::Null, - ) - }), - } - } -} - -struct NotificationHandler { - handle: Box Result<(), io::Error> + Send + Sync>, -} - -impl NotificationHandler { - fn new(handle: F) -> Self - where - T: lsp_types::notification::Notification, - F: Fn(T::Params) -> Result<(), io::Error> + Sized + Send + Sync + 'static, - { - Self { - handle: Box::new(move |request| { - trace!("Deserializing params ({:#?}) into value", &request.params); - let params = from_value(request.params.clone()); - if let Ok(params) = params { - trace!("Parsed params successfully, calling handler"); - let result = handle(params); - trace!("Handler was: {:?}", &result); - result - } else { - Ok(()) - } - }), - } - } } -impl Default for Server { - fn default() -> Self { +impl Server { + pub fn new(handler: T) -> Self { let (write_sender, write_receiver) = bounded::(0); let (read_sender, read_receiver) = bounded::(0); - let request_handlers: Arc> = Arc::new(DashMap::new()); - let notification_handlers: Arc> = Arc::new(DashMap::new()); - let handler_request_handlers = request_handlers.clone(); - let handler_notification_handlers = notification_handlers.clone(); let handler_receiver = read_receiver.clone(); let handler_sender = write_sender.clone(); - let mut initialized = false; - let handler = Builder::new() + let request_handler = Builder::new() .name("LspMessageHandler".into()) .spawn(move || { while let Ok(message) = handler_receiver.recv() { debug!("LspMessageHandler -> {:#?}", &message); - let exit = message.is_exit_notification(); - if exit { + if message.is_exit_notification() { break; } - if let Message::Request(request) = &message { - if let Some(handler) = handler_request_handlers.get(request.method.as_str()) { - if !initialized && request.method.as_str() != Initialize::METHOD { - debug!("Skipping method {:?} before initialization", request.method.as_str()); - continue; - } - debug!("Found RequestHandler for {:?}", request.method.as_str()); - let response = (handler.handle)(request); - debug!("RequestHandler <- {:#?}", &response); - if let Err(e) = handler_sender.send(Message::Response(response)) { - warn!("Handler failed to send response {:?}", &e); - return Err(io::Error::new(io::ErrorKind::Other, e)); - } - if !initialized && request.method.as_str() == Initialize::METHOD { - debug!("Intialized successfully"); - initialized = true; - } - } else { - warn!("Could not find handler for request {:?}", request.method.as_str()); - let response = Response::Err( - request.id.clone(), - ErrorCode::MethodNotFound, - format!("MethodNotFound: {:?}", request.method.as_str()), - Value::Null, - ); - if let Err(e) = handler_sender.send(Message::Response(response)) { - warn!("Handler failed to send response {:?}", &e); - return Err(io::Error::new(io::ErrorKind::Other, e)); - } - } - } else if let Message::Notification(notification) = &message { - if let Some(handler) = handler_notification_handlers.get(notification.method.as_str()) { - debug!("Found NotificationHandler for {:?}", notification.method.as_str()); - let response = (handler.handle)(notification); - debug!("NotificationHandler <- {:#?}", &response); - } else { - warn!("Could not find handler for notification {:?}", notification.method.as_str()); + let response = handler.handle(message); + if let Some(response) = response { + if let Err(e) = handler_sender.send(response) { + warn!("Handler failed to send response {:?}", &e); + return Err(io::Error::new(io::ErrorKind::Other, e)); } } } @@ -180,27 +68,12 @@ impl Default for Server { Ok(()) }) .expect("Failed to create Reader"); - Server { - write_sender, - write_receiver, - read_sender, - read_receiver, - request_handlers, - notification_handlers, - handler, - } - } -} - -impl Server { - pub fn new() -> Self { - Self::default() + Server { write_sender, write_receiver, read_sender, read_receiver, request_handler } } pub fn listen_stdio(&self) -> Result { let write_receiver = self.write_receiver.clone(); let writer = Builder::new().name("LspWriter".into()).spawn(move || { - trace!("LSPWRITER"); let mut stdout = io::stdout().lock(); while let Ok(message) = write_receiver.recv() { trace!("{:?}", message); @@ -210,7 +83,6 @@ impl Server { })?; let read_sender = self.read_sender.clone(); let reader = Builder::new().name("LspReader".into()).spawn(move || { - trace!("LSPREADER"); let mut stdin = io::stdin().lock(); while let Some(message) = Message::read(&mut stdin)? { if let Err(e) = read_sender.send(message) { @@ -230,43 +102,32 @@ impl Server { pub fn raw_channels(&self) -> (Sender, Receiver) { (self.read_sender.clone(), self.write_receiver.clone()) } - - pub fn handle( - self, - handler: impl Fn(T::Params) -> Result + Send + Sync + 'static, - ) -> Self { - self.request_handlers.insert(T::METHOD, RequestHandler::new::(handler)); - self - } - - pub fn on( - self, - handler: impl Fn(T::Params) -> Result<(), io::Error> + Send + Sync + 'static, - ) -> Self { - self.notification_handlers.insert(T::METHOD, NotificationHandler::new::(handler)); - self - } } #[cfg(test)] mod tests { + use crate::{ErrorCode, Request, Response}; + use super::*; use lsp_types::{ - request::{GotoDeclaration, GotoDeclarationResponse, Request as RequestTrait}, - InitializeParams, InitializeResult, + request::{GotoDeclaration, GotoDeclarationParams, Initialize, Request as RequestTrait}, + GotoDefinitionResponse, InitializeParams, InitializeResult, }; - use serde_json::json; + use serde_json::{json, to_value, Value}; use tracing::level_filters::LevelFilter; use tracing_subscriber::{fmt, layer::SubscriberExt, registry, util::SubscriberInitExt, Layer}; #[test] fn smoke_test() { let stderr_log = fmt::layer().with_writer(io::stderr).with_filter(LevelFilter::TRACE); - let server = Server::new() - .handle::(move |_| -> Result { + struct TestHandler {} + impl Handler for TestHandler { + fn initialize(&self, req: InitializeParams) -> Result { Ok(InitializeResult { ..Default::default() }) - }) - .handle::(move |_| -> Result, io::Error> { Ok(None) }); + } + } + + let server = Server::new(TestHandler {}); registry().with(stderr_log).with(server.tracer()).init(); let (sender, receiver) = server.raw_channels(); sender @@ -292,6 +153,14 @@ mod tests { }), })) .unwrap(); - assert_eq!(receiver.recv(), Ok(Message::Response(Response::Ok(1.into(), Value::Null)))); + assert_eq!( + receiver.recv(), + Ok(Message::Response(Response::Err( + 1.into(), + ErrorCode::MethodNotFound, + "MethodNotFound".into(), + Value::Null + ))) + ); } } diff --git a/crates/hdx_lsp/src/server/handler.rs b/crates/hdx_lsp/src/server/handler.rs new file mode 100644 index 00000000..9e964c50 --- /dev/null +++ b/crates/hdx_lsp/src/server/handler.rs @@ -0,0 +1,885 @@ +use crate::jsonrpc::{ErrorCode, Id, Message, Response}; +use lsp_types::{notification::*, request::*}; +use serde_json::Value; +use tracing::{debug, trace_span}; + +pub trait Handler: Sized + Send + Sync + 'static { + fn invalid_params(&self, id: Id) -> Message { + Message::Response(Response::Err(id, ErrorCode::InvalidParams, "InvalidParams".into(), Value::Null)) + } + + fn method_not_found(&self, id: Id) -> Message { + Message::Response(Response::Err(id, ErrorCode::MethodNotFound, "MethodNotFound".into(), Value::Null)) + } + + fn internal_error(&self, id: Id) -> Message { + Message::Response(Response::Err(id, ErrorCode::InternalError, "InternalError".into(), Value::Null)) + } + + fn initialized(&self) -> bool { + false + } + + fn handle(&self, message: Message) -> Option { + let span = trace_span!("Handling request", "{:#?}", message); + let _ = span.enter(); + let id = message.id().unwrap_or_default(); + debug!("LspMessageHandler -> {:#?}", &message); + if message.is_exit_notification() { + return None; + } + let initialize_request = message.is_initialize_request(); + if !self.initialized() && !initialize_request { + debug!("Skipping message {:?} before initialization", message); + return None; + } + match message.method().unwrap_or_default() { + ApplyWorkspaceEdit::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.apply_workspace_edit(p)), + )) + } + CallHierarchyIncomingCalls::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.call_hierarchy_incoming_calls(p)), + )) + } + CallHierarchyOutgoingCalls::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.call_hierarchy_outgoing_calls(p)), + )) + } + CallHierarchyPrepare::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.call_hierarchy_prepare(p)), + )) + } + CodeActionRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.code_action_request(p)), + )), + CodeActionResolveRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.code_action_resolve_request(p)), + )), + CodeLensRefresh::METHOD => Some(Message::from_result(id.clone(), self.code_lens_refresh())), + CodeLensRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.code_lens_request(p)), + )), + CodeLensResolve::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.code_lens_resolve(p)), + )), + ColorPresentationRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.color_presentation_request(p)), + )) + } + Completion::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.completion(p)), + )), + DocumentColor::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.document_color(p)), + )), + DocumentDiagnosticRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.document_diagnostic_request(p)), + )) + } + DocumentHighlightRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.document_highlight_request(p)), + )) + } + DocumentLinkRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.document_link_request(p)), + )), + DocumentLinkResolve::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.document_link_resolve(p)), + )), + DocumentSymbolRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.document_symbol_request(p)), + )), + ExecuteCommand::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.execute_command(p)), + )), + FoldingRangeRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.folding_range_request(p)), + )), + Formatting::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.formatting(p)), + )), + GotoDeclaration::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.goto_declaration(p)), + )), + GotoDefinition::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.goto_definition(p)), + )), + GotoImplementation::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.goto_implementation(p)), + )), + GotoTypeDefinition::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.goto_type_definition(p)), + )), + HoverRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.hover_request(p)), + )), + Initialize::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.initialize(p)), + )), + InlayHintRefreshRequest::METHOD => { + Some(Message::from_result(id.clone(), self.inlay_hint_refresh_request())) + } + InlayHintRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.inlay_hint_request(p)), + )), + InlayHintResolveRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.inlay_hint_resolve_request(p)), + )), + InlineValueRefreshRequest::METHOD => { + Some(Message::from_result(id.clone(), self.inline_value_refresh_request())) + } + InlineValueRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.inline_value_request(p)), + )), + LinkedEditingRange::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.linked_editing_range(p)), + )) + } + MonikerRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.moniker_request(p)), + )), + OnTypeFormatting::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.on_type_formatting(p)), + )) + } + PrepareRenameRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.prepare_rename_request(p)), + )) + } + RangeFormatting::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.range_formatting(p)), + )) + } + References::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.references(p)), + )), + RegisterCapability::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.register_capability(p)), + )), + Rename::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.rename(p)), + )), + ResolveCompletionItem::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.resolve_completion_item(p)), + )), + SelectionRangeRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.selection_range_request(p)), + )), + SemanticTokensFullDeltaRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.semantic_tokens_full_delta_request(p)), + )) + } + SemanticTokensFullRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.semantic_tokens_full_request(p)), + )) + } + SemanticTokensRangeRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.semantic_tokens_range_request(p)), + )) + } + SemanticTokensRefresh::METHOD => Some(Message::from_result(id.clone(), self.semantic_tokens_refresh())), + ShowDocument::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.show_document(p)), + )), + ShowMessageRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.show_message_request(p)), + )), + Shutdown::METHOD => Some(Message::from_result(id.clone(), self.shutdown())), + SignatureHelpRequest::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.signature_help_request(p)), + )), + TypeHierarchyPrepare::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.type_hierarchy_prepare(p)), + )) + } + TypeHierarchySubtypes::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.type_hierarchy_subtypes(p)), + )) + } + TypeHierarchySupertypes::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.type_hierarchy_supertypes(p)), + )) + } + UnregisterCapability::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.unregister_capability(p)), + )), + WillCreateFiles::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.will_create_files(p)), + )), + WillDeleteFiles::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.will_delete_files(p)), + )), + WillRenameFiles::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.will_rename_files(p)), + )), + WillSaveWaitUntil::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.will_save_wait_until(p)), + )) + } + WorkDoneProgressCreate::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.work_done_progress_create(p)), + )) + } + WorkspaceConfiguration::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.workspace_configuration(p)), + )), + WorkspaceDiagnosticRefresh::METHOD => { + Some(Message::from_result(id.clone(), self.workspace_diagnostic_refresh())) + } + WorkspaceDiagnosticRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.workspace_diagnostic_request(p)), + )) + } + WorkspaceFoldersRequest::METHOD => Some(Message::from_result(id.clone(), self.workspace_folders_request())), + WorkspaceSymbolRequest::METHOD => { + Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.workspace_symbol_request(p)), + )) + } + WorkspaceSymbolResolve::METHOD => Some(message.from_value::().map_or_else( + |_| self.invalid_params(id.clone()), + |p| Message::from_result(id.clone(), self.workspace_symbol_resolve(p)), + )), + + // Notifications + Cancel::METHOD => { + message.from_value::().map(|p| self.on_cancel(p)).ok(); + None + } + DidChangeConfiguration::METHOD => { + message + .from_value::() + .map(|p| self.on_did_change_configuration(p)) + .ok(); + None + } + DidChangeNotebookDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_change_notebook_document(p)) + .ok(); + None + } + DidChangeTextDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_change_text_document(p)) + .ok(); + None + } + DidChangeWatchedFiles::METHOD => { + message + .from_value::() + .map(|p| self.on_did_change_watched_files(p)) + .ok(); + None + } + DidChangeWorkspaceFolders::METHOD => { + message + .from_value::() + .map(|p| self.on_did_change_workspace_folders(p)) + .ok(); + None + } + DidCloseNotebookDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_close_notebook_document(p)) + .ok(); + None + } + DidCloseTextDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_close_text_document(p)) + .ok(); + None + } + DidCreateFiles::METHOD => { + message.from_value::().map(|p| self.on_did_create_files(p)).ok(); + None + } + DidDeleteFiles::METHOD => { + message.from_value::().map(|p| self.on_did_delete_files(p)).ok(); + None + } + DidOpenNotebookDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_open_notebook_document(p)) + .ok(); + None + } + DidOpenTextDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_open_text_document(p)) + .ok(); + None + } + DidRenameFiles::METHOD => { + message.from_value::().map(|p| self.on_did_rename_files(p)).ok(); + None + } + DidSaveNotebookDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_save_notebook_document(p)) + .ok(); + None + } + DidSaveTextDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_did_save_text_document(p)) + .ok(); + None + } + Initialized::METHOD => { + message.from_value::().map(|p| self.on_initialized(p)).ok(); + None + } + LogMessage::METHOD => { + message.from_value::().map(|p| self.on_log_message(p)).ok(); + None + } + LogTrace::METHOD => { + message.from_value::().map(|p| self.on_log_trace(p)).ok(); + None + } + Progress::METHOD => { + message.from_value::().map(|p| self.on_progress(p)).ok(); + None + } + PublishDiagnostics::METHOD => { + message + .from_value::() + .map(|p| self.on_publish_diagnostics(p)) + .ok(); + None + } + SetTrace::METHOD => { + message.from_value::().map(|p| self.on_set_trace(p)).ok(); + None + } + ShowMessage::METHOD => { + message.from_value::().map(|p| self.on_show_message(p)).ok(); + None + } + TelemetryEvent::METHOD => { + message + .from_value::>() + .map(|p| self.on_telemetry_event(p)) + .ok(); + None + } + WillSaveTextDocument::METHOD => { + message + .from_value::() + .map(|p| self.on_will_save_text_document(p)) + .ok(); + None + } + WorkDoneProgressCancel::METHOD => { + message + .from_value::() + .map(|p| self.on_work_done_progress_cance(p)) + .ok(); + None + } + _ => { + if let Message::Request(crate::jsonrpc::Request { id, .. }) = message { + Some(self.method_not_found(id.clone())) + } else { + None + } + } + } + } + + // Requests + + fn apply_workspace_edit( + &self, + _req: lsp_types::ApplyWorkspaceEditParams, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn call_hierarchy_incoming_calls( + &self, + _req: lsp_types::CallHierarchyIncomingCallsParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn call_hierarchy_outgoing_calls( + &self, + _req: lsp_types::CallHierarchyOutgoingCallsParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn call_hierarchy_prepare( + &self, + _req: lsp_types::CallHierarchyPrepareParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn code_action_request( + &self, + _req: lsp_types::CodeActionParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn code_action_resolve_request(&self, _req: lsp_types::CodeAction) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn code_lens_refresh(&self) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn code_lens_request( + &self, + _req: lsp_types::CodeLensParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn code_lens_resolve(&self, _req: lsp_types::CodeLens) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn color_presentation_request( + &self, + _req: lsp_types::ColorPresentationParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn completion( + &self, + _req: lsp_types::CompletionParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn document_color( + &self, + _req: lsp_types::DocumentColorParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn document_diagnostic_request( + &self, + _req: lsp_types::DocumentDiagnosticParams, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn document_highlight_request( + &self, + _req: lsp_types::DocumentHighlightParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn document_link_request( + &self, + _req: lsp_types::DocumentLinkParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn document_link_resolve(&self, _req: lsp_types::DocumentLink) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn document_symbol_request( + &self, + _req: lsp_types::DocumentSymbolParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn execute_command(&self, _req: lsp_types::ExecuteCommandParams) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn folding_range_request( + &self, + _req: lsp_types::FoldingRangeParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn formatting( + &self, + _req: lsp_types::DocumentFormattingParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn goto_declaration( + &self, + _req: lsp_types::GotoDefinitionParams, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn goto_definition( + &self, + _req: lsp_types::GotoDefinitionParams, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn goto_implementation( + &self, + _req: lsp_types::GotoDefinitionParams, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn goto_type_definition( + &self, + _req: lsp_types::GotoDefinitionParams, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn hover_request(&self, _req: lsp_types::HoverParams) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn initialize(&self, _req: lsp_types::InitializeParams) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn inlay_hint_refresh_request(&self) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn inlay_hint_request( + &self, + _req: lsp_types::InlayHintParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn inlay_hint_resolve_request(&self, _req: lsp_types::InlayHint) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn inline_value_refresh_request(&self) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn inline_value_request( + &self, + _req: lsp_types::InlineValueParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn linked_editing_range( + &self, + _req: lsp_types::LinkedEditingRangeParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn moniker_request(&self, _req: lsp_types::MonikerParams) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn on_type_formatting( + &self, + _req: lsp_types::DocumentOnTypeFormattingParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn prepare_rename_request( + &self, + _req: lsp_types::TextDocumentPositionParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn range_formatting( + &self, + _req: lsp_types::DocumentRangeFormattingParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn references(&self, _req: lsp_types::ReferenceParams) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn register_capability(&self, _req: lsp_types::RegistrationParams) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn rename(&self, _req: lsp_types::RenameParams) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn resolve_completion_item(&self, _req: lsp_types::CompletionItem) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn selection_range_request( + &self, + _req: lsp_types::SelectionRangeParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn semantic_tokens_full_delta_request( + &self, + _req: lsp_types::SemanticTokensDeltaParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn semantic_tokens_full_request( + &self, + _req: lsp_types::SemanticTokensParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn semantic_tokens_range_request( + &self, + _req: lsp_types::SemanticTokensRangeParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn semantic_tokens_refresh(&self) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn show_document(&self, _req: lsp_types::ShowDocumentParams) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn show_message_request( + &self, + _req: lsp_types::ShowMessageParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn shutdown(&self) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn signature_help_request( + &self, + _req: lsp_types::SignatureHelpParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn type_hierarchy_prepare( + &self, + _req: lsp_types::TypeHierarchyPrepareParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn type_hierarchy_subtypes( + &self, + _req: lsp_types::TypeHierarchySubtypesParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn type_hierarchy_supertypes( + &self, + _req: lsp_types::TypeHierarchySupertypesParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn unregister_capability(&self, _req: lsp_types::UnregistrationParams) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn will_create_files( + &self, + _req: lsp_types::CreateFilesParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn will_delete_files( + &self, + _req: lsp_types::DeleteFilesParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn will_rename_files( + &self, + _req: lsp_types::RenameFilesParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn will_save_wait_until( + &self, + _req: lsp_types::WillSaveTextDocumentParams, + ) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn work_done_progress_create(&self, _req: lsp_types::WorkDoneProgressCreateParams) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn workspace_configuration(&self, _req: lsp_types::ConfigurationParams) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn workspace_diagnostic_refresh(&self) -> Result<(), ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn workspace_diagnostic_request( + &self, + _req: lsp_types::WorkspaceDiagnosticParams, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + fn workspace_folders_request(&self) -> Result>, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn workspace_symbol_request( + &self, + _req: lsp_types::WorkspaceSymbolParams, + ) -> Result, ErrorCode> { + Err(ErrorCode::MethodNotFound) + } + + fn workspace_symbol_resolve( + &self, + _req: lsp_types::WorkspaceSymbol, + ) -> Result { + Err(ErrorCode::MethodNotFound) + } + + // Notifications + + fn on_cancel(&self, _req: lsp_types::CancelParams) {} + fn on_did_change_configuration(&self, _req: lsp_types::DidChangeConfigurationParams) {} + fn on_did_change_notebook_document(&self, _req: lsp_types::DidChangeNotebookDocumentParams) {} + fn on_did_change_text_document(&self, _req: lsp_types::DidChangeTextDocumentParams) {} + fn on_did_change_watched_files(&self, _req: lsp_types::DidChangeWatchedFilesParams) {} + fn on_did_change_workspace_folders(&self, _req: lsp_types::DidChangeWorkspaceFoldersParams) {} + fn on_did_close_notebook_document(&self, _req: lsp_types::DidCloseNotebookDocumentParams) {} + fn on_did_close_text_document(&self, _req: lsp_types::DidCloseTextDocumentParams) {} + fn on_did_create_files(&self, _req: lsp_types::CreateFilesParams) {} + fn on_did_delete_files(&self, _req: lsp_types::DeleteFilesParams) {} + fn on_did_open_notebook_document(&self, _req: lsp_types::DidOpenNotebookDocumentParams) {} + fn on_did_open_text_document(&self, _req: lsp_types::DidOpenTextDocumentParams) {} + fn on_did_rename_files(&self, _req: lsp_types::RenameFilesParams) {} + fn on_did_save_notebook_document(&self, _req: lsp_types::DidSaveNotebookDocumentParams) {} + fn on_did_save_text_document(&self, _req: lsp_types::DidSaveTextDocumentParams) {} + fn on_initialized(&self, _req: lsp_types::InitializedParams) {} + fn on_log_message(&self, _req: lsp_types::LogMessageParams) {} + fn on_log_trace(&self, _req: lsp_types::LogTraceParams) {} + fn on_progress(&self, _req: lsp_types::ProgressParams) {} + fn on_publish_diagnostics(&self, _req: lsp_types::PublishDiagnosticsParams) {} + fn on_set_trace(&self, _req: lsp_types::SetTraceParams) {} + fn on_show_message(&self, _req: lsp_types::ShowMessageParams) {} + fn on_telemetry_event(&self, _req: lsp_types::OneOf) {} + fn on_will_save_text_document(&self, _req: lsp_types::WillSaveTextDocumentParams) {} + fn on_work_done_progress_cance(&self, _req: lsp_types::WorkDoneProgressCancelParams) {} +} diff --git a/crates/hdx_lsp/src/service.rs b/crates/hdx_lsp/src/service.rs new file mode 100644 index 00000000..817ea898 --- /dev/null +++ b/crates/hdx_lsp/src/service.rs @@ -0,0 +1,182 @@ +use bumpalo::Bump; +use dashmap::DashMap; +use hdx_ast::css::{StyleSheet, Visitable}; +use hdx_highlight::{SemanticKind, SemanticModifier, TokenHighlighter}; +use hdx_parser::{Features, Parser}; +use itertools::Itertools; +use lsp_types::Uri; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; +use strum::VariantNames; +use tracing::trace; + +use crate::{ErrorCode, Handler}; + +pub struct LSPService { + version: String, + files: Arc>, + initialized: AtomicBool, +} + +impl LSPService { + pub fn new(version: &'static str) -> Self { + Self { version: version.into(), files: Arc::new(DashMap::new()), initialized: AtomicBool::new(false) } + } +} + +impl Handler for LSPService { + fn initialized(&self) -> bool { + self.initialized.load(Ordering::SeqCst) + } + + fn initialize(&self, req: lsp_types::InitializeParams) -> Result { + self.initialized.swap(true, Ordering::SeqCst); + Ok(lsp_types::InitializeResult { + capabilities: lsp_types::ServerCapabilities { + // position_encoding: (), + text_document_sync: Some(lsp_types::TextDocumentSyncCapability::Options( + lsp_types::TextDocumentSyncOptions { + open_close: Some(true), + change: Some(lsp_types::TextDocumentSyncKind::FULL), + will_save: Some(true), + will_save_wait_until: Some(false), + save: Some(lsp_types::TextDocumentSyncSaveOptions::Supported(false)), + }, + )), + // notebook_document_sync: (), + // selection_range_provider: (), + // hover_provider: (), + completion_provider: Some(lsp_types::CompletionOptions { + resolve_provider: None, + trigger_characters: Some(vec![".".into(), ":".into(), "@".into(), "#".into(), "-".into()]), + all_commit_characters: None, + work_done_progress_options: lsp_types::WorkDoneProgressOptions { work_done_progress: None }, + completion_item: None, + }), + // signature_help_provider: (), + // definition_provider: (), + // type_definition_provider: (), + // implementation_provider: (), + // references_provider: (), + // document_highlight_provider: (), + // document_symbol_provider: (), + // workspace_symbol_provider: (), + // code_action_provider: (), + // code_lens_provider: (), + // document_formatting_provider: (), + // document_range_formatting_provider: (), + // document_on_type_formatting_provider: (), + // rename_provider: (), + // document_link_provider: (), + // color_provider: (), + // folding_range_provider: (), + // declaration_provider: (), + // execute_command_provider: (), + // workspace: (), + // call_hierarchy_provider: (), + semantic_tokens_provider: Some(lsp_types::SemanticTokensServerCapabilities::SemanticTokensOptions( + lsp_types::SemanticTokensOptions { + work_done_progress_options: lsp_types::WorkDoneProgressOptions { + work_done_progress: Some(false), + }, + legend: lsp_types::SemanticTokensLegend { + token_types: SemanticKind::VARIANTS + .iter() + .map(|v| lsp_types::SemanticTokenType::new(v)) + .collect(), + token_modifiers: SemanticModifier::VARIANTS + .iter() + .map(|v| lsp_types::SemanticTokenModifier::new(v)) + .collect(), + }, + range: Some(false), + full: Some(lsp_types::SemanticTokensFullOptions::Delta { delta: Some(true) }), + }, + )), + // moniker_provider: (), + // linked_editing_range_provider: (), + // inline_value_provider: (), + // inlay_hint_provider: (), + // diagnostic_provider: (), + // inline_completion_provider: (), + // experimental: (), + ..Default::default() + }, + server_info: Some(lsp_types::ServerInfo { + name: String::from("hdx-lsp"), + version: Some(self.version.clone()), + }), + offset_encoding: None, + }) + } + + fn semantic_tokens_full_request( + &self, + req: lsp_types::SemanticTokensParams, + ) -> Result, ErrorCode> { + let uri = req.text_document.uri; + let allocator = Bump::default(); + if let Some(source_text) = self.files.get(&uri) { + trace!("Asked for SemanticTokens"); + let result = + Parser::new(&allocator, source_text.as_str(), Features::default()).parse_entirely::(); + if let Some(stylesheet) = result.output { + trace!("Sucessfully parsed stylesheet: {:#?}", &stylesheet); + let mut highlighter = TokenHighlighter::new(); + stylesheet.accept(&mut highlighter); + let mut current_line = 0; + let mut current_start = 0; + let data = highlighter + .highlights() + .sorted_by(|a, b| Ord::cmp(&a.span(), &b.span())) + .map(|highlight| { + let span_contents = highlight.span().span_contents(source_text.as_str()); + let (line, start) = span_contents.line_and_column(); + let delta_line = line - current_line; + current_line = line; + let delta_start = if delta_line == 0 { start - current_start } else { start }; + current_start = start; + lsp_types::SemanticToken { + token_type: highlight.kind().bits() as u32, + token_modifiers_bitset: highlight.modifier().bits() as u32, + delta_line, + delta_start, + length: span_contents.size(), + } + }) + .collect(); + return Ok(Some(lsp_types::SemanticTokensResult::Tokens(lsp_types::SemanticTokens { + result_id: None, + data, + }))); + } else if !result.errors.is_empty() { + trace!("\n\nParse on {:?} failed. Saw error {:?}", &uri, result.errors); + } + } + Err(ErrorCode::InternalError) + } + + fn completion(&self, req: lsp_types::CompletionParams) -> Result, ErrorCode> { + // let uri = req.text_document.uri; + // let position = req.text_document_position; + // let context = req.context; + Err(ErrorCode::UnknownErrorCode) + } + + fn on_did_open_text_document(&self, req: lsp_types::DidOpenTextDocumentParams) { + let uri = req.text_document.uri; + let source_text = req.text_document.text; + self.files.clone().insert(uri, source_text); + } + + fn on_did_change_text_document(&self, req: lsp_types::DidChangeTextDocumentParams) { + let uri = req.text_document.uri; + let changes = req.content_changes; + if changes.len() == 1 && changes[0].range.is_none() { + let source_text = &changes[0].text; + self.files.clone().insert(uri, source_text.into()); + } + } +}