aboutsummaryrefslogtreecommitdiff
path: root/crates/gen_lsp_server
diff options
context:
space:
mode:
Diffstat (limited to 'crates/gen_lsp_server')
-rw-r--r--crates/gen_lsp_server/Cargo.toml4
-rw-r--r--crates/gen_lsp_server/src/lib.rs85
2 files changed, 80 insertions, 9 deletions
diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml
index 6580ba6e4..cf5c34a88 100644
--- a/crates/gen_lsp_server/Cargo.toml
+++ b/crates/gen_lsp_server/Cargo.toml
@@ -2,11 +2,13 @@
2name = "gen_lsp_server" 2name = "gen_lsp_server"
3version = "0.1.0" 3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 4authors = ["Aleksey Kladov <[email protected]>"]
5repository = "https://github.com/rust-analyzer/rust-analyzer"
6license = "MIT OR Apache-2.0"
7description = "Generic LSP server scaffold."
5 8
6[dependencies] 9[dependencies]
7languageserver-types = "0.51.0" 10languageserver-types = "0.51.0"
8log = "0.4.3" 11log = "0.4.3"
9
10failure = "0.1.2" 12failure = "0.1.2"
11serde_json = "1.0.24" 13serde_json = "1.0.24"
12serde = "1.0.71" 14serde = "1.0.71"
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 @@
1//! A language server scaffold, exposing synchroneous crossbeam-channel based API.
2//! This crate handles protocol handshaking and parsing messages, while you
3//! control the message dispatch loop yourself.
4//!
5//! Run with `RUST_LOG=sync_lsp_server=debug` to see all the messages.
6//!
7//! ```no_run
8//! extern crate gen_lsp_server;
9//! extern crate languageserver_types;
10//! extern crate failure;
11//! extern crate crossbeam_channel;
12//!
13//! use crossbeam_channel::{Sender, Receiver};
14//! use languageserver_types::{ServerCapabilities, InitializeParams, request::{GotoDefinition, GotoDefinitionResponse}};
15//! use gen_lsp_server::{run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse};
16//!
17//! fn main() -> Result<(), failure::Error> {
18//! let (receiver, sender, io_threads) = stdio_transport();
19//! gen_lsp_server::run_server(
20//! ServerCapabilities::default(),
21//! receiver,
22//! sender,
23//! main_loop,
24//! )?;
25//! io_threads.join()?;
26//! Ok(())
27//! }
28//!
29//! fn main_loop(
30//! _params: InitializeParams,
31//! receiver: &Receiver<RawMessage>,
32//! sender: &Sender<RawMessage>,
33//! ) -> Result<(), failure::Error> {
34//! for msg in receiver {
35//! match msg {
36//! RawMessage::Request(req) => {
37//! let req = match handle_shutdown(req, sender) {
38//! None => return Ok(()),
39//! Some(req) => req,
40//! };
41//! let req = match req.cast::<GotoDefinition>() {
42//! Ok((id, _params)) => {
43//! let resp = RawResponse::ok::<GotoDefinition>(
44//! id,
45//! &Some(GotoDefinitionResponse::Array(Vec::new())),
46//! );
47//! sender.send(RawMessage::Response(resp));
48//! continue;
49//! },
50//! Err(req) => req,
51//! };
52//! // ...
53//! }
54//! RawMessage::Response(_resp) => (),
55//! RawMessage::Notification(_not) => (),
56//! }
57//! }
58//! Ok(())
59//! }
60//! ```
61
62
1#[macro_use] 63#[macro_use]
2extern crate failure; 64extern crate failure;
3#[macro_use] 65#[macro_use]
@@ -25,20 +87,26 @@ pub use {
25 stdio::{stdio_transport, Threads}, 87 stdio::{stdio_transport, Threads},
26}; 88};
27 89
90/// Main entry point: runs the server from initialization to shutdown.
91/// To attach server to standard input/output streams, use `stdio_transport`
92/// function to create corresponding `sender` and `receiver` pair.
93///
94///`server` should use `handle_shutdown` function to handle the `Shutdown`
95/// request.
28pub fn run_server( 96pub fn run_server(
29 caps: ServerCapabilities, 97 caps: ServerCapabilities,
98 receiver: Receiver<RawMessage>,
99 sender: Sender<RawMessage>,
30 server: impl FnOnce( 100 server: impl FnOnce(
31 InitializeParams, 101 InitializeParams,
32 &mut Receiver<RawMessage>, 102 &Receiver<RawMessage>,
33 &mut Sender<RawMessage>, 103 &Sender<RawMessage>,
34 ) -> Result<()>, 104 ) -> Result<()>,
35 mut receiver: Receiver<RawMessage>,
36 mut sender: Sender<RawMessage>,
37) -> Result<()> { 105) -> Result<()> {
38 info!("lsp server initializes"); 106 info!("lsp server initializes");
39 let params = initialize(&mut receiver, &mut sender, caps)?; 107 let params = initialize(&receiver, &sender, caps)?;
40 info!("lsp server initialized, serving requests"); 108 info!("lsp server initialized, serving requests");
41 server(params, &mut receiver, &mut sender)?; 109 server(params, &receiver, &sender)?;
42 info!("lsp server waiting for exit notification"); 110 info!("lsp server waiting for exit notification");
43 match receiver.recv() { 111 match receiver.recv() {
44 Some(RawMessage::Notification(n)) => { 112 Some(RawMessage::Notification(n)) => {
@@ -52,6 +120,7 @@ pub fn run_server(
52 Ok(()) 120 Ok(())
53} 121}
54 122
123/// if `req` is `Shutdown`, respond to it and return `None`, otherwise return `Some(req)`
55pub fn handle_shutdown(req: RawRequest, sender: &Sender<RawMessage>) -> Option<RawRequest> { 124pub fn handle_shutdown(req: RawRequest, sender: &Sender<RawMessage>) -> Option<RawRequest> {
56 match req.cast::<Shutdown>() { 125 match req.cast::<Shutdown>() {
57 Ok((id, ())) => { 126 Ok((id, ())) => {
@@ -64,8 +133,8 @@ pub fn handle_shutdown(req: RawRequest, sender: &Sender<RawMessage>) -> Option<R
64} 133}
65 134
66fn initialize( 135fn initialize(
67 receiver: &mut Receiver<RawMessage>, 136 receiver: &Receiver<RawMessage>,
68 sender: &mut Sender<RawMessage>, 137 sender: &Sender<RawMessage>,
69 caps: ServerCapabilities, 138 caps: ServerCapabilities,
70) -> Result<InitializeParams> { 139) -> Result<InitializeParams> {
71 let (id, params) = match receiver.recv() { 140 let (id, params) = match receiver.recv() {