Merge #1313
1313: Update `gen_lsp_server` examples r=matklad a=dmoonfire - updated the documentation with an example that has no errors with current compiler - added two example code to test compilation and show in use - one example is the bare bones version in documentation - the other example is the same but with logging statements to show flow Co-authored-by: Dylan Moonfire <dylan.moonfire@ryan.com>
This commit is contained in:
commit
078c0e26c3
@ -14,3 +14,6 @@ failure = "0.1.4"
|
||||
serde_json = "1.0.34"
|
||||
serde = { version = "1.0.83", features = ["derive"] }
|
||||
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
|
||||
//! 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
|
||||
//! extern crate gen_lsp_server;
|
||||
//! extern crate lsp_types;
|
||||
//! extern crate failure;
|
||||
//! extern crate crossbeam_channel;
|
||||
//!
|
||||
//! 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();
|
||||
//! gen_lsp_server::run_server(
|
||||
//! run_server(
|
||||
//! ServerCapabilities::default(),
|
||||
//! receiver,
|
||||
//! sender,
|
||||
@ -38,13 +33,13 @@
|
||||
//! None => return Ok(()),
|
||||
//! Some(req) => req,
|
||||
//! };
|
||||
//! let req = match req.cast::<GotoDefinition>() {
|
||||
//! match req.cast::<GotoDefinition>() {
|
||||
//! Ok((id, _params)) => {
|
||||
//! let resp = RawResponse::ok::<GotoDefinition>(
|
||||
//! id,
|
||||
//! &Some(GotoDefinitionResponse::Array(Vec::new())),
|
||||
//! );
|
||||
//! sender.send(RawMessage::Response(resp));
|
||||
//! sender.send(RawMessage::Response(resp))?;
|
||||
//! continue;
|
||||
//! },
|
||||
//! Err(req) => req,
|
||||
|
Loading…
Reference in New Issue
Block a user