diff --git a/Cargo.lock b/Cargo.lock index 0bea37d..67fc844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -792,7 +792,7 @@ dependencies = [ [[package]] name = "protols" -version = "0.12.5" +version = "0.12.6" dependencies = [ "async-lsp", "basic-toml", diff --git a/Cargo.toml b/Cargo.toml index 624d1ca..8630f72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "protols" description = "Language server for proto3 files" -version = "0.12.5" +version = "0.12.6" edition = "2024" license = "MIT" homepage = "https://github.com/coder3101/protols" @@ -12,8 +12,8 @@ keywords = ["lsp", "proto"] exclude = ["assets/*", "sample/*"] [dependencies] -async-lsp = { version = "0.2.0", features = ["tokio"] } -futures = "0.3.30" +async-lsp = { version = "0.2.2", features = ["tokio"] } +futures = "0.3.31" tokio = { version = "1.38.0", features = ["time", "full"] } tokio-util = { version = "0.7.11", features = ["compat"] } tower = "0.5.2" diff --git a/src/lsp.rs b/src/lsp.rs index afd5de5..37f01ab 100644 --- a/src/lsp.rs +++ b/src/lsp.rs @@ -4,34 +4,30 @@ use tracing::{error, info}; use async_lsp::lsp_types::{ CompletionItem, CompletionItemKind, CompletionOptions, CompletionParams, CompletionResponse, - CreateFilesParams, DeleteFilesParams, DidChangeConfigurationParams, - DidChangeTextDocumentParams, DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, - DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentFormattingParams, - DocumentRangeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, Documentation, - FileOperationFilter, FileOperationPattern, FileOperationPatternKind, - FileOperationRegistrationOptions, GotoDefinitionParams, GotoDefinitionResponse, Hover, - HoverContents, HoverParams, HoverProviderCapability, InitializeParams, InitializeResult, - Location, MarkupContent, MarkupKind, OneOf, PrepareRenameResponse, ReferenceParams, - RenameFilesParams, RenameOptions, RenameParams, ServerCapabilities, ServerInfo, - TextDocumentPositionParams, TextDocumentSyncCapability, TextDocumentSyncKind, TextEdit, Url, - WorkspaceEdit, WorkspaceFileOperationsServerCapabilities, WorkspaceFoldersServerCapabilities, + CreateFilesParams, DeleteFilesParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams, + DidSaveTextDocumentParams, DocumentFormattingParams, DocumentRangeFormattingParams, + DocumentSymbolParams, DocumentSymbolResponse, Documentation, FileOperationFilter, + FileOperationPattern, FileOperationPatternKind, FileOperationRegistrationOptions, + GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverContents, HoverParams, + HoverProviderCapability, InitializeParams, InitializeResult, Location, MarkupContent, + MarkupKind, OneOf, PrepareRenameResponse, ReferenceParams, RenameFilesParams, RenameOptions, + RenameParams, ServerCapabilities, ServerInfo, TextDocumentPositionParams, + TextDocumentSyncCapability, TextDocumentSyncKind, TextEdit, Url, WorkspaceEdit, + WorkspaceFileOperationsServerCapabilities, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities, }; -use async_lsp::{LanguageClient, LanguageServer, ResponseError}; +use async_lsp::{LanguageClient, ResponseError}; use futures::future::BoxFuture; use crate::docs; use crate::formatter::ProtoFormatter; use crate::server::ProtoLanguageServer; -impl LanguageServer for ProtoLanguageServer { - type Error = ResponseError; - type NotifyResult = ControlFlow>; - - fn initialize( +impl ProtoLanguageServer { + pub(super) fn initialize( &mut self, params: InitializeParams, - ) -> BoxFuture<'static, Result> { + ) -> BoxFuture<'static, Result> { let (cname, version) = params .client_info .as_ref() @@ -122,10 +118,10 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(response) }) } - fn hover( + pub(super) fn hover( &mut self, param: HoverParams, - ) -> BoxFuture<'static, Result, Self::Error>> { + ) -> BoxFuture<'static, Result, ResponseError>> { let uri = param.text_document_position_params.text_document.uri; let pos = param.text_document_position_params.position; @@ -154,10 +150,10 @@ impl LanguageServer for ProtoLanguageServer { }) } - fn completion( + pub(super) fn completion( &mut self, params: CompletionParams, - ) -> BoxFuture<'static, Result, Self::Error>> { + ) -> BoxFuture<'static, Result, ResponseError>> { let uri = params.text_document_position.text_document.uri; // All keywords in the language @@ -203,10 +199,10 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(Some(CompletionResponse::Array(completions))) }) } - fn prepare_rename( + pub(super) fn prepare_rename( &mut self, params: TextDocumentPositionParams, - ) -> BoxFuture<'static, Result, Self::Error>> { + ) -> BoxFuture<'static, Result, ResponseError>> { let uri = params.text_document.uri; let pos = params.position; @@ -220,10 +216,10 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(response) }) } - fn rename( + pub(super) fn rename( &mut self, params: RenameParams, - ) -> BoxFuture<'static, Result, Self::Error>> { + ) -> BoxFuture<'static, Result, ResponseError>> { let uri = params.text_document_position.text_document.uri; let pos = params.text_document_position.position; @@ -271,7 +267,7 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(response) }) } - fn references( + pub(super) fn references( &mut self, param: ReferenceParams, ) -> BoxFuture<'static, Result>, ResponseError>> { @@ -318,7 +314,7 @@ impl LanguageServer for ProtoLanguageServer { }) } - fn definition( + pub(super) fn definition( &mut self, param: GotoDefinitionParams, ) -> BoxFuture<'static, Result, ResponseError>> { @@ -353,10 +349,10 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(response) }) } - fn document_symbol( + pub(super) fn document_symbol( &mut self, params: DocumentSymbolParams, - ) -> BoxFuture<'static, Result, Self::Error>> { + ) -> BoxFuture<'static, Result, ResponseError>> { let uri = params.text_document.uri; let Some(tree) = self.state.get_tree(&uri) else { @@ -371,10 +367,10 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(Some(response)) }) } - fn formatting( + pub(super) fn formatting( &mut self, params: DocumentFormattingParams, - ) -> BoxFuture<'static, Result>, Self::Error>> { + ) -> BoxFuture<'static, Result>, ResponseError>> { let uri = params.text_document.uri; let content = self.state.get_content(&uri); @@ -386,10 +382,10 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(response) }) } - fn range_formatting( + pub(super) fn range_formatting( &mut self, params: DocumentRangeFormattingParams, - ) -> BoxFuture<'static, Result>, Self::Error>> { + ) -> BoxFuture<'static, Result>, ResponseError>> { let uri = params.text_document.uri; let content = self.state.get_content(&uri); @@ -401,7 +397,10 @@ impl LanguageServer for ProtoLanguageServer { Box::pin(async move { Ok(response) }) } - fn did_save(&mut self, params: DidSaveTextDocumentParams) -> Self::NotifyResult { + pub(super) fn did_save( + &mut self, + params: DidSaveTextDocumentParams, + ) -> ControlFlow> { let uri = params.text_document.uri; let content = self.state.get_content(&uri); @@ -424,11 +423,10 @@ impl LanguageServer for ProtoLanguageServer { ControlFlow::Continue(()) } - fn did_close(&mut self, _params: DidCloseTextDocumentParams) -> Self::NotifyResult { - ControlFlow::Continue(()) - } - - fn did_open(&mut self, params: DidOpenTextDocumentParams) -> Self::NotifyResult { + pub(super) fn did_open( + &mut self, + params: DidOpenTextDocumentParams, + ) -> ControlFlow> { let uri = params.text_document.uri; let content = params.text_document.text; @@ -451,7 +449,10 @@ impl LanguageServer for ProtoLanguageServer { ControlFlow::Continue(()) } - fn did_change(&mut self, params: DidChangeTextDocumentParams) -> Self::NotifyResult { + pub(super) fn did_change( + &mut self, + params: DidChangeTextDocumentParams, + ) -> ControlFlow> { let uri = params.text_document.uri; let content = params.content_changes[0].text.clone(); @@ -474,7 +475,10 @@ impl LanguageServer for ProtoLanguageServer { ControlFlow::Continue(()) } - fn did_create_files(&mut self, params: CreateFilesParams) -> Self::NotifyResult { + pub(super) fn did_create_files( + &mut self, + params: CreateFilesParams, + ) -> ControlFlow> { for file in params.files { if let Ok(uri) = Url::from_file_path(&file.uri) { // Safety: The uri is always a file type @@ -488,7 +492,10 @@ impl LanguageServer for ProtoLanguageServer { ControlFlow::Continue(()) } - fn did_rename_files(&mut self, params: RenameFilesParams) -> Self::NotifyResult { + pub(super) fn did_rename_files( + &mut self, + params: RenameFilesParams, + ) -> ControlFlow> { for file in params.files { let Ok(new_uri) = Url::from_file_path(&file.new_uri) else { error!(uri = file.new_uri, "failed to parse uri"); @@ -505,7 +512,10 @@ impl LanguageServer for ProtoLanguageServer { ControlFlow::Continue(()) } - fn did_delete_files(&mut self, params: DeleteFilesParams) -> Self::NotifyResult { + pub(super) fn did_delete_files( + &mut self, + params: DeleteFilesParams, + ) -> ControlFlow> { for file in params.files { if let Ok(uri) = Url::from_file_path(&file.uri) { self.state.delete_file(&uri); @@ -515,17 +525,4 @@ impl LanguageServer for ProtoLanguageServer { } ControlFlow::Continue(()) } - - // Required because of: https://github.com/coder3101/protols/issues/32 - fn did_change_configuration(&mut self, _: DidChangeConfigurationParams) -> Self::NotifyResult { - ControlFlow::Continue(()) - } - - // Required because when jumping to outside the workspace; this is triggered - fn did_change_workspace_folders( - &mut self, - _: DidChangeWorkspaceFoldersParams, - ) -> Self::NotifyResult { - ControlFlow::Continue(()) - } } diff --git a/src/main.rs b/src/main.rs index 55f45e1..348f17f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,7 +37,7 @@ async fn main() { let cli = Cli::parse(); let dir = std::env::temp_dir(); - eprintln!("Rolling file based logging at directory: {dir:?}"); + eprintln!("file logging at directory: {dir:?}"); let file_appender = tracing_appender::rolling::daily(dir.clone(), "protols.log"); let file_appender = tracing_appender::non_blocking(file_appender); @@ -48,9 +48,10 @@ async fn main() { .with_writer(file_appender.0) .init(); + tracing::info!("server version: {}", env!("CARGO_PKG_VERSION")); let (server, _) = async_lsp::MainLoop::new_server(|client| { tracing::info!("Using CLI options: {:?}", cli); - let server = ProtoLanguageServer::new_router( + let router = ProtoLanguageServer::new_router( client.clone(), cli.include_paths .map(|ic| ic.into_iter().map(std::path::PathBuf::from).collect()) @@ -76,7 +77,7 @@ async fn main() { .layer(CatchUnwindLayer::default()) .layer(ConcurrencyLayer::default()) .layer(ClientProcessMonitorLayer::new(client.clone())) - .service(server) + .service(router) }); // Prefer truly asynchronous piped stdin/stdout without blocking tasks. diff --git a/src/server.rs b/src/server.rs index d75007a..fcb45af 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,6 +1,16 @@ use async_lsp::{ ClientSocket, LanguageClient, - lsp_types::{NumberOrString, ProgressParams, ProgressParamsValue}, + lsp_types::{ + NumberOrString, ProgressParams, ProgressParamsValue, + notification::{ + DidChangeTextDocument, DidCreateFiles, DidDeleteFiles, DidOpenTextDocument, + DidRenameFiles, DidSaveTextDocument, + }, + request::{ + Completion, DocumentSymbolRequest, Formatting, GotoDefinition, HoverRequest, + Initialize, PrepareRenameRequest, RangeFormatting, References, Rename, + }, + }, router::Router, }; use std::{ @@ -22,19 +32,45 @@ pub struct ProtoLanguageServer { impl ProtoLanguageServer { pub fn new_router(client: ClientSocket, cli_include_paths: Vec) -> Router { - let mut router = Router::from_language_server(Self { + let mut router = Router::new(Self { client, counter: 0, state: ProtoLanguageState::new(), configs: WorkspaceProtoConfigs::new(cli_include_paths), }); - router.event(Self::on_tick); - router - } - fn on_tick(&mut self, _: TickEvent) -> ControlFlow> { - self.counter += 1; - ControlFlow::Continue(()) + router.event::(|st, _| { + st.counter += 1; + ControlFlow::Continue(()) + }); + + // Ignore any unknown notification. + router.unhandled_notification(|_, notif| { + tracing::info!(notif.method, "ignored unknown notification"); + ControlFlow::Continue(()) + }); + + // Handling request + router.request::(|st, params| st.initialize(params)); + router.request::(|st, params| st.hover(params)); + router.request::(|st, params| st.completion(params)); + router.request::(|st, params| st.prepare_rename(params)); + router.request::(|st, params| st.rename(params)); + router.request::(|st, params| st.references(params)); + router.request::(|st, params| st.definition(params)); + router.request::(|st, params| st.document_symbol(params)); + router.request::(|st, params| st.formatting(params)); + router.request::(|st, params| st.range_formatting(params)); + + // Handling notification + router.notification::(|st, params| st.did_save(params)); + router.notification::(|st, params| st.did_open(params)); + router.notification::(|st, params| st.did_change(params)); + router.notification::(|st, params| st.did_create_files(params)); + router.notification::(|st, params| st.did_rename_files(params)); + router.notification::(|st, params| st.did_delete_files(params)); + + router } pub fn with_report_progress(&self, token: NumberOrString) -> Sender {