mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-27 12:25:05 +00:00
updated gen_lsp_server examples
- updated the documentation with an example that has no errors with current compiler - added two example code to test compilation and show in use
This commit is contained in:
parent
a25e103e45
commit
cbd131acbe
4 changed files with 170 additions and 9 deletions
|
@ -14,3 +14,6 @@ failure = "0.1.4"
|
||||||
serde_json = "1.0.34"
|
serde_json = "1.0.34"
|
||||||
serde = { version = "1.0.83", features = ["derive"] }
|
serde = { version = "1.0.83", features = ["derive"] }
|
||||||
crossbeam-channel = "0.3.5"
|
crossbeam-channel = "0.3.5"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
flexi_logger = "0.11.0"
|
||||||
|
|
45
crates/gen_lsp_server/examples/01_gen_lsp_server.rs
Normal file
45
crates/gen_lsp_server/examples/01_gen_lsp_server.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use crossbeam_channel::{Sender, Receiver};
|
||||||
|
use lsp_types::{
|
||||||
|
ServerCapabilities, InitializeParams,
|
||||||
|
request::{GotoDefinition, GotoDefinitionResponse},
|
||||||
|
};
|
||||||
|
use gen_lsp_server::{run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse};
|
||||||
|
|
||||||
|
fn main() -> Result<(), failure::Error> {
|
||||||
|
let (receiver, sender, io_threads) = stdio_transport();
|
||||||
|
run_server(ServerCapabilities::default(), receiver, sender, main_loop)?;
|
||||||
|
io_threads.join()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_loop(
|
||||||
|
_params: InitializeParams,
|
||||||
|
receiver: &Receiver<RawMessage>,
|
||||||
|
sender: &Sender<RawMessage>,
|
||||||
|
) -> Result<(), failure::Error> {
|
||||||
|
for msg in receiver {
|
||||||
|
match msg {
|
||||||
|
RawMessage::Request(req) => {
|
||||||
|
let req = match handle_shutdown(req, sender) {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(req) => req,
|
||||||
|
};
|
||||||
|
match req.cast::<GotoDefinition>() {
|
||||||
|
Ok((id, _params)) => {
|
||||||
|
let resp = RawResponse::ok::<GotoDefinition>(
|
||||||
|
id,
|
||||||
|
&Some(GotoDefinitionResponse::Array(Vec::new())),
|
||||||
|
);
|
||||||
|
sender.send(RawMessage::Response(resp))?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(req) => req,
|
||||||
|
};
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
RawMessage::Response(_resp) => (),
|
||||||
|
RawMessage::Notification(_not) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
118
crates/gen_lsp_server/examples/02_gen_lsp_server_with_logging.rs
Normal file
118
crates/gen_lsp_server/examples/02_gen_lsp_server_with_logging.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
//! 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 respose. 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}
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use crossbeam_channel::{Sender, Receiver};
|
||||||
|
use lsp_types::{
|
||||||
|
ServerCapabilities, InitializeParams,
|
||||||
|
request::{GotoDefinition, GotoDefinitionResponse},
|
||||||
|
};
|
||||||
|
use log::info;
|
||||||
|
use gen_lsp_server::{
|
||||||
|
run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse, RawRequest,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), failure::Error> {
|
||||||
|
// Set up logging. Because `stdio_transport` gets a lock on stdout and stdin, we must have
|
||||||
|
// our logging only write out to stderr.
|
||||||
|
flexi_logger::Logger::with_str("info").start().unwrap();
|
||||||
|
info!("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 (receiver, sender, io_threads) = stdio_transport();
|
||||||
|
|
||||||
|
// Run the server and wait for the two threads to end (typically by trigger LSP Exit event).
|
||||||
|
run_server(ServerCapabilities::default(), receiver, sender, main_loop)?;
|
||||||
|
io_threads.join()?;
|
||||||
|
|
||||||
|
// Shut down gracefully.
|
||||||
|
info!("shutting down server");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_loop(
|
||||||
|
_params: InitializeParams,
|
||||||
|
receiver: &Receiver<RawMessage>,
|
||||||
|
sender: &Sender<RawMessage>,
|
||||||
|
) -> Result<(), failure::Error> {
|
||||||
|
info!("starting example main loop");
|
||||||
|
for msg in receiver {
|
||||||
|
info!("got msg: {:?}", msg);
|
||||||
|
match msg {
|
||||||
|
RawMessage::Request(req) => {
|
||||||
|
let req = match log_handle_shutdown(req, sender) {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(req) => req,
|
||||||
|
};
|
||||||
|
info!("got request: {:?}", req);
|
||||||
|
match req.cast::<GotoDefinition>() {
|
||||||
|
Ok((id, params)) => {
|
||||||
|
info!("got gotoDefinition request #{}: {:?}", id, params);
|
||||||
|
let resp = RawResponse::ok::<GotoDefinition>(
|
||||||
|
id,
|
||||||
|
&Some(GotoDefinitionResponse::Array(Vec::new())),
|
||||||
|
);
|
||||||
|
info!("sending gotoDefinition response: {:?}", resp);
|
||||||
|
sender.send(RawMessage::Response(resp))?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(req) => req,
|
||||||
|
};
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
RawMessage::Response(resp) => {
|
||||||
|
info!("got response: {:?}", resp);
|
||||||
|
}
|
||||||
|
RawMessage::Notification(not) => {
|
||||||
|
info!("got notification: {:?}", not);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_handle_shutdown(req: RawRequest, sender: &Sender<RawMessage>) -> Option<RawRequest> {
|
||||||
|
info!("handle_shutdown: {:?}", req);
|
||||||
|
handle_shutdown(req, sender)
|
||||||
|
}
|
|
@ -2,21 +2,16 @@
|
||||||
//! This crate handles protocol handshaking and parsing messages, while you
|
//! This crate handles protocol handshaking and parsing messages, while you
|
||||||
//! control the message dispatch loop yourself.
|
//! control the message dispatch loop yourself.
|
||||||
//!
|
//!
|
||||||
//! Run with `RUST_LOG=sync_lsp_server=debug` to see all the messages.
|
//! Run with `RUST_LOG=gen_lsp_server=debug` to see all the messages.
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! extern crate gen_lsp_server;
|
|
||||||
//! extern crate lsp_types;
|
|
||||||
//! extern crate failure;
|
|
||||||
//! extern crate crossbeam_channel;
|
|
||||||
//!
|
|
||||||
//! use crossbeam_channel::{Sender, Receiver};
|
//! use crossbeam_channel::{Sender, Receiver};
|
||||||
//! use lsp_types::{ServerCapabilities, InitializeParams, request::{GotoDefinition, GotoDefinitionResponse}};
|
//! use lsp_types::{ServerCapabilities, InitializeParams, request::{GotoDefinition, GotoDefinitionResponse}};
|
||||||
//! use gen_lsp_server::{run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse};
|
//! use gen_lsp_server::{run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse};
|
||||||
//!
|
//!
|
||||||
//! fn main() -> Result<(), failure::Error> {
|
//! fn main() -> Result<(), failure::Error> {
|
||||||
//! let (receiver, sender, io_threads) = stdio_transport();
|
//! let (receiver, sender, io_threads) = stdio_transport();
|
||||||
//! gen_lsp_server::run_server(
|
//! run_server(
|
||||||
//! ServerCapabilities::default(),
|
//! ServerCapabilities::default(),
|
||||||
//! receiver,
|
//! receiver,
|
||||||
//! sender,
|
//! sender,
|
||||||
|
@ -38,13 +33,13 @@
|
||||||
//! None => return Ok(()),
|
//! None => return Ok(()),
|
||||||
//! Some(req) => req,
|
//! Some(req) => req,
|
||||||
//! };
|
//! };
|
||||||
//! let req = match req.cast::<GotoDefinition>() {
|
//! match req.cast::<GotoDefinition>() {
|
||||||
//! Ok((id, _params)) => {
|
//! Ok((id, _params)) => {
|
||||||
//! let resp = RawResponse::ok::<GotoDefinition>(
|
//! let resp = RawResponse::ok::<GotoDefinition>(
|
||||||
//! id,
|
//! id,
|
||||||
//! &Some(GotoDefinitionResponse::Array(Vec::new())),
|
//! &Some(GotoDefinitionResponse::Array(Vec::new())),
|
||||||
//! );
|
//! );
|
||||||
//! sender.send(RawMessage::Response(resp));
|
//! sender.send(RawMessage::Response(resp))?;
|
||||||
//! continue;
|
//! continue;
|
||||||
//! },
|
//! },
|
||||||
//! Err(req) => req,
|
//! Err(req) => req,
|
||||||
|
|
Loading…
Reference in a new issue