diff options
Diffstat (limited to 'crates/gen_lsp_server')
-rw-r--r-- | crates/gen_lsp_server/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/gen_lsp_server/src/lib.rs | 85 |
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 @@ | |||
2 | name = "gen_lsp_server" | 2 | name = "gen_lsp_server" |
3 | version = "0.1.0" | 3 | version = "0.1.0" |
4 | authors = ["Aleksey Kladov <[email protected]>"] | 4 | authors = ["Aleksey Kladov <[email protected]>"] |
5 | repository = "https://github.com/rust-analyzer/rust-analyzer" | ||
6 | license = "MIT OR Apache-2.0" | ||
7 | description = "Generic LSP server scaffold." | ||
5 | 8 | ||
6 | [dependencies] | 9 | [dependencies] |
7 | languageserver-types = "0.51.0" | 10 | languageserver-types = "0.51.0" |
8 | log = "0.4.3" | 11 | log = "0.4.3" |
9 | |||
10 | failure = "0.1.2" | 12 | failure = "0.1.2" |
11 | serde_json = "1.0.24" | 13 | serde_json = "1.0.24" |
12 | serde = "1.0.71" | 14 | serde = "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] |
2 | extern crate failure; | 64 | extern 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. | ||
28 | pub fn run_server( | 96 | pub 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)` | ||
55 | pub fn handle_shutdown(req: RawRequest, sender: &Sender<RawMessage>) -> Option<RawRequest> { | 124 | pub 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 | ||
66 | fn initialize( | 135 | fn 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() { |