aboutsummaryrefslogtreecommitdiff
path: root/crates/gen_lsp_server/examples
diff options
context:
space:
mode:
Diffstat (limited to 'crates/gen_lsp_server/examples')
-rw-r--r--crates/gen_lsp_server/examples/01_gen_lsp_server.rs45
-rw-r--r--crates/gen_lsp_server/examples/02_gen_lsp_server_with_logging.rs118
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 @@
1use crossbeam_channel::{Sender, Receiver};
2use lsp_types::{
3 ServerCapabilities, InitializeParams,
4 request::{GotoDefinition, GotoDefinitionResponse},
5};
6use gen_lsp_server::{run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse};
7
8fn 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
15fn 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
45use crossbeam_channel::{Sender, Receiver};
46use lsp_types::{
47 ServerCapabilities, InitializeParams,
48 request::{GotoDefinition, GotoDefinitionResponse},
49};
50use log::info;
51use gen_lsp_server::{
52 run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse, RawRequest,
53};
54
55fn 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
74fn 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
115pub fn log_handle_shutdown(req: RawRequest, sender: &Sender<RawMessage>) -> Option<RawRequest> {
116 info!("handle_shutdown: {:?}", req);
117 handle_shutdown(req, sender)
118}