diff --git a/crates/squawk_server/src/dispatch.rs b/crates/squawk_server/src/dispatch.rs index d4aee76d..76c926d6 100644 --- a/crates/squawk_server/src/dispatch.rs +++ b/crates/squawk_server/src/dispatch.rs @@ -3,7 +3,7 @@ use anyhow::Result; use log::{error, info}; use lsp_server::{Connection, Message, Response}; -use lsp_types::request::Request as LspRequest; +use lsp_types::{notification::Notification as LspNotification, request::Request as LspRequest}; use crate::system::System; @@ -76,3 +76,60 @@ impl<'a> RequestDispatcher<'a> { } } } + +pub(crate) struct NotificationDispatcher<'a> { + connection: &'a Connection, + notif: Option, + system: &'a mut dyn System, +} + +impl<'a> NotificationDispatcher<'a> { + pub(crate) fn new( + connection: &'a Connection, + notif: lsp_server::Notification, + system: &'a mut dyn System, + ) -> Self { + Self { + connection, + notif: Some(notif), + system, + } + } + + fn parse(&mut self) -> Option + where + N: LspNotification, + { + let notif = self + .notif + .take_if(|notif| notif.method.as_str() == N::METHOD)?; + + match notif.extract(N::METHOD) { + Ok(params) => Some(params), + Err(err) => { + error!("Failed to parse notification params: {err}"); + None + } + } + } + + pub(crate) fn on( + mut self, + handler: fn(&Connection, N::Params, &mut dyn System) -> Result<()>, + ) -> Result + where + N: LspNotification, + { + if let Some(params) = self.parse::() { + handler(self.connection, params, self.system)?; + } + + Ok(self) + } + + pub(crate) fn finish(self) { + if let Some(notif) = self.notif { + info!("Ignoring unhandled notification: {}", notif.method); + } + } +} diff --git a/crates/squawk_server/src/handlers/notifications.rs b/crates/squawk_server/src/handlers/notifications.rs index b262c6d5..9253afa9 100644 --- a/crates/squawk_server/src/handlers/notifications.rs +++ b/crates/squawk_server/src/handlers/notifications.rs @@ -34,10 +34,9 @@ fn publish_diagnostics( pub(crate) fn handle_did_open( connection: &Connection, - notif: lsp_server::Notification, - system: &mut impl System, + params: DidOpenTextDocumentParams, + system: &mut dyn System, ) -> Result<()> { - let params: DidOpenTextDocumentParams = serde_json::from_value(notif.params)?; let uri = params.text_document.uri; let content = params.text_document.text; let version = params.text_document.version; @@ -55,10 +54,9 @@ pub(crate) fn handle_did_open( pub(crate) fn handle_did_change( connection: &Connection, - notif: lsp_server::Notification, - system: &mut impl System, + params: DidChangeTextDocumentParams, + system: &mut dyn System, ) -> Result<()> { - let params: DidChangeTextDocumentParams = serde_json::from_value(notif.params)?; let uri = params.text_document.uri; let version = params.text_document.version; @@ -85,10 +83,9 @@ pub(crate) fn handle_did_change( pub(crate) fn handle_did_close( connection: &Connection, - notif: lsp_server::Notification, - system: &mut impl System, + params: DidCloseTextDocumentParams, + system: &mut dyn System, ) -> Result<()> { - let params: DidCloseTextDocumentParams = serde_json::from_value(notif.params)?; let uri = params.text_document.uri; system.remove(&uri); diff --git a/crates/squawk_server/src/server.rs b/crates/squawk_server/src/server.rs index 68062d6d..350163b3 100644 --- a/crates/squawk_server/src/server.rs +++ b/crates/squawk_server/src/server.rs @@ -6,16 +6,14 @@ use lsp_types::{ FoldingRangeProviderCapability, HoverProviderCapability, InitializeParams, OneOf, SelectionRangeProviderCapability, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind, WorkDoneProgressOptions, - notification::{ - DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument, Notification as _, - }, + notification::{DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument}, request::{ CodeActionRequest, Completion, DocumentSymbolRequest, FoldingRangeRequest, GotoDefinition, HoverRequest, InlayHintRequest, References, SelectionRangeRequest, }, }; -use crate::dispatch::RequestDispatcher; +use crate::dispatch::{NotificationDispatcher, RequestDispatcher}; use crate::handlers::{ SyntaxTreeRequest, TokensRequest, handle_code_action, handle_completion, handle_did_change, handle_did_close, handle_did_open, handle_document_symbol, handle_folding_range, @@ -114,20 +112,12 @@ fn main_loop(connection: Connection, params: serde_json::Value) -> Result<()> { } Message::Notification(notif) => { info!("Received notification: method={}", notif.method); - match notif.method.as_ref() { - DidOpenTextDocument::METHOD => { - handle_did_open(&connection, notif, &mut system)?; - } - DidChangeTextDocument::METHOD => { - handle_did_change(&connection, notif, &mut system)?; - } - DidCloseTextDocument::METHOD => { - handle_did_close(&connection, notif, &mut system)?; - } - _ => { - info!("Ignoring unhandled notification: {}", notif.method); - } - } + + NotificationDispatcher::new(&connection, notif, &mut system) + .on::(handle_did_open)? + .on::(handle_did_change)? + .on::(handle_did_close)? + .finish(); } } }