Skip to main content

lsp_server/
msg.rs

1use std::{
2    fmt,
3    io::{self, BufRead, Write},
4};
5
6use serde::de::DeserializeOwned;
7use serde_derive::{Deserialize, Serialize};
8
9use crate::error::ExtractError;
10
11#[derive(Serialize, Deserialize, Debug, Clone)]
12#[serde(untagged)]
13pub enum Message {
14    Request(Request),
15    Response(Response),
16    Notification(Notification),
17}
18
19impl From<Request> for Message {
20    fn from(request: Request) -> Message {
21        Message::Request(request)
22    }
23}
24
25impl From<Response> for Message {
26    fn from(response: Response) -> Message {
27        Message::Response(response)
28    }
29}
30
31impl From<Notification> for Message {
32    fn from(notification: Notification) -> Message {
33        Message::Notification(notification)
34    }
35}
36
37#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
38#[serde(transparent)]
39pub struct RequestId(IdRepr);
40
41#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
42#[serde(untagged)]
43enum IdRepr {
44    I32(i32),
45    String(String),
46}
47
48impl From<i32> for RequestId {
49    fn from(id: i32) -> RequestId {
50        RequestId(IdRepr::I32(id))
51    }
52}
53
54impl From<String> for RequestId {
55    fn from(id: String) -> RequestId {
56        RequestId(IdRepr::String(id))
57    }
58}
59
60impl fmt::Display for RequestId {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        match &self.0 {
63            IdRepr::I32(it) => fmt::Display::fmt(it, f),
64            // Use debug here, to make it clear that `92` and `"92"` are
65            // different, and to reduce WTF factor if the sever uses `" "` as an
66            // ID.
67            IdRepr::String(it) => fmt::Debug::fmt(it, f),
68        }
69    }
70}
71
72#[derive(Debug, Serialize, Deserialize, Clone)]
73pub struct Request {
74    pub id: RequestId,
75    pub method: String,
76    #[serde(default = "serde_json::Value::default")]
77    #[serde(skip_serializing_if = "serde_json::Value::is_null")]
78    pub params: serde_json::Value,
79}
80
81#[derive(Debug, Serialize, Deserialize, Clone)]
82pub struct Response {
83    // JSON-RPC allows this to be null if we can't find or parse the
84    // request id. We fail deserialization in that case, so we just
85    // make this field mandatory.
86    pub id: RequestId,
87    #[serde(flatten)]
88    pub response_kind: ResponseKind,
89}
90
91#[derive(Debug, Serialize, Deserialize, Clone)]
92#[serde(untagged)]
93pub enum ResponseKind {
94    Ok { result: serde_json::Value },
95    Err { error: ResponseError },
96}
97
98#[derive(Debug, Serialize, Deserialize, Clone)]
99pub struct ResponseError {
100    pub code: i32,
101    pub message: String,
102    #[serde(skip_serializing_if = "Option::is_none", default)]
103    pub data: Option<serde_json::Value>,
104}
105
106#[derive(Clone, Copy, Debug)]
107#[non_exhaustive]
108pub enum ErrorCode {
109    // Defined by JSON RPC:
110    ParseError = -32700,
111    InvalidRequest = -32600,
112    MethodNotFound = -32601,
113    InvalidParams = -32602,
114    InternalError = -32603,
115    ServerErrorStart = -32099,
116    ServerErrorEnd = -32000,
117
118    /// Error code indicating that a server received a notification or
119    /// request before the server has received the `initialize` request.
120    ServerNotInitialized = -32002,
121    UnknownErrorCode = -32001,
122
123    // Defined by the protocol:
124    /// The client has canceled a request and a server has detected
125    /// the cancel.
126    RequestCanceled = -32800,
127
128    /// The server detected that the content of a document got
129    /// modified outside normal conditions. A server should
130    /// NOT send this error code if it detects a content change
131    /// in it unprocessed messages. The result even computed
132    /// on an older state might still be useful for the client.
133    ///
134    /// If a client decides that a result is not of any use anymore
135    /// the client should cancel the request.
136    ContentModified = -32801,
137
138    /// The server cancelled the request. This error code should
139    /// only be used for requests that explicitly support being
140    /// server cancellable.
141    ///
142    /// @since 3.17.0
143    ServerCancelled = -32802,
144
145    /// A request failed but it was syntactically correct, e.g the
146    /// method name was known and the parameters were valid. The error
147    /// message should contain human readable information about why
148    /// the request failed.
149    ///
150    /// @since 3.17.0
151    RequestFailed = -32803,
152}
153
154#[derive(Debug, Serialize, Deserialize, Clone)]
155pub struct Notification {
156    pub method: String,
157    #[serde(default = "serde_json::Value::default")]
158    #[serde(skip_serializing_if = "serde_json::Value::is_null")]
159    pub params: serde_json::Value,
160}
161
162fn invalid_data(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
163    io::Error::new(io::ErrorKind::InvalidData, error)
164}
165
166macro_rules! invalid_data {
167    ($($tt:tt)*) => (invalid_data(format!($($tt)*)))
168}
169
170impl Message {
171    pub fn read(r: &mut impl BufRead) -> io::Result<Option<Message>> {
172        Message::_read(r)
173    }
174    fn _read(r: &mut dyn BufRead) -> io::Result<Option<Message>> {
175        let text = match read_msg_text(r)? {
176            None => return Ok(None),
177            Some(text) => text,
178        };
179
180        let msg = match serde_json::from_str(&text) {
181            Ok(msg) => msg,
182            Err(e) => {
183                return Err(invalid_data!("malformed LSP payload `{e:?}`: {text:?}"));
184            }
185        };
186
187        Ok(Some(msg))
188    }
189    pub fn write(&self, w: &mut impl Write) -> io::Result<()> {
190        self._write(w)
191    }
192    fn _write(&self, w: &mut dyn Write) -> io::Result<()> {
193        #[derive(Serialize)]
194        struct JsonRpc<'a> {
195            jsonrpc: &'static str,
196            #[serde(flatten)]
197            msg: &'a Message,
198        }
199        let text = serde_json::to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?;
200        write_msg_text(w, &text)
201    }
202}
203
204impl Response {
205    pub fn new_ok<R: serde::Serialize>(id: RequestId, result: R) -> Response {
206        Response {
207            id,
208            response_kind: ResponseKind::Ok { result: serde_json::to_value(result).unwrap() },
209        }
210    }
211    pub fn new_err(id: RequestId, code: i32, message: String) -> Response {
212        let error = ResponseError { code, message, data: None };
213        Response { id, response_kind: ResponseKind::Err { error } }
214    }
215}
216
217impl Request {
218    pub fn new<P: serde::Serialize>(id: RequestId, method: String, params: P) -> Request {
219        Request { id, method, params: serde_json::to_value(params).unwrap() }
220    }
221    pub fn extract<P: DeserializeOwned>(
222        self,
223        method: &str,
224    ) -> Result<(RequestId, P), ExtractError<Request>> {
225        if self.method != method {
226            return Err(ExtractError::MethodMismatch(self));
227        }
228        match serde_json::from_value(self.params) {
229            Ok(params) => Ok((self.id, params)),
230            Err(error) => Err(ExtractError::JsonError { method: self.method, error }),
231        }
232    }
233
234    pub(crate) fn is_shutdown(&self) -> bool {
235        self.method == "shutdown"
236    }
237    pub(crate) fn is_initialize(&self) -> bool {
238        self.method == "initialize"
239    }
240}
241
242impl Notification {
243    pub fn new(method: String, params: impl serde::Serialize) -> Notification {
244        Notification { method, params: serde_json::to_value(params).unwrap() }
245    }
246    pub fn extract<P: DeserializeOwned>(
247        self,
248        method: &str,
249    ) -> Result<P, ExtractError<Notification>> {
250        if self.method != method {
251            return Err(ExtractError::MethodMismatch(self));
252        }
253        match serde_json::from_value(self.params) {
254            Ok(params) => Ok(params),
255            Err(error) => Err(ExtractError::JsonError { method: self.method, error }),
256        }
257    }
258    pub(crate) fn is_exit(&self) -> bool {
259        self.method == "exit"
260    }
261    pub(crate) fn is_initialized(&self) -> bool {
262        self.method == "initialized"
263    }
264}
265
266fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
267    let mut size = None;
268    let mut buf = String::new();
269    loop {
270        buf.clear();
271        if inp.read_line(&mut buf)? == 0 {
272            return Ok(None);
273        }
274        if !buf.ends_with("\r\n") {
275            return Err(invalid_data!("malformed header: {:?}", buf));
276        }
277        let buf = &buf[..buf.len() - 2];
278        if buf.is_empty() {
279            break;
280        }
281        let mut parts = buf.splitn(2, ": ");
282        let header_name = parts.next().unwrap();
283        let header_value =
284            parts.next().ok_or_else(|| invalid_data!("malformed header: {:?}", buf))?;
285        if header_name.eq_ignore_ascii_case("Content-Length") {
286            size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
287        }
288    }
289    let size: usize = size.ok_or_else(|| invalid_data!("no Content-Length"))?;
290    let mut buf = buf.into_bytes();
291    buf.resize(size, 0);
292    inp.read_exact(&mut buf)?;
293    let buf = String::from_utf8(buf).map_err(invalid_data)?;
294    log::debug!("< {buf}");
295    Ok(Some(buf))
296}
297
298fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> {
299    log::debug!("> {msg}");
300    write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
301    out.write_all(msg.as_bytes())?;
302    out.flush()?;
303    Ok(())
304}
305
306#[cfg(test)]
307mod tests {
308    use super::{Message, Notification, Request, RequestId};
309
310    #[test]
311    fn shutdown_with_explicit_null() {
312        let text = "{\"jsonrpc\": \"2.0\",\"id\": 3,\"method\": \"shutdown\", \"params\": null }";
313        let msg: Message = serde_json::from_str(text).unwrap();
314
315        assert!(
316            matches!(msg, Message::Request(req) if req.id == 3.into() && req.method == "shutdown")
317        );
318    }
319
320    #[test]
321    fn shutdown_with_no_params() {
322        let text = "{\"jsonrpc\": \"2.0\",\"id\": 3,\"method\": \"shutdown\"}";
323        let msg: Message = serde_json::from_str(text).unwrap();
324
325        assert!(
326            matches!(msg, Message::Request(req) if req.id == 3.into() && req.method == "shutdown")
327        );
328    }
329
330    #[test]
331    fn notification_with_explicit_null() {
332        let text = "{\"jsonrpc\": \"2.0\",\"method\": \"exit\", \"params\": null }";
333        let msg: Message = serde_json::from_str(text).unwrap();
334
335        assert!(matches!(msg, Message::Notification(not) if not.method == "exit"));
336    }
337
338    #[test]
339    fn notification_with_no_params() {
340        let text = "{\"jsonrpc\": \"2.0\",\"method\": \"exit\"}";
341        let msg: Message = serde_json::from_str(text).unwrap();
342
343        assert!(matches!(msg, Message::Notification(not) if not.method == "exit"));
344    }
345
346    #[test]
347    fn serialize_request_with_null_params() {
348        let msg = Message::Request(Request {
349            id: RequestId::from(3),
350            method: "shutdown".into(),
351            params: serde_json::Value::Null,
352        });
353        let serialized = serde_json::to_string(&msg).unwrap();
354
355        assert_eq!("{\"id\":3,\"method\":\"shutdown\"}", serialized);
356    }
357
358    #[test]
359    fn serialize_notification_with_null_params() {
360        let msg = Message::Notification(Notification {
361            method: "exit".into(),
362            params: serde_json::Value::Null,
363        });
364        let serialized = serde_json::to_string(&msg).unwrap();
365
366        assert_eq!("{\"method\":\"exit\"}", serialized);
367    }
368}