From b39376cd8921cd557e4f8443f505ec06732bb91e Mon Sep 17 00:00:00 2001 From: Shashi Shankar Date: Sun, 6 Jul 2025 17:38:27 +0200 Subject: [PATCH 1/2] Add richer LSP server example (#20017) --- crates/rust-analyzer/Cargo.toml | 4 ++ .../rust_analyzer_lsp_example/main.rs | 69 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index b301a7189b3c..18acd70249de 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -106,3 +106,7 @@ in-rust-tree = [ [lints] workspace = true + +[[example]] +name = "rust_analyzer_lsp_example" +path = "examples/rust_analyzer_lsp_example/main.rs" diff --git a/crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs b/crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs new file mode 100644 index 000000000000..0f85528be28d --- /dev/null +++ b/crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs @@ -0,0 +1,69 @@ +//! rust-analyzer LSP example +//! +//! A minimal Language Server Protocol server demonstrating how to embed +//! `rust-analyzer` as a library. To run it: +//! ```bash +//! cargo run --example rust_analyzer_lsp_example +// +#![allow(clippy::print_stderr)] + +use anyhow::Result; +use lsp_server::{Connection, Message}; +use lsp_types::{ + CompletionParams, DidChangeTextDocumentParams, DocumentFormattingParams, OneOf, + ServerCapabilities, TextDocumentSyncKind, TextDocumentSyncOptions, + request::{Completion, Formatting, Request as LspRequest}, +}; +use serde_json::json; + +fn main() -> Result<()> { + // Set up a JSON-RPC connection over stdio + let (connection, io_threads) = Connection::stdio(); + + // Perform the initialize handshake and advertise capabilities + let (init_id, _init_params) = connection.initialize_start()?; + let capabilities = ServerCapabilities { + text_document_sync: Some( + TextDocumentSyncOptions { + change: Some(TextDocumentSyncKind::FULL), + ..Default::default() + } + .into(), + ), + completion_provider: Some(Default::default()), + document_formatting_provider: Some(OneOf::Left(true)), + ..Default::default() + }; + connection.initialize_finish(init_id, json!({ "capabilities": capabilities }))?; + + // Enter the main message loop + for message in connection.receiver.iter() { + match message { + Message::Notification(notification) + if notification.method == "textDocument/didChange" => + { + let params: DidChangeTextDocumentParams = + serde_json::from_value(notification.params).unwrap(); + eprintln!("Document changed: {}", params.text_document.uri); + } + Message::Request(request) if request.method == Completion::METHOD => { + let _: CompletionParams = serde_json::from_value(request.params).unwrap(); + let response = lsp_server::Response::new_ok( + request.id, + json!({ "isIncomplete": false, "items": [] }), + ); + connection.sender.send(Message::Response(response)).unwrap(); + } + Message::Request(request) if request.method == Formatting::METHOD => { + let _: DocumentFormattingParams = serde_json::from_value(request.params).unwrap(); + let response = lsp_server::Response::new_ok(request.id, json!([])); + connection.sender.send(Message::Response(response)).unwrap(); + } + Message::Request(request) if connection.handle_shutdown(&request)? => break, + _ => {} // ignore all other messages + } + } + + io_threads.join().unwrap(); + Ok(()) +} From 379a36967ea6577228d0dfa45b5b9f6b29fa72be Mon Sep 17 00:00:00 2001 From: Shashi Shankar Date: Tue, 8 Jul 2025 20:09:09 +0200 Subject: [PATCH 2/2] lsp-server: relocate and rename example; add anyhow as dev-dependency - Move the completion/formatting example from crates/rust-analyzer/examples/ to crates/lsp-server/examples/ - Rename file to completion_and_formatting.rs to match snake_case and clearly indicate both features - Add anyhow = "1.0" under [dev-dependencies] in crates/lsp-server/Cargo.toml so the example compiles without error --- crates/rust-analyzer/Cargo.toml | 4 ---- lib/lsp-server/Cargo.toml | 4 ++++ .../lsp-server/examples/completion_and_formatting.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs => lib/lsp-server/examples/completion_and_formatting.rs (97%) diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 18acd70249de..b301a7189b3c 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -106,7 +106,3 @@ in-rust-tree = [ [lints] workspace = true - -[[example]] -name = "rust_analyzer_lsp_example" -path = "examples/rust_analyzer_lsp_example/main.rs" diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml index 35a5a4d82b24..9924adab9dbc 100644 --- a/lib/lsp-server/Cargo.toml +++ b/lib/lsp-server/Cargo.toml @@ -19,3 +19,7 @@ ctrlc = "3.4.7" [lints] workspace = true + +[[example]] +name = "completion_and_formatting" +path = "examples/completion_and_formatting.rs" diff --git a/crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs b/lib/lsp-server/examples/completion_and_formatting.rs similarity index 97% rename from crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs rename to lib/lsp-server/examples/completion_and_formatting.rs index 0f85528be28d..90dde56b469b 100644 --- a/crates/rust-analyzer/examples/rust_analyzer_lsp_example/main.rs +++ b/lib/lsp-server/examples/completion_and_formatting.rs @@ -7,7 +7,7 @@ // #![allow(clippy::print_stderr)] -use anyhow::Result; +type Result = std::result::Result>; use lsp_server::{Connection, Message}; use lsp_types::{ CompletionParams, DidChangeTextDocumentParams, DocumentFormattingParams, OneOf,