@@ -2,6 +2,7 @@ use crate::types::{Call, Id, LSError, LanguageId, RawMessage, ToInt, ToParams, T
2
2
use anyhow:: { anyhow, Result } ;
3
3
use crossbeam:: channel:: { bounded, unbounded, Receiver , Sender } ;
4
4
use log:: * ;
5
+ use regex:: Regex ;
5
6
use serde:: { de:: DeserializeOwned , Serialize } ;
6
7
use std:: io:: Write ;
7
8
use std:: str:: FromStr ;
@@ -15,6 +16,13 @@ use std::{
15
16
16
17
const CONTENT_MODIFIED_ERROR_CODE : i64 = -32801 ;
17
18
19
+ lazy_static ! {
20
+ // this regex is used to remove some additional fields that we get from some servers, namely:
21
+ // meta, sent by javascript-typescript-langserver and requestMethod, sent by Sorbet.
22
+ static ref RE_REMOVE_EXTRA_FIELDS : Regex =
23
+ Regex :: new( r#",\s?"(?:meta|requestMethod)":(?:"\w+(/\w+)?"|\{\})"# ) . unwrap( ) ;
24
+ }
25
+
18
26
#[ derive( Serialize ) ]
19
27
pub struct RpcClient {
20
28
language_id : LanguageId ,
@@ -181,8 +189,9 @@ fn loop_read(
181
189
continue ;
182
190
}
183
191
info ! ( "<= {:?} {}" , language_id, message) ;
184
- // FIXME: Remove extra `meta` property from javascript-typescript-langserver.
185
- let s = message. replace ( r#","meta":{}"# , "" ) ;
192
+ // FIXME: Remove extra `meta` property from javascript-typescript-langserver and
193
+ // `requestMethod` sent by Sorbet.
194
+ let s = RE_REMOVE_EXTRA_FIELDS . replace ( message, "" ) ;
186
195
let message = serde_json:: from_str ( & s) ;
187
196
if let Err ( ref err) = message {
188
197
error ! (
@@ -240,3 +249,37 @@ fn loop_write(
240
249
}
241
250
Ok ( ( ) )
242
251
}
252
+
253
+ #[ cfg( test) ]
254
+ mod test {
255
+ use super :: RE_REMOVE_EXTRA_FIELDS ;
256
+ use crate :: types:: RawMessage ;
257
+
258
+ #[ test]
259
+ // The library we're using for json-rpc doesn't accept extra fields in the structs used to
260
+ // deserialize the message. Sorbet (and possibly other servers) sends an extra field in it, so
261
+ // the client fails to deserialize that response.
262
+ // Our previous solution was to pin the dependency to jsonrpc-core to version 12, but is
263
+ // suboptimal, so we now try to remove the extra fields we know of from the response.
264
+ //
265
+ // See related issue: https://github.com/autozimu/LanguageClient-neovim/issues/892
266
+ fn it_should_remove_extra_fields ( ) {
267
+ // it removes the requestMethod field from Sorbet
268
+ let message = r#"{"jsonrpc":"2.0","id":1,"requestMethod":"initialize","result":0}"# ;
269
+ let message = RE_REMOVE_EXTRA_FIELDS . replace ( message, "" ) ;
270
+ let result: Result < RawMessage , _ > = serde_json:: from_str ( & message) ;
271
+ assert ! ( result. is_ok( ) ) ;
272
+
273
+ let message =
274
+ r#"{"jsonrpc":"2.0","id":1,"requestMethod":"textDocument/definition","result":0}"# ;
275
+ let message = RE_REMOVE_EXTRA_FIELDS . replace ( message, "" ) ;
276
+ let result: Result < RawMessage , _ > = serde_json:: from_str ( & message) ;
277
+ assert ! ( result. is_ok( ) ) ;
278
+
279
+ // it removes the meta field from javascript-typescript-langserver
280
+ let message = r#"{"jsonrpc":"2.0","id":1,"meta":{},"result":0}"# ;
281
+ let message = RE_REMOVE_EXTRA_FIELDS . replace ( message, "" ) ;
282
+ let result: Result < RawMessage , _ > = serde_json:: from_str ( & message) ;
283
+ assert ! ( result. is_ok( ) ) ;
284
+ }
285
+ }
0 commit comments