diff options
Diffstat (limited to 'crates/gen_lsp_server')
-rw-r--r-- | crates/gen_lsp_server/Cargo.toml | 14 | ||||
-rw-r--r-- | crates/gen_lsp_server/src/lib.rs | 77 | ||||
-rw-r--r-- | crates/gen_lsp_server/src/msg.rs | 172 | ||||
-rw-r--r-- | crates/gen_lsp_server/src/stdio.rs | 49 |
4 files changed, 312 insertions, 0 deletions
diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml new file mode 100644 index 000000000..b31884802 --- /dev/null +++ b/crates/gen_lsp_server/Cargo.toml | |||
@@ -0,0 +1,14 @@ | |||
1 | [package] | ||
2 | name = "gen_lsp_server" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Aleksey Kladov <[email protected]>"] | ||
5 | |||
6 | [dependencies] | ||
7 | languageserver-types = "0.49.0" | ||
8 | log = "0.4.3" | ||
9 | |||
10 | failure = "0.1.2" | ||
11 | serde_json = "1.0.24" | ||
12 | serde = "1.0.71" | ||
13 | serde_derive = "1.0.71" | ||
14 | crossbeam-channel = "0.2.4" | ||
diff --git a/crates/gen_lsp_server/src/lib.rs b/crates/gen_lsp_server/src/lib.rs new file mode 100644 index 000000000..a31e90f35 --- /dev/null +++ b/crates/gen_lsp_server/src/lib.rs | |||
@@ -0,0 +1,77 @@ | |||
1 | #[macro_use] | ||
2 | extern crate failure; | ||
3 | #[macro_use] | ||
4 | extern crate log; | ||
5 | extern crate serde; | ||
6 | extern crate serde_json; | ||
7 | #[macro_use] | ||
8 | extern crate serde_derive; | ||
9 | extern crate crossbeam_channel; | ||
10 | extern crate languageserver_types; | ||
11 | |||
12 | mod msg; | ||
13 | mod stdio; | ||
14 | |||
15 | use crossbeam_channel::{Sender, Receiver}; | ||
16 | use languageserver_types::{ | ||
17 | ServerCapabilities, InitializeResult, | ||
18 | request::{Initialize}, | ||
19 | notification::{Initialized, Exit}, | ||
20 | }; | ||
21 | |||
22 | pub type Result<T> = ::std::result::Result<T, failure::Error>; | ||
23 | pub use { | ||
24 | msg::{RawMessage, RawRequest, RawResponse, RawResponseError, RawNotification}, | ||
25 | stdio::{stdio_transport, Threads}, | ||
26 | }; | ||
27 | |||
28 | pub type LspServer = fn(&mut Receiver<RawMessage>, &mut Sender<RawMessage>) -> Result<()>; | ||
29 | |||
30 | pub fn run_server( | ||
31 | caps: ServerCapabilities, | ||
32 | server: LspServer, | ||
33 | mut receiver: Receiver<RawMessage>, | ||
34 | mut sender: Sender<RawMessage>, | ||
35 | ) -> Result<()> { | ||
36 | info!("lsp server initializes"); | ||
37 | initialize(&mut receiver, &mut sender, caps)?; | ||
38 | info!("lsp server initialized, serving requests"); | ||
39 | server(&mut receiver, &mut sender)?; | ||
40 | info!("lsp server waiting for exit notification"); | ||
41 | match receiver.recv() { | ||
42 | Some(RawMessage::Notification(n)) => { | ||
43 | n.cast::<Exit>().map_err(|n| format_err!( | ||
44 | "unexpected notification during shutdown: {:?}", n | ||
45 | ))? | ||
46 | } | ||
47 | m => bail!("unexpected message during shutdown: {:?}", m) | ||
48 | } | ||
49 | info!("lsp server shutdown complete"); | ||
50 | Ok(()) | ||
51 | } | ||
52 | |||
53 | fn initialize( | ||
54 | receiver: &mut Receiver<RawMessage>, | ||
55 | sender: &mut Sender<RawMessage>, | ||
56 | caps: ServerCapabilities, | ||
57 | ) -> Result<()> { | ||
58 | let id = match receiver.recv() { | ||
59 | Some(RawMessage::Request(req)) => match req.cast::<Initialize>() { | ||
60 | Err(req) => bail!("expected initialize request, got {:?}", req), | ||
61 | Ok(req) => req.0, | ||
62 | } | ||
63 | msg => | ||
64 | bail!("expected initialize request, got {:?}", msg), | ||
65 | }; | ||
66 | let resp = RawResponse::ok(id, InitializeResult { capabilities: caps }); | ||
67 | sender.send(RawMessage::Response(resp)); | ||
68 | match receiver.recv() { | ||
69 | Some(RawMessage::Notification(n)) => { | ||
70 | n.cast::<Initialized>().map_err(|_| format_err!( | ||
71 | "expected initialized notification" | ||
72 | ))?; | ||
73 | } | ||
74 | _ => bail!("expected initialized notification"), | ||
75 | } | ||
76 | Ok(()) | ||
77 | } | ||
diff --git a/crates/gen_lsp_server/src/msg.rs b/crates/gen_lsp_server/src/msg.rs new file mode 100644 index 000000000..9426e98ec --- /dev/null +++ b/crates/gen_lsp_server/src/msg.rs | |||
@@ -0,0 +1,172 @@ | |||
1 | use std::io::{BufRead, Write}; | ||
2 | |||
3 | use serde_json::{Value, from_str, to_string, from_value, to_value}; | ||
4 | use serde::{Serialize, de::DeserializeOwned}; | ||
5 | use languageserver_types::{ | ||
6 | request::Request, | ||
7 | notification::Notification, | ||
8 | }; | ||
9 | |||
10 | use Result; | ||
11 | |||
12 | #[derive(Debug, Serialize, Deserialize)] | ||
13 | #[serde(untagged)] | ||
14 | pub enum RawMessage { | ||
15 | Request(RawRequest), | ||
16 | Notification(RawNotification), | ||
17 | Response(RawResponse), | ||
18 | } | ||
19 | |||
20 | #[derive(Debug, Serialize, Deserialize)] | ||
21 | pub struct RawRequest { | ||
22 | pub id: u64, | ||
23 | pub method: String, | ||
24 | pub params: Value, | ||
25 | } | ||
26 | |||
27 | #[derive(Debug, Serialize, Deserialize)] | ||
28 | pub struct RawResponse { | ||
29 | // JSON RPC allows this to be null if it was impossible | ||
30 | // to decode the request's id. Ignore this special case | ||
31 | // and just die horribly. | ||
32 | pub id: u64, | ||
33 | #[serde(skip_serializing_if = "Option::is_none")] | ||
34 | pub result: Option<Value>, | ||
35 | #[serde(skip_serializing_if = "Option::is_none")] | ||
36 | pub error: Option<RawResponseError>, | ||
37 | } | ||
38 | |||
39 | #[derive(Debug, Serialize, Deserialize)] | ||
40 | pub struct RawResponseError { | ||
41 | pub code: i32, | ||
42 | pub message: String, | ||
43 | #[serde(skip_serializing_if = "Option::is_none")] | ||
44 | pub data: Option<Value>, | ||
45 | } | ||
46 | |||
47 | #[allow(unused)] | ||
48 | pub enum ErrorCode { | ||
49 | ParseError = -32700, | ||
50 | InvalidRequest = -32600, | ||
51 | MethodNotFound = -32601, | ||
52 | InvalidParams = -32602, | ||
53 | InternalError = -32603, | ||
54 | ServerErrorStart = -32099, | ||
55 | ServerErrorEnd = -32000, | ||
56 | ServerNotInitialized = -32002, | ||
57 | UnknownErrorCode = -32001, | ||
58 | RequestCancelled = -32800, | ||
59 | } | ||
60 | |||
61 | #[derive(Debug, Serialize, Deserialize)] | ||
62 | pub struct RawNotification { | ||
63 | pub method: String, | ||
64 | pub params: Value, | ||
65 | } | ||
66 | |||
67 | impl RawMessage { | ||
68 | pub fn read(r: &mut impl BufRead) -> Result<Option<RawMessage>> { | ||
69 | let text = match read_msg_text(r)? { | ||
70 | None => return Ok(None), | ||
71 | Some(text) => text, | ||
72 | }; | ||
73 | let msg = from_str(&text)?; | ||
74 | Ok(Some(msg)) | ||
75 | } | ||
76 | pub fn write(self, w: &mut impl Write) -> Result<()> { | ||
77 | #[derive(Serialize)] | ||
78 | struct JsonRpc { | ||
79 | jsonrpc: &'static str, | ||
80 | #[serde(flatten)] | ||
81 | msg: RawMessage, | ||
82 | } | ||
83 | let text = to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?; | ||
84 | write_msg_text(w, &text)?; | ||
85 | Ok(()) | ||
86 | } | ||
87 | } | ||
88 | |||
89 | impl RawRequest { | ||
90 | pub fn cast<R>(self) -> ::std::result::Result<(u64, R::Params), RawRequest> | ||
91 | where | ||
92 | R: Request, | ||
93 | R::Params: DeserializeOwned, | ||
94 | { | ||
95 | if self.method != R::METHOD { | ||
96 | return Err(self); | ||
97 | } | ||
98 | let id = self.id; | ||
99 | let params: R::Params = from_value(self.params).unwrap(); | ||
100 | Ok((id, params)) | ||
101 | } | ||
102 | } | ||
103 | |||
104 | impl RawResponse { | ||
105 | pub fn ok(id: u64, result: impl Serialize) -> RawResponse { | ||
106 | RawResponse { | ||
107 | id, | ||
108 | result: Some(to_value(&result).unwrap()), | ||
109 | error: None, | ||
110 | } | ||
111 | } | ||
112 | pub fn err(id: u64, code: i32, message: String) -> RawResponse { | ||
113 | let error = RawResponseError { code, message, data: None }; | ||
114 | RawResponse { | ||
115 | id, | ||
116 | result: None, | ||
117 | error: Some(error), | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | impl RawNotification { | ||
123 | pub fn cast<N>(self) -> ::std::result::Result<N::Params, RawNotification> | ||
124 | where | ||
125 | N: Notification, | ||
126 | N::Params: DeserializeOwned, | ||
127 | { | ||
128 | if self.method != N::METHOD { | ||
129 | return Err(self); | ||
130 | } | ||
131 | Ok(from_value(self.params).unwrap()) | ||
132 | } | ||
133 | } | ||
134 | |||
135 | fn read_msg_text(inp: &mut impl BufRead) -> Result<Option<String>> { | ||
136 | let mut size = None; | ||
137 | let mut buf = String::new(); | ||
138 | loop { | ||
139 | buf.clear(); | ||
140 | if inp.read_line(&mut buf)? == 0 { | ||
141 | return Ok(None); | ||
142 | } | ||
143 | if !buf.ends_with("\r\n") { | ||
144 | bail!("malformed header: {:?}", buf); | ||
145 | } | ||
146 | let buf = &buf[..buf.len() - 2]; | ||
147 | if buf.is_empty() { | ||
148 | break; | ||
149 | } | ||
150 | let mut parts = buf.splitn(2, ": "); | ||
151 | let header_name = parts.next().unwrap(); | ||
152 | let header_value = parts.next().ok_or_else(|| format_err!("malformed header: {:?}", buf))?; | ||
153 | if header_name == "Content-Length" { | ||
154 | size = Some(header_value.parse::<usize>()?); | ||
155 | } | ||
156 | } | ||
157 | let size = size.ok_or_else(|| format_err!("no Content-Length"))?; | ||
158 | let mut buf = buf.into_bytes(); | ||
159 | buf.resize(size, 0); | ||
160 | inp.read_exact(&mut buf)?; | ||
161 | let buf = String::from_utf8(buf)?; | ||
162 | debug!("< {}", buf); | ||
163 | Ok(Some(buf)) | ||
164 | } | ||
165 | |||
166 | fn write_msg_text(out: &mut impl Write, msg: &str) -> Result<()> { | ||
167 | debug!("> {}", msg); | ||
168 | write!(out, "Content-Length: {}\r\n\r\n", msg.len())?; | ||
169 | out.write_all(msg.as_bytes())?; | ||
170 | out.flush()?; | ||
171 | Ok(()) | ||
172 | } | ||
diff --git a/crates/gen_lsp_server/src/stdio.rs b/crates/gen_lsp_server/src/stdio.rs new file mode 100644 index 000000000..81397bb2a --- /dev/null +++ b/crates/gen_lsp_server/src/stdio.rs | |||
@@ -0,0 +1,49 @@ | |||
1 | use std::{ | ||
2 | thread, | ||
3 | io::{ | ||
4 | stdout, stdin, | ||
5 | }, | ||
6 | }; | ||
7 | |||
8 | use crossbeam_channel::{Receiver, Sender, bounded}; | ||
9 | |||
10 | use {RawMessage, Result}; | ||
11 | |||
12 | pub fn stdio_transport() -> (Receiver<RawMessage>, Sender<RawMessage>, Threads) { | ||
13 | let (writer_sender, mut writer_receiver) = bounded::<RawMessage>(16); | ||
14 | let writer = thread::spawn(move || { | ||
15 | let stdout = stdout(); | ||
16 | let mut stdout = stdout.lock(); | ||
17 | writer_receiver.try_for_each(|it| it.write(&mut stdout))?; | ||
18 | Ok(()) | ||
19 | }); | ||
20 | let (reader_sender, reader_receiver) = bounded::<RawMessage>(16); | ||
21 | let reader = thread::spawn(move || { | ||
22 | let stdin = stdin(); | ||
23 | let mut stdin = stdin.lock(); | ||
24 | while let Some(msg) = RawMessage::read(&mut stdin)? { | ||
25 | reader_sender.send(msg); | ||
26 | } | ||
27 | Ok(()) | ||
28 | }); | ||
29 | let threads = Threads { reader, writer }; | ||
30 | (reader_receiver, writer_sender, threads) | ||
31 | } | ||
32 | |||
33 | pub struct Threads { | ||
34 | reader: thread::JoinHandle<Result<()>>, | ||
35 | writer: thread::JoinHandle<Result<()>>, | ||
36 | } | ||
37 | |||
38 | impl Threads { | ||
39 | pub fn join(self) -> Result<()> { | ||
40 | match self.reader.join() { | ||
41 | Ok(r) => r?, | ||
42 | Err(_) => bail!("reader panicked"), | ||
43 | } | ||
44 | match self.writer.join() { | ||
45 | Ok(r) => r, | ||
46 | Err(_) => bail!("writer panicked"), | ||
47 | } | ||
48 | } | ||
49 | } | ||