diff options
| author | Lukas Wirth <lukastw97@gmail.com> | 2024-04-21 14:40:10 +0200 |
|---|---|---|
| committer | Lukas Wirth <lukastw97@gmail.com> | 2024-04-21 16:26:55 +0200 |
| commit | 7c3926345004c4d679c835760dbea5438a4f9d7b (patch) | |
| tree | 600a079cdebc5cdd91b5ed272f796e472401e5af /src/tools/rust-analyzer/lib/lsp-server/examples | |
| parent | 55d9a533b309119c8acd13061581b43ae8840823 (diff) | |
| download | rust-7c3926345004c4d679c835760dbea5438a4f9d7b.tar.gz rust-7c3926345004c4d679c835760dbea5438a4f9d7b.zip | |
Allow rust files to be used linkedProjects
Diffstat (limited to 'src/tools/rust-analyzer/lib/lsp-server/examples')
| -rw-r--r-- | src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs b/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs new file mode 100644 index 00000000000..6ad144b85fe --- /dev/null +++ b/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs @@ -0,0 +1,132 @@ +//! A minimal example LSP server that can only respond to the `gotoDefinition` request. To use +//! this example, execute it and then send an `initialize` request. +//! +//! ```no_run +//! Content-Length: 85 +//! +//! {"jsonrpc": "2.0", "method": "initialize", "id": 1, "params": {"capabilities": {}}} +//! ``` +//! +//! This will respond with a server response. Then send it a `initialized` notification which will +//! have no response. +//! +//! ```no_run +//! Content-Length: 59 +//! +//! {"jsonrpc": "2.0", "method": "initialized", "params": {}} +//! ``` +//! +//! Once these two are sent, then we enter the main loop of the server. The only request this +//! example can handle is `gotoDefinition`: +//! +//! ```no_run +//! Content-Length: 159 +//! +//! {"jsonrpc": "2.0", "method": "textDocument/definition", "id": 2, "params": {"textDocument": {"uri": "file://temp"}, "position": {"line": 1, "character": 1}}} +//! ``` +//! +//! To finish up without errors, send a shutdown request: +//! +//! ```no_run +//! Content-Length: 67 +//! +//! {"jsonrpc": "2.0", "method": "shutdown", "id": 3, "params": null} +//! ``` +//! +//! The server will exit the main loop and finally we send a `shutdown` notification to stop +//! the server. +//! +//! ``` +//! Content-Length: 54 +//! +//! {"jsonrpc": "2.0", "method": "exit", "params": null} +//! ``` + +#![allow(clippy::print_stderr)] + +use std::error::Error; + +use lsp_types::OneOf; +use lsp_types::{ + request::GotoDefinition, GotoDefinitionResponse, InitializeParams, ServerCapabilities, +}; + +use lsp_server::{Connection, ExtractError, Message, Request, RequestId, Response}; + +fn main() -> Result<(), Box<dyn Error + Sync + Send>> { + // Note that we must have our logging only write out to stderr. + eprintln!("starting generic LSP server"); + + // Create the transport. Includes the stdio (stdin and stdout) versions but this could + // also be implemented to use sockets or HTTP. + let (connection, io_threads) = Connection::stdio(); + + // Run the server and wait for the two threads to end (typically by trigger LSP Exit event). + let server_capabilities = serde_json::to_value(&ServerCapabilities { + definition_provider: Some(OneOf::Left(true)), + ..Default::default() + }) + .unwrap(); + 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()); + } + }; + main_loop(connection, initialization_params)?; + io_threads.join()?; + + // Shut down gracefully. + eprintln!("shutting down server"); + Ok(()) +} + +fn main_loop( + connection: Connection, + params: serde_json::Value, +) -> Result<(), Box<dyn Error + Sync + Send>> { + let _params: InitializeParams = serde_json::from_value(params).unwrap(); + eprintln!("starting example main loop"); + 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::<GotoDefinition>(req) { + Ok((id, params)) => { + eprintln!("got gotoDefinition request #{id}: {params:?}"); + let result = Some(GotoDefinitionResponse::Array(Vec::new())); + let result = serde_json::to_value(&result).unwrap(); + let resp = Response { id, result: Some(result), error: None }; + connection.sender.send(Message::Response(resp))?; + continue; + } + Err(err @ ExtractError::JsonError { .. }) => panic!("{err:?}"), + Err(ExtractError::MethodMismatch(req)) => req, + }; + // ... + } + Message::Response(resp) => { + eprintln!("got response: {resp:?}"); + } + Message::Notification(not) => { + eprintln!("got notification: {not:?}"); + } + } + } + Ok(()) +} + +fn cast<R>(req: Request) -> Result<(RequestId, R::Params), ExtractError<Request>> +where + R: lsp_types::request::Request, + R::Params: serde::de::DeserializeOwned, +{ + req.extract(R::METHOD) +} |
