diff options
Diffstat (limited to 'crates/gen_lsp_server/examples')
-rw-r--r-- | crates/gen_lsp_server/examples/01_gen_lsp_server.rs | 45 | ||||
-rw-r--r-- | crates/gen_lsp_server/examples/02_gen_lsp_server_with_logging.rs | 118 |
2 files changed, 163 insertions, 0 deletions
diff --git a/crates/gen_lsp_server/examples/01_gen_lsp_server.rs b/crates/gen_lsp_server/examples/01_gen_lsp_server.rs new file mode 100644 index 000000000..60c581075 --- /dev/null +++ b/crates/gen_lsp_server/examples/01_gen_lsp_server.rs | |||
@@ -0,0 +1,45 @@ | |||
1 | use crossbeam_channel::{Sender, Receiver}; | ||
2 | use lsp_types::{ | ||
3 | ServerCapabilities, InitializeParams, | ||
4 | request::{GotoDefinition, GotoDefinitionResponse}, | ||
5 | }; | ||
6 | use gen_lsp_server::{run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse}; | ||
7 | |||
8 | fn main() -> Result<(), failure::Error> { | ||
9 | let (receiver, sender, io_threads) = stdio_transport(); | ||
10 | run_server(ServerCapabilities::default(), receiver, sender, main_loop)?; | ||
11 | io_threads.join()?; | ||
12 | Ok(()) | ||
13 | } | ||
14 | |||
15 | fn main_loop( | ||
16 | _params: InitializeParams, | ||
17 | receiver: &Receiver<RawMessage>, | ||
18 | sender: &Sender<RawMessage>, | ||
19 | ) -> Result<(), failure::Error> { | ||
20 | for msg in receiver { | ||
21 | match msg { | ||
22 | RawMessage::Request(req) => { | ||
23 | let req = match handle_shutdown(req, sender) { | ||
24 | None => return Ok(()), | ||
25 | Some(req) => req, | ||
26 | }; | ||
27 | match req.cast::<GotoDefinition>() { | ||
28 | Ok((id, _params)) => { | ||
29 | let resp = RawResponse::ok::<GotoDefinition>( | ||
30 | id, | ||
31 | &Some(GotoDefinitionResponse::Array(Vec::new())), | ||
32 | ); | ||
33 | sender.send(RawMessage::Response(resp))?; | ||
34 | continue; | ||
35 | } | ||
36 | Err(req) => req, | ||
37 | }; | ||
38 | // ... | ||
39 | } | ||
40 | RawMessage::Response(_resp) => (), | ||
41 | RawMessage::Notification(_not) => (), | ||
42 | } | ||
43 | } | ||
44 | Ok(()) | ||
45 | } | ||
diff --git a/crates/gen_lsp_server/examples/02_gen_lsp_server_with_logging.rs b/crates/gen_lsp_server/examples/02_gen_lsp_server_with_logging.rs new file mode 100644 index 000000000..27e4f1cbc --- /dev/null +++ b/crates/gen_lsp_server/examples/02_gen_lsp_server_with_logging.rs | |||
@@ -0,0 +1,118 @@ | |||
1 | //! A minimal example LSP server that can only respond to the `gotoDefinition` request. To use | ||
2 | //! this example, execute it and then send an `initialize` request. | ||
3 | //! | ||
4 | //! ```no_run | ||
5 | //! Content-Length: 85 | ||
6 | //! | ||
7 | //! {"jsonrpc": "2.0", "method": "initialize", "id": 1, "params": {"capabilities": {}}} | ||
8 | //! ``` | ||
9 | //! | ||
10 | //! This will respond with a server respose. Then send it a `initialized` notification which will | ||
11 | //! have no response. | ||
12 | //! | ||
13 | //! ```no_run | ||
14 | //! Content-Length: 59 | ||
15 | //! | ||
16 | //! {"jsonrpc": "2.0", "method": "initialized", "params": {}} | ||
17 | //! ``` | ||
18 | //! | ||
19 | //! Once these two are sent, then we enter the main loop of the server. The only request this | ||
20 | //! example can handle is `gotoDefinition`: | ||
21 | //! | ||
22 | //! ```no_run | ||
23 | //! Content-Length: 159 | ||
24 | //! | ||
25 | //! {"jsonrpc": "2.0", "method": "textDocument/definition", "id": 2, "params": {"textDocument": {"uri": "file://temp"}, "position": {"line": 1, "character": 1}}} | ||
26 | //! ``` | ||
27 | //! | ||
28 | //! To finish up without errors, send a shutdown request: | ||
29 | //! | ||
30 | //! ```no_run | ||
31 | //! Content-Length: 67 | ||
32 | //! | ||
33 | //! {"jsonrpc": "2.0", "method": "shutdown", "id": 3, "params": null} | ||
34 | //! ``` | ||
35 | //! | ||
36 | //! The server will exit the main loop and finally we send a `shutdown` notification to stop | ||
37 | //! the server. | ||
38 | //! | ||
39 | //! ``` | ||
40 | //! Content-Length: 54 | ||
41 | //! | ||
42 | //! {"jsonrpc": "2.0", "method": "exit", "params": null} | ||
43 | //! ``` | ||
44 | |||
45 | use crossbeam_channel::{Sender, Receiver}; | ||
46 | use lsp_types::{ | ||
47 | ServerCapabilities, InitializeParams, | ||
48 | request::{GotoDefinition, GotoDefinitionResponse}, | ||
49 | }; | ||
50 | use log::info; | ||
51 | use gen_lsp_server::{ | ||
52 | run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse, RawRequest, | ||
53 | }; | ||
54 | |||
55 | fn main() -> Result<(), failure::Error> { | ||
56 | // Set up logging. Because `stdio_transport` gets a lock on stdout and stdin, we must have | ||
57 | // our logging only write out to stderr. | ||
58 | flexi_logger::Logger::with_str("info").start().unwrap(); | ||
59 | info!("starting generic LSP server"); | ||
60 | |||
61 | // Create the transport. Includes the stdio (stdin and stdout) versions but this could | ||
62 | // also be implemented to use sockets or HTTP. | ||
63 | let (receiver, sender, io_threads) = stdio_transport(); | ||
64 | |||
65 | // Run the server and wait for the two threads to end (typically by trigger LSP Exit event). | ||
66 | run_server(ServerCapabilities::default(), receiver, sender, main_loop)?; | ||
67 | io_threads.join()?; | ||
68 | |||
69 | // Shut down gracefully. | ||
70 | info!("shutting down server"); | ||
71 | Ok(()) | ||
72 | } | ||
73 | |||
74 | fn main_loop( | ||
75 | _params: InitializeParams, | ||
76 | receiver: &Receiver<RawMessage>, | ||
77 | sender: &Sender<RawMessage>, | ||
78 | ) -> Result<(), failure::Error> { | ||
79 | info!("starting example main loop"); | ||
80 | for msg in receiver { | ||
81 | info!("got msg: {:?}", msg); | ||
82 | match msg { | ||
83 | RawMessage::Request(req) => { | ||
84 | let req = match log_handle_shutdown(req, sender) { | ||
85 | None => return Ok(()), | ||
86 | Some(req) => req, | ||
87 | }; | ||
88 | info!("got request: {:?}", req); | ||
89 | match req.cast::<GotoDefinition>() { | ||
90 | Ok((id, params)) => { | ||
91 | info!("got gotoDefinition request #{}: {:?}", id, params); | ||
92 | let resp = RawResponse::ok::<GotoDefinition>( | ||
93 | id, | ||
94 | &Some(GotoDefinitionResponse::Array(Vec::new())), | ||
95 | ); | ||
96 | info!("sending gotoDefinition response: {:?}", resp); | ||
97 | sender.send(RawMessage::Response(resp))?; | ||
98 | continue; | ||
99 | } | ||
100 | Err(req) => req, | ||
101 | }; | ||
102 | // ... | ||
103 | } | ||
104 | RawMessage::Response(resp) => { | ||
105 | info!("got response: {:?}", resp); | ||
106 | } | ||
107 | RawMessage::Notification(not) => { | ||
108 | info!("got notification: {:?}", not); | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | Ok(()) | ||
113 | } | ||
114 | |||
115 | pub fn log_handle_shutdown(req: RawRequest, sender: &Sender<RawMessage>) -> Option<RawRequest> { | ||
116 | info!("handle_shutdown: {:?}", req); | ||
117 | handle_shutdown(req, sender) | ||
118 | } | ||