sync_ls/
msg.rs

1//! Message from and to language servers and clients.
2
3use std::{
4    fmt,
5    io::{self, BufRead, Write},
6};
7
8use serde::{Deserialize, Serialize};
9
10#[cfg(feature = "dap")]
11use crate::dap;
12#[cfg(feature = "lsp")]
13use crate::lsp;
14
15/// A request ID in the Language Server Protocol.
16#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[serde(transparent)]
18pub struct RequestId(IdRepr);
19
20impl RequestId {
21    #[cfg(feature = "dap")]
22    pub(crate) fn dap(id: RequestId) -> i64 {
23        match id.0 {
24            IdRepr::I32(it) => it as i64,
25            IdRepr::String(it) => panic!("unexpected string ID in DAP: {it}"),
26        }
27    }
28}
29
30#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31#[serde(untagged)]
32enum IdRepr {
33    I32(i32),
34    String(String),
35}
36
37impl From<i32> for RequestId {
38    fn from(id: i32) -> RequestId {
39        RequestId(IdRepr::I32(id))
40    }
41}
42
43impl From<String> for RequestId {
44    fn from(id: String) -> RequestId {
45        RequestId(IdRepr::String(id))
46    }
47}
48
49impl fmt::Display for RequestId {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        match &self.0 {
52            IdRepr::I32(it) => fmt::Display::fmt(it, f),
53            // Use debug here, to make it clear that `92` and `"92"` are
54            // different, and to reduce WTF factor if the sever uses `" "` as an
55            // ID.
56            IdRepr::String(it) => fmt::Debug::fmt(it, f),
57        }
58    }
59}
60
61/// A response from the server.
62#[derive(Debug, Serialize, Deserialize, Clone)]
63pub struct ResponseError {
64    /// The error code.
65    pub code: i32,
66    /// The error message.
67    pub message: String,
68    /// Additional data.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub data: Option<serde_json::Value>,
71}
72
73/// The error codes defined by the JSON RPC.
74#[derive(Clone, Copy, Debug)]
75#[non_exhaustive]
76pub enum ErrorCode {
77    // Defined by JSON RPC:
78    /// Invalid JSON was received by the server.
79    ParseError = -32700,
80    /// The JSON sent is not a valid Request object.
81    InvalidRequest = -32600,
82    /// The method does not exist / is not available.
83    MethodNotFound = -32601,
84    /// Invalid method parameter(s).
85    InvalidParams = -32602,
86    /// Internal JSON-RPC error.
87    InternalError = -32603,
88    /// The JSON sent is not a valid Request object.
89    ServerErrorStart = -32099,
90    /// The JSON sent is not a valid Request object.
91    ServerErrorEnd = -32000,
92
93    /// Error code indicating that a server received a notification or
94    /// request before the server has received the `initialize` request.
95    ServerNotInitialized = -32002,
96    /// Error code indicating that a server received a request that
97    /// is missing a required property.
98    UnknownErrorCode = -32001,
99
100    // Defined by the protocol:
101    /// The client has canceled a request and a server has detected
102    /// the cancel.
103    RequestCanceled = -32800,
104
105    /// The server detected that the content of a document got
106    /// modified outside normal conditions. A server should
107    /// NOT send this error code if it detects a content change
108    /// in it unprocessed messages. The result even computed
109    /// on an older state might still be useful for the client.
110    ///
111    /// If a client decides that a result is not of any use anymore
112    /// the client should cancel the request.
113    ContentModified = -32801,
114
115    /// The server cancelled the request. This error code should
116    /// only be used for requests that explicitly support being
117    /// server cancellable.
118    ///
119    /// @since 3.17.0
120    ServerCancelled = -32802,
121
122    /// A request failed but it was syntactically correct, e.g the
123    /// method name was known and the parameters were valid. The error
124    /// message should contain human readable information about why
125    /// the request failed.
126    ///
127    /// @since 3.17.0
128    RequestFailed = -32803,
129}
130
131/// The kind of the message.
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub enum MessageKind {
134    /// A message in the LSP protocol.
135    #[cfg(feature = "lsp")]
136    Lsp,
137    /// A message in the DAP protocol.
138    #[cfg(feature = "dap")]
139    Dap,
140}
141
142/// Gets the kind of the message.
143pub trait GetMessageKind {
144    /// Returns the kind of the message.
145    fn get_message_kind() -> MessageKind;
146}
147
148#[cfg(feature = "lsp")]
149impl GetMessageKind for LspMessage {
150    fn get_message_kind() -> MessageKind {
151        MessageKind::Lsp
152    }
153}
154
155/// The common message type for the LSP protocol.
156#[cfg(feature = "lsp")]
157pub type LspMessage = lsp::Message;
158/// The common message type for the DAP protocol.
159#[cfg(feature = "dap")]
160pub type DapMessage = dap::Message;
161
162/// The common message type for the language server.
163#[derive(Debug)]
164pub enum Message {
165    /// A message in the LSP protocol.
166    #[cfg(feature = "lsp")]
167    Lsp(LspMessage),
168    /// A message in the DAP protocol.
169    #[cfg(feature = "dap")]
170    Dap(DapMessage),
171}
172
173impl Message {
174    /// Reads a lsp message from the given reader.
175    #[cfg(feature = "lsp")]
176    pub fn read_lsp<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
177        let msg = lsp::Message::read(reader)?;
178        Ok(msg.map(Message::Lsp))
179    }
180
181    /// Reads a dap message from the given reader.
182    #[cfg(feature = "dap")]
183    pub fn read_dap<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
184        let msg = dap::Message::read(reader)?;
185        Ok(msg.map(Message::Dap))
186    }
187
188    /// Writes the message to the given writer.
189    pub fn write<W: std::io::Write>(self, writer: &mut W) -> std::io::Result<()> {
190        match self {
191            #[cfg(feature = "lsp")]
192            Message::Lsp(msg) => msg.write(writer),
193            #[cfg(feature = "dap")]
194            Message::Dap(msg) => msg.write(writer),
195        }
196    }
197}
198
199pub(crate) enum LspOrDapResponse {
200    #[cfg(feature = "lsp")]
201    Lsp(lsp::Response),
202    #[cfg(feature = "dap")]
203    Dap(dap::Response),
204}
205
206pub(crate) fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
207    let mut size = None;
208    let mut buf = String::new();
209    loop {
210        buf.clear();
211        if inp.read_line(&mut buf)? == 0 {
212            return Ok(None);
213        }
214        if !buf.ends_with("\r\n") {
215            return Err(invalid_data_fmt!("malformed header: {buf:?}"));
216        }
217        let buf = &buf[..buf.len() - 2];
218        if buf.is_empty() {
219            break;
220        }
221        let mut parts = buf.splitn(2, ": ");
222        let header_name = parts.next().unwrap();
223        let header_value = parts
224            .next()
225            .ok_or_else(|| invalid_data_fmt!("malformed header: {buf:?}"))?;
226        if header_name.eq_ignore_ascii_case("Content-Length") {
227            size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
228        }
229    }
230    let size: usize = size.ok_or_else(|| invalid_data_fmt!("no Content-Length"))?;
231    let mut buf = buf.into_bytes();
232    buf.resize(size, 0);
233    inp.read_exact(&mut buf)?;
234    let buf = String::from_utf8(buf).map_err(invalid_data)?;
235    log::debug!("< {}", buf);
236    Ok(Some(buf))
237}
238
239pub(crate) fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> {
240    log::debug!("> {}", msg);
241    write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
242    out.write_all(msg.as_bytes())?;
243    out.flush()?;
244    Ok(())
245}
246
247pub(crate) fn invalid_data(
248    error: impl Into<Box<dyn std::error::Error + Send + Sync>>,
249) -> io::Error {
250    io::Error::new(io::ErrorKind::InvalidData, error)
251}
252
253macro_rules! invalid_data_fmt {
254    ($($tt:tt)*) => ($crate::invalid_data(format!($($tt)*)))
255}
256pub(crate) use invalid_data_fmt;