aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/gen_lsp_server/Cargo.toml14
-rw-r--r--crates/gen_lsp_server/src/lib.rs77
-rw-r--r--crates/gen_lsp_server/src/msg.rs172
-rw-r--r--crates/gen_lsp_server/src/stdio.rs49
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]
2name = "gen_lsp_server"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5
6[dependencies]
7languageserver-types = "0.49.0"
8log = "0.4.3"
9
10failure = "0.1.2"
11serde_json = "1.0.24"
12serde = "1.0.71"
13serde_derive = "1.0.71"
14crossbeam-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]
2extern crate failure;
3#[macro_use]
4extern crate log;
5extern crate serde;
6extern crate serde_json;
7#[macro_use]
8extern crate serde_derive;
9extern crate crossbeam_channel;
10extern crate languageserver_types;
11
12mod msg;
13mod stdio;
14
15use crossbeam_channel::{Sender, Receiver};
16use languageserver_types::{
17 ServerCapabilities, InitializeResult,
18 request::{Initialize},
19 notification::{Initialized, Exit},
20};
21
22pub type Result<T> = ::std::result::Result<T, failure::Error>;
23pub use {
24 msg::{RawMessage, RawRequest, RawResponse, RawResponseError, RawNotification},
25 stdio::{stdio_transport, Threads},
26};
27
28pub type LspServer = fn(&mut Receiver<RawMessage>, &mut Sender<RawMessage>) -> Result<()>;
29
30pub 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
53fn 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 @@
1use std::io::{BufRead, Write};
2
3use serde_json::{Value, from_str, to_string, from_value, to_value};
4use serde::{Serialize, de::DeserializeOwned};
5use languageserver_types::{
6 request::Request,
7 notification::Notification,
8};
9
10use Result;
11
12#[derive(Debug, Serialize, Deserialize)]
13#[serde(untagged)]
14pub enum RawMessage {
15 Request(RawRequest),
16 Notification(RawNotification),
17 Response(RawResponse),
18}
19
20#[derive(Debug, Serialize, Deserialize)]
21pub struct RawRequest {
22 pub id: u64,
23 pub method: String,
24 pub params: Value,
25}
26
27#[derive(Debug, Serialize, Deserialize)]
28pub 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)]
40pub 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)]
48pub 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)]
62pub struct RawNotification {
63 pub method: String,
64 pub params: Value,
65}
66
67impl 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
89impl 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
104impl 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
122impl 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
135fn 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
166fn 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 @@
1use std::{
2 thread,
3 io::{
4 stdout, stdin,
5 },
6};
7
8use crossbeam_channel::{Receiver, Sender, bounded};
9
10use {RawMessage, Result};
11
12pub 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
33pub struct Threads {
34 reader: thread::JoinHandle<Result<()>>,
35 writer: thread::JoinHandle<Result<()>>,
36}
37
38impl 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}