sync_ls/
msg.rs

1//! Message from and to language servers and clients.
2
3use std::fmt;
4#[cfg(any(feature = "lsp", feature = "dap"))]
5use std::io::{self, BufRead, Write};
6
7use serde::{Deserialize, Serialize};
8
9#[cfg(feature = "dap")]
10use crate::dap;
11#[cfg(feature = "lsp")]
12use crate::lsp;
13
14/// A request ID in the Language Server Protocol.
15#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[serde(transparent)]
17pub struct RequestId(IdRepr);
18
19impl RequestId {
20    /// Converts the request ID back to the original dap type.
21    #[cfg(feature = "dap")]
22    pub 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 common message type for the LSP protocol.
132#[cfg(feature = "lsp")]
133pub type LspMessage = lsp::Message;
134/// The common message type for the DAP protocol.
135#[cfg(feature = "dap")]
136pub type DapMessage = dap::Message;
137
138/// The common message type for the language server.
139#[derive(Debug)]
140pub enum Message {
141    /// A message in the LSP protocol.
142    #[cfg(feature = "lsp")]
143    Lsp(LspMessage),
144    /// A message in the DAP protocol.
145    #[cfg(feature = "dap")]
146    Dap(DapMessage),
147}
148
149impl Message {
150    /// Reads a lsp message from the given reader.
151    #[cfg(feature = "lsp")]
152    pub fn read_lsp<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
153        let msg = lsp::Message::read(reader)?;
154        Ok(msg.map(Message::Lsp))
155    }
156
157    /// Reads a dap message from the given reader.
158    #[cfg(feature = "dap")]
159    pub fn read_dap<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
160        let msg = dap::Message::read(reader)?;
161        Ok(msg.map(Message::Dap))
162    }
163
164    /// Writes the message to the given writer.
165    pub fn write<W: std::io::Write>(self, _writer: &mut W) -> std::io::Result<()> {
166        match self {
167            #[cfg(feature = "lsp")]
168            Message::Lsp(msg) => msg.write(_writer),
169            #[cfg(feature = "dap")]
170            Message::Dap(msg) => msg.write(_writer),
171        }
172    }
173}
174
175/// The kind of the message.
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub enum MessageKind {
178    /// A message in the LSP protocol.
179    #[cfg(feature = "lsp")]
180    Lsp,
181    /// A message in the DAP protocol.
182    #[cfg(feature = "dap")]
183    Dap,
184}
185
186/// Gets the kind of the message.
187pub trait GetMessageKind {
188    /// Returns the kind of the message.
189    const MESSAGE_KIND: MessageKind;
190}
191
192#[cfg(feature = "lsp")]
193impl GetMessageKind for LspMessage {
194    const MESSAGE_KIND: MessageKind = MessageKind::Lsp;
195}
196
197#[cfg(feature = "dap")]
198impl GetMessageKind for DapMessage {
199    const MESSAGE_KIND: MessageKind = MessageKind::Dap;
200}
201
202#[allow(unused)]
203pub(crate) enum LspOrDapResponse {
204    #[cfg(feature = "lsp")]
205    Lsp(lsp::Response),
206    #[cfg(feature = "dap")]
207    Dap(dap::Response),
208}
209
210#[cfg(any(feature = "lsp", feature = "dap"))]
211pub(crate) fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
212    let mut size = None;
213    let mut buf = String::new();
214    loop {
215        buf.clear();
216        if inp.read_line(&mut buf)? == 0 {
217            return Ok(None);
218        }
219        if !buf.ends_with("\r\n") {
220            return Err(invalid_data_fmt!("malformed header: {buf:?}"));
221        }
222        let buf = &buf[..buf.len() - 2];
223        if buf.is_empty() {
224            break;
225        }
226        let mut parts = buf.splitn(2, ": ");
227        let header_name = parts.next().unwrap();
228        let header_value = parts
229            .next()
230            .ok_or_else(|| invalid_data_fmt!("malformed header: {buf:?}"))?;
231        if header_name.eq_ignore_ascii_case("Content-Length") {
232            size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
233        }
234    }
235    let size: usize = size.ok_or_else(|| invalid_data_fmt!("no Content-Length"))?;
236    let mut buf = buf.into_bytes();
237    buf.resize(size, 0);
238    inp.read_exact(&mut buf)?;
239    let buf = String::from_utf8(buf).map_err(invalid_data)?;
240    log::debug!("< {buf}");
241    Ok(Some(buf))
242}
243
244#[cfg(any(feature = "lsp", feature = "dap"))]
245pub(crate) fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> {
246    log::debug!("> {msg}");
247    write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
248    out.write_all(msg.as_bytes())?;
249    out.flush()?;
250    Ok(())
251}
252
253#[cfg(any(feature = "lsp", feature = "dap"))]
254pub(crate) fn invalid_data(
255    error: impl Into<Box<dyn std::error::Error + Send + Sync>>,
256) -> io::Error {
257    io::Error::new(io::ErrorKind::InvalidData, error)
258}
259
260#[cfg(any(feature = "lsp", feature = "dap"))]
261macro_rules! invalid_data_fmt {
262    ($($tt:tt)*) => ($crate::invalid_data(format!($($tt)*)))
263}
264#[cfg(any(feature = "lsp", feature = "dap"))]
265pub(crate) use invalid_data_fmt;