on master help sign in
embed jsonrpc types from jsonrpc-core crate (#2801)

We should not depend on jsonrpc-core anymore: * The project just announced it's no longer actively maintained[^1], preferring their new implementation in `jsonrpsee`. * The types are too strict: we would benefit from removing some `#[serde(deny_unknown_fields)]` annotations to allow language servers that disrespect the spec[^2]. * We don't use much of the project. Just the types out of core. These are easy to embed directly into the `helix-lsp` crate. [^1]: https://github.com/paritytech/jsonrpc/pull/674 [^2]: https://github.com/helix-editor/helix/issues/2786

commit45ce1ebdb604ae8b044a012f2933e6a42574430a authorMichael Davis <mcarsondavis@gmail.com> dateFri 17 Jun 2022, 22:59 (4 years ago) parentb13e534
6 files changed+373−19
Cargo.lock−14 helix-lsp/Cargo.toml−1 helix-lsp/src/client.rs+1−1 helix-lsp/src/jsonrpc.rs+370 helix-lsp/src/lib.rs+1−1 helix-lsp/src/transport.rs+1−2
Cargo.lock−14
@@ -421,7 +421,6 @@ dependencies = [
421421 "futures-executor",
422422 "futures-util",
423423 "helix-core",
424− "jsonrpc-core",
425424 "log",
426425 "lsp-types",
427426 "serde",
@@ -551,19 +550,6 @@ version = "1.0.2"
551550source = "registry+https://github.com/rust-lang/crates.io-index"
552551checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
553552
554−[[package]]
555−name = "jsonrpc-core"
556−version = "18.0.0"
557−source = "registry+https://github.com/rust-lang/crates.io-index"
558−checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb"
559−dependencies = [
560− "futures-util",
561− "log",
562− "serde",
563− "serde_derive",
564− "serde_json",
565−]
566−
567553[[package]]
568554name = "lazy_static"
569555version = "1.4.0"
helix-lsp/Cargo.toml−1
@@ -17,7 +17,6 @@ helix-core = { version = "0.6", path = "../helix-core" }
1717anyhow = "1.0"
1818futures-executor = "0.3"
1919futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
20−jsonrpc-core = { version = "18.0", default-features = false } # don't pull in all of futures
2120log = "0.4"
2221lsp-types = { version = "0.93", features = ["proposed"] }
2322serde = { version = "1.0", features = ["derive"] }
helix-lsp/src/client.rs+1−1
@@ -1,11 +1,11 @@
11use crate::{
2+ jsonrpc,
23 transport::{Payload, Transport},
34 Call, Error, OffsetEncoding, Result,
45};
56
67use anyhow::anyhow;
78use helix_core::{find_root, ChangeSet, Rope};
8−use jsonrpc_core as jsonrpc;
99use lsp_types as lsp;
1010use serde::Deserialize;
1111use serde_json::Value;
helix-lsp/src/jsonrpc.rsnew file+370
@@ -0,0 +1,370 @@
1+//! An implementation of the JSONRPC 2.0 spec types
2+
3+// Upstream implementation: https://github.com/paritytech/jsonrpc/tree/38af3c9439aa75481805edf6c05c6622a5ab1e70/core/src/types
4+// Changes from upstream:
5+// * unused functions (almost all non-trait-implementation functions) have been removed
6+// * `#[serde(deny_unknown_fields)]` annotations have been removed on response types
7+// for compatibility with non-strict language server implementations like Ruby Sorbet
8+// (see https://github.com/helix-editor/helix/issues/2786)
9+// * some variable names have been lengthened for readability
10+
11+use serde::de::{self, DeserializeOwned, Visitor};
12+use serde::{Deserialize, Serialize};
13+use serde_json::Value;
14+
15+// https://www.jsonrpc.org/specification#error_object
16+#[derive(Debug, PartialEq, Clone)]
17+pub enum ErrorCode {
18+ ParseError,
19+ InvalidRequest,
20+ MethodNotFound,
21+ InvalidParams,
22+ InternalError,
23+ ServerError(i64),
24+}
25+
26+impl ErrorCode {
27+ pub fn code(&self) -> i64 {
28+ match *self {
29+ ErrorCode::ParseError => -32700,
30+ ErrorCode::InvalidRequest => -32600,
31+ ErrorCode::MethodNotFound => -32601,
32+ ErrorCode::InvalidParams => -32602,
33+ ErrorCode::InternalError => -32603,
34+ ErrorCode::ServerError(code) => code,
35+ }
36+ }
37+}
38+
39+impl From<i64> for ErrorCode {
40+ fn from(code: i64) -> Self {
41+ match code {
42+ -32700 => ErrorCode::ParseError,
43+ -32600 => ErrorCode::InvalidRequest,
44+ -32601 => ErrorCode::MethodNotFound,
45+ -32602 => ErrorCode::InvalidParams,
46+ -32603 => ErrorCode::InternalError,
47+ code => ErrorCode::ServerError(code),
48+ }
49+ }
50+}
51+
52+impl<'de> Deserialize<'de> for ErrorCode {
53+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
54+ where
55+ D: serde::Deserializer<'de>,
56+ {
57+ let code: i64 = Deserialize::deserialize(deserializer)?;
58+ Ok(ErrorCode::from(code))
59+ }
60+}
61+
62+impl Serialize for ErrorCode {
63+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
64+ where
65+ S: serde::Serializer,
66+ {
67+ serializer.serialize_i64(self.code())
68+ }
69+}
70+
71+#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
72+pub struct Error {
73+ pub code: ErrorCode,
74+ pub message: String,
75+ #[serde(skip_serializing_if = "Option::is_none")]
76+ pub data: Option<Value>,
77+}
78+
79+impl Error {
80+ pub fn invalid_params<M>(message: M) -> Self
81+ where
82+ M: Into<String>,
83+ {
84+ Error {
85+ code: ErrorCode::InvalidParams,
86+ message: message.into(),
87+ data: None,
88+ }
89+ }
90+}
91+
92+impl std::fmt::Display for Error {
93+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94+ write!(f, "{:?}: {}", self.code, self.message)
95+ }
96+}
97+
98+impl std::error::Error for Error {}
99+
100+// https://www.jsonrpc.org/specification#request_object
101+
102+/// Request ID
103+#[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)]
104+#[serde(untagged)]
105+pub enum Id {
106+ Null,
107+ Num(u64),
108+ Str(String),
109+}
110+
111+/// Protocol Version
112+#[derive(Debug, PartialEq, Clone, Copy, Hash, Eq)]
113+pub enum Version {
114+ V2,
115+}
116+
117+impl Serialize for Version {
118+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
119+ where
120+ S: serde::Serializer,
121+ {
122+ match *self {
123+ Version::V2 => serializer.serialize_str("2.0"),
124+ }
125+ }
126+}
127+
128+struct VersionVisitor;
129+
130+impl<'v> Visitor<'v> for VersionVisitor {
131+ type Value = Version;
132+
133+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
134+ formatter.write_str("a string")
135+ }
136+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
137+ where
138+ E: de::Error,
139+ {
140+ match value {
141+ "2.0" => Ok(Version::V2),
142+ _ => Err(de::Error::custom("invalid version")),
143+ }
144+ }
145+}
146+
147+impl<'de> Deserialize<'de> for Version {
148+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
149+ where
150+ D: serde::Deserializer<'de>,
151+ {
152+ deserializer.deserialize_identifier(VersionVisitor)
153+ }
154+}
155+
156+#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
157+#[serde(untagged)]
158+pub enum Params {
159+ None,
160+ Array(Vec<Value>),
161+ Map(serde_json::Map<String, Value>),
162+}
163+
164+impl Params {
165+ pub fn parse<D>(self) -> Result<D, Error>
166+ where
167+ D: DeserializeOwned,
168+ {
169+ let value: Value = self.into();
170+ serde_json::from_value(value)
171+ .map_err(|err| Error::invalid_params(format!("Invalid params: {}.", err)))
172+ }
173+}
174+
175+impl From<Params> for Value {
176+ fn from(params: Params) -> Value {
177+ match params {
178+ Params::Array(vec) => Value::Array(vec),
179+ Params::Map(map) => Value::Object(map),
180+ Params::None => Value::Null,
181+ }
182+ }
183+}
184+
185+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
186+#[serde(deny_unknown_fields)]
187+pub struct MethodCall {
188+ pub jsonrpc: Option<Version>,
189+ pub method: String,
190+ #[serde(default = "default_params")]
191+ pub params: Params,
192+ pub id: Id,
193+}
194+
195+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
196+#[serde(deny_unknown_fields)]
197+pub struct Notification {
198+ pub jsonrpc: Option<Version>,
199+ pub method: String,
200+ #[serde(default = "default_params")]
201+ pub params: Params,
202+}
203+
204+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
205+#[serde(deny_unknown_fields)]
206+#[serde(untagged)]
207+pub enum Call {
208+ MethodCall(MethodCall),
209+ Notification(Notification),
210+ Invalid {
211+ // We can attempt to salvage the id out of the invalid request
212+ // for better debugging
213+ #[serde(default = "default_id")]
214+ id: Id,
215+ },
216+}
217+
218+fn default_params() -> Params {
219+ Params::None
220+}
221+
222+fn default_id() -> Id {
223+ Id::Null
224+}
225+
226+impl From<MethodCall> for Call {
227+ fn from(method_call: MethodCall) -> Self {
228+ Call::MethodCall(method_call)
229+ }
230+}
231+
232+impl From<Notification> for Call {
233+ fn from(notification: Notification) -> Self {
234+ Call::Notification(notification)
235+ }
236+}
237+
238+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
239+#[serde(deny_unknown_fields)]
240+#[serde(untagged)]
241+pub enum Request {
242+ Single(Call),
243+ Batch(Vec<Call>),
244+}
245+
246+// https://www.jsonrpc.org/specification#response_object
247+
248+#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
249+pub struct Success {
250+ #[serde(skip_serializing_if = "Option::is_none")]
251+ pub jsonrpc: Option<Version>,
252+ pub result: Value,
253+ pub id: Id,
254+}
255+
256+#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
257+pub struct Failure {
258+ #[serde(skip_serializing_if = "Option::is_none")]
259+ pub jsonrpc: Option<Version>,
260+ pub error: Error,
261+ pub id: Id,
262+}
263+
264+// Note that failure comes first because we're not using
265+// #[serde(deny_unknown_field)]: we want a request that contains
266+// both `result` and `error` to be a `Failure`.
267+#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
268+#[serde(untagged)]
269+pub enum Output {
270+ Failure(Failure),
271+ Success(Success),
272+}
273+
274+impl From<Output> for Result<Value, Error> {
275+ fn from(output: Output) -> Self {
276+ match output {
277+ Output::Success(success) => Ok(success.result),
278+ Output::Failure(failure) => Err(failure.error),
279+ }
280+ }
281+}
282+
283+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
284+#[serde(untagged)]
285+pub enum Response {
286+ Single(Output),
287+ Batch(Vec<Output>),
288+}
289+
290+impl From<Failure> for Response {
291+ fn from(failure: Failure) -> Self {
292+ Response::Single(Output::Failure(failure))
293+ }
294+}
295+
296+impl From<Success> for Response {
297+ fn from(success: Success) -> Self {
298+ Response::Single(Output::Success(success))
299+ }
300+}
301+
302+#[test]
303+fn method_call_serialize() {
304+ use serde_json;
305+
306+ let m = MethodCall {
307+ jsonrpc: Some(Version::V2),
308+ method: "update".to_owned(),
309+ params: Params::Array(vec![Value::from(1), Value::from(2)]),
310+ id: Id::Num(1),
311+ };
312+
313+ let serialized = serde_json::to_string(&m).unwrap();
314+ assert_eq!(
315+ serialized,
316+ r#"{"jsonrpc":"2.0","method":"update","params":[1,2],"id":1}"#
317+ );
318+}
319+
320+#[test]
321+fn notification_serialize() {
322+ use serde_json;
323+
324+ let n = Notification {
325+ jsonrpc: Some(Version::V2),
326+ method: "update".to_owned(),
327+ params: Params::Array(vec![Value::from(1), Value::from(2)]),
328+ };
329+
330+ let serialized = serde_json::to_string(&n).unwrap();
331+ assert_eq!(
332+ serialized,
333+ r#"{"jsonrpc":"2.0","method":"update","params":[1,2]}"#
334+ );
335+}
336+
337+#[test]
338+fn success_output_deserialize() {
339+ use serde_json;
340+
341+ let dso = r#"{"jsonrpc":"2.0","result":1,"id":1}"#;
342+
343+ let deserialized: Output = serde_json::from_str(dso).unwrap();
344+ assert_eq!(
345+ deserialized,
346+ Output::Success(Success {
347+ jsonrpc: Some(Version::V2),
348+ result: Value::from(1),
349+ id: Id::Num(1)
350+ })
351+ );
352+}
353+
354+#[test]
355+fn success_output_deserialize_with_extra_fields() {
356+ use serde_json;
357+
358+ // https://github.com/helix-editor/helix/issues/2786
359+ let dso = r#"{"jsonrpc":"2.0","result":1,"id":1,"requestMethod":"initialize"}"#;
360+
361+ let deserialized: Output = serde_json::from_str(dso).unwrap();
362+ assert_eq!(
363+ deserialized,
364+ Output::Success(Success {
365+ jsonrpc: Some(Version::V2),
366+ result: Value::from(1),
367+ id: Id::Num(1)
368+ })
369+ );
370+}
helix-lsp/src/lib.rs+1−1
@@ -1,10 +1,10 @@
11mod client;
2+pub mod jsonrpc;
23mod transport;
34
45pub use client::Client;
56pub use futures_executor::block_on;
67pub use jsonrpc::Call;
7−pub use jsonrpc_core as jsonrpc;
88pub use lsp::{Position, Url};
99pub use lsp_types as lsp;
1010
helix-lsp/src/transport.rs+1−2
@@ -1,6 +1,5 @@
1−use crate::{Error, Result};
1+use crate::{jsonrpc, Error, Result};
22use anyhow::Context;
3−use jsonrpc_core as jsonrpc;
43use log::{error, info};
54use serde::{Deserialize, Serialize};
65use serde_json::Value;