From b35dd287f28b4952ff5ab3677b2e022e32e3c5c2 Mon Sep 17 00:00:00 2001 From: DavidLee18 Date: Thu, 31 Oct 2024 03:14:01 +0900 Subject: [PATCH] ditch tower_lsp in favor of lsp_server --- Cargo.toml | 9 +- src/main.rs | 250 ++++++++++++++++++++---------------------- src/norminette_msg.rs | 2 +- 3 files changed, 119 insertions(+), 142 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5610248..63cb472 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,14 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] +lsp-server = "0.7.7" lsp-types = "0.97.0" nom = "7.1.3" serde_json = "1.0.128" -tokio = { version = "1.40.0", features = [ - "rt-multi-thread", - "macros", - "io-std", -] } -tokio-macros = "2.4.0" -tower-lsp = "0.20.0" tracing-subscriber = "0.3.18" +serde = "1.0.210" diff --git a/src/main.rs b/src/main.rs index 37bfcbd..a44c42c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,140 +1,32 @@ pub mod norminette_msg; pub mod parser; +use lsp_server::{Connection, ExtractError, Message, Request, RequestId, Response}; +use lsp_types::request::DocumentDiagnosticRequest; +use lsp_types::{ + Diagnostic, DiagnosticOptions, DiagnosticServerCapabilities, InitializeParams, + LogMessageParams, MessageType, PublishDiagnosticsParams, ServerCapabilities, + WorkDoneProgressOptions, +}; +use parser::parse_norminette; +use std::error::Error; use std::io; use std::path::Path; -use parser::parse_norminette; -use serde_json::Value; -use tower_lsp::jsonrpc::{self, Result}; -use tower_lsp::lsp_types::*; -use tower_lsp::{Client, LanguageServer, LspService, Server}; - -#[derive(Debug)] -struct Backend { - client: Client, - // norminette_options: Arc> -} - -#[tower_lsp::async_trait] -impl LanguageServer for Backend { - async fn initialize(&self, _: InitializeParams) -> Result { - Ok(InitializeResult { - server_info: None, - capabilities: ServerCapabilities { - diagnostic_provider: Some(DiagnosticServerCapabilities::Options( - DiagnosticOptions::default(), - )), - workspace: Some(WorkspaceServerCapabilities { - workspace_folders: Some(WorkspaceFoldersServerCapabilities { - supported: Some(true), - change_notifications: None, - }), - file_operations: None, - }), - ..Default::default() - }, - }) - } - - async fn initialized(&self, _: InitializedParams) { - self.client - .log_message(MessageType::INFO, "initialized!") - .await; - } - - async fn shutdown(&self) -> Result<()> { - Ok(()) - } - - async fn did_open(&self, p: DidOpenTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "file opened!") - .await; - match read_norminette(&Path::new(p.text_document.uri.path())) { - Ok(diags) => { - self.client - .publish_diagnostics(p.text_document.uri, diags, None) - .await; - } - Err(e) => { - self.client.log_message(MessageType::ERROR, format!("norminette read of {} failed: {}", p.text_document.uri, e)).await; - } - } - } - - async fn did_change(&self, p: DidChangeTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "file changed!") - .await; - match read_norminette(&Path::new(p.text_document.uri.path())) { - Ok(diags) => { - self.client - .publish_diagnostics(p.text_document.uri, diags, None) - .await; - } - Err(e) => { - self.client.log_message(MessageType::ERROR, format!("norminette read of {} failed: {}", p.text_document.uri, e)).await; - } - } - - } - - async fn did_save(&self, p: DidSaveTextDocumentParams) { - self.client - .log_message(MessageType::INFO, format!("file saved: {:?}", p.text)) - .await; - match read_norminette(&Path::new(p.text_document.uri.path())) { - Ok(diags) => { - self.client - .publish_diagnostics(p.text_document.uri, diags, None) - .await; - }, - Err(e) => { - self.client.log_message(MessageType::ERROR, format!("norminette read of {} failed: {}", p.text_document.uri, e)).await; - } - } - } - - async fn did_close(&self, _: DidCloseTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "file closed!") - .await; - } - - async fn completion(&self, _: CompletionParams) -> Result> { - Err(jsonrpc::Error::method_not_found()) - } - - async fn did_change_configuration(&self, _: DidChangeConfigurationParams) { - self.client - .log_message(MessageType::INFO, "configuration changed!") - .await; - } - - async fn did_change_workspace_folders(&self, _: DidChangeWorkspaceFoldersParams) { - self.client - .log_message(MessageType::INFO, "workspace folders changed!") - .await; - } - - async fn did_change_watched_files(&self, _: DidChangeWatchedFilesParams) { - self.client - .log_message(MessageType::INFO, "watched files have changed!") - .await; - } - - async fn execute_command(&self, _: ExecuteCommandParams) -> Result> { - Err(jsonrpc::Error::method_not_found()) - } -} - -pub fn read_norminette(path: &Path) -> io::Result> { +fn read_norminette(path: &Path) -> io::Result> { let output = std::process::Command::new("norminette") .arg(path) .output()?; - let (_, diags) = parse_norminette(&String::from_utf8(output.stdout).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?) - .map_err(|err| io::Error::new(io::ErrorKind::Other, format!("norminette parse error: {:?}", err)))?; + let (_, diags) = parse_norminette( + &String::from_utf8(output.stdout) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, + ) + .map_err(|err| { + io::Error::new( + io::ErrorKind::Other, + format!("norminette parse error: {:?}", err), + ) + })?; Ok(diags .into_iter() @@ -144,12 +36,102 @@ pub fn read_norminette(path: &Path) -> io::Result> { .collect()) } -#[tokio::main] -async fn main() { - tracing_subscriber::fmt().init(); +fn main() -> Result<(), Box> { + eprintln!("starting norminette LSP server"); + + let (connection, io_threads) = Connection::stdio(); + + let server_capabilities = serde_json::to_value(&ServerCapabilities { + diagnostic_provider: Some(DiagnosticServerCapabilities::Options(DiagnosticOptions { + identifier: None, + inter_file_dependencies: false, + workspace_diagnostics: false, + work_done_progress_options: WorkDoneProgressOptions::default(), + })), + ..Default::default() + })?; + let initialization_params = match connection.initialize(server_capabilities) { + Ok(it) => it, + Err(e) => { + if e.channel_is_disconnected() { + io_threads.join()?; + } + return Err(e.into()); + } + }; + eprintln!("initialized connection!"); + main_loop(connection, initialization_params)?; + io_threads.join()?; + eprintln!("shutting down server"); + Ok(()) +} - let (stdin, stdout) = (tokio::io::stdin(), tokio::io::stdout()); +fn main_loop( + connection: Connection, + params: serde_json::Value, +) -> Result<(), Box> { + let _params: InitializeParams = serde_json::from_value(params)?; + + for msg in &connection.receiver { + eprintln!("got msg: {msg:?}"); + match msg { + Message::Request(req) => { + if connection.handle_shutdown(&req)? { + return Ok(()); + } + eprintln!("got request: {req:?}"); + match cast::(req) { + Ok((id, params)) => { + eprintln!("got doc diagnostic request #{id} params: {params:?}"); + match read_norminette(&Path::new(params.text_document.uri.path().as_str())) + { + Ok(diags) => { + connection.sender.send(Message::Response(Response { + id, + result: Some(serde_json::to_value( + &PublishDiagnosticsParams { + uri: params.text_document.uri, + diagnostics: diags, + version: None, + }, + )?), + error: None, + }))?; + } + Err(e) => { + connection.sender.send(Message::Response(Response { + id, + result: Some(serde_json::to_value(&LogMessageParams { + typ: MessageType::ERROR, + message: format!( + "norminette read of {} failed: {}", + params.text_document.uri.path(), + e + ), + })?), + error: None, + }))?; + } + } + } + Err(e) => return Err(Box::new(e)), + }; + } + Message::Response(resp) => { + eprintln!("got response: {resp:?}"); + } + Message::Notification(not) => { + eprintln!("got notification: {not:?}"); + } + } + } + Ok(()) +} - let (service, socket) = LspService::new(|client| Backend { client }); - Server::new(stdin, stdout, socket).serve(service).await; +fn cast(req: Request) -> Result<(RequestId, R::Params), ExtractError> +where + R: lsp_types::request::Request, + R::Params: serde::de::DeserializeOwned, +{ + req.extract(R::METHOD) } diff --git a/src/norminette_msg.rs b/src/norminette_msg.rs index cce310c..78f1076 100644 --- a/src/norminette_msg.rs +++ b/src/norminette_msg.rs @@ -1,6 +1,6 @@ use std::u32; -use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range}; +use lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range}; #[derive(Debug)] pub enum NorminetteMsg {