From 239213a3db61530c073d366b50c31b3a86aad879 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Oct 2018 12:55:23 +0300 Subject: Prepare gen_lsp_server for publishing --- crates/gen_lsp_server/src/lib.rs | 85 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 8 deletions(-) (limited to 'crates/gen_lsp_server/src') diff --git a/crates/gen_lsp_server/src/lib.rs b/crates/gen_lsp_server/src/lib.rs index baca921df..645728a57 100644 --- a/crates/gen_lsp_server/src/lib.rs +++ b/crates/gen_lsp_server/src/lib.rs @@ -1,3 +1,65 @@ +//! A language server scaffold, exposing synchroneous crossbeam-channel based API. +//! 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. +//! +//! ```no_run +//! extern crate gen_lsp_server; +//! extern crate languageserver_types; +//! extern crate failure; +//! extern crate crossbeam_channel; +//! +//! use crossbeam_channel::{Sender, Receiver}; +//! use languageserver_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( +//! ServerCapabilities::default(), +//! receiver, +//! sender, +//! main_loop, +//! )?; +//! io_threads.join()?; +//! Ok(()) +//! } +//! +//! fn main_loop( +//! _params: InitializeParams, +//! receiver: &Receiver, +//! sender: &Sender, +//! ) -> 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, +//! }; +//! let req = match req.cast::() { +//! Ok((id, _params)) => { +//! let resp = RawResponse::ok::( +//! id, +//! &Some(GotoDefinitionResponse::Array(Vec::new())), +//! ); +//! sender.send(RawMessage::Response(resp)); +//! continue; +//! }, +//! Err(req) => req, +//! }; +//! // ... +//! } +//! RawMessage::Response(_resp) => (), +//! RawMessage::Notification(_not) => (), +//! } +//! } +//! Ok(()) +//! } +//! ``` + + #[macro_use] extern crate failure; #[macro_use] @@ -25,20 +87,26 @@ pub use { stdio::{stdio_transport, Threads}, }; +/// Main entry point: runs the server from initialization to shutdown. +/// To attach server to standard input/output streams, use `stdio_transport` +/// function to create corresponding `sender` and `receiver` pair. +/// +///`server` should use `handle_shutdown` function to handle the `Shutdown` +/// request. pub fn run_server( caps: ServerCapabilities, + receiver: Receiver, + sender: Sender, server: impl FnOnce( InitializeParams, - &mut Receiver, - &mut Sender, + &Receiver, + &Sender, ) -> Result<()>, - mut receiver: Receiver, - mut sender: Sender, ) -> Result<()> { info!("lsp server initializes"); - let params = initialize(&mut receiver, &mut sender, caps)?; + let params = initialize(&receiver, &sender, caps)?; info!("lsp server initialized, serving requests"); - server(params, &mut receiver, &mut sender)?; + server(params, &receiver, &sender)?; info!("lsp server waiting for exit notification"); match receiver.recv() { Some(RawMessage::Notification(n)) => { @@ -52,6 +120,7 @@ pub fn run_server( Ok(()) } +/// if `req` is `Shutdown`, respond to it and return `None`, otherwise return `Some(req)` pub fn handle_shutdown(req: RawRequest, sender: &Sender) -> Option { match req.cast::() { Ok((id, ())) => { @@ -64,8 +133,8 @@ pub fn handle_shutdown(req: RawRequest, sender: &Sender) -> Option, - sender: &mut Sender, + receiver: &Receiver, + sender: &Sender, caps: ServerCapabilities, ) -> Result { let (id, params) = match receiver.recv() { -- cgit v1.2.3