@@ -17,8 +17,9 @@ use std::{
17
17
use crossbeam_channel:: { never, select, unbounded, RecvError , Sender } ;
18
18
use lsp_server:: { Connection , ErrorCode , Message , Notification , Request , RequestId , Response } ;
19
19
use lsp_types:: {
20
- ClientCapabilities , NumberOrString , WorkDoneProgress , WorkDoneProgressBegin ,
21
- WorkDoneProgressCreateParams , WorkDoneProgressEnd , WorkDoneProgressReport ,
20
+ ClientCapabilities , NumberOrString , TextDocumentClientCapabilities , WorkDoneProgress ,
21
+ WorkDoneProgressBegin , WorkDoneProgressCreateParams , WorkDoneProgressEnd ,
22
+ WorkDoneProgressReport ,
22
23
} ;
23
24
use ra_cargo_watch:: { url_from_path_with_drive_lowercasing, CheckOptions , CheckTask } ;
24
25
use ra_ide:: { Canceled , FileId , InlayHintsOptions , LibraryData , SourceRootId } ;
@@ -40,6 +41,7 @@ use crate::{
40
41
world:: { Options , WorldSnapshot , WorldState } ,
41
42
Result , ServerConfig ,
42
43
} ;
44
+ use req:: ConfigurationParams ;
43
45
44
46
#[ derive( Debug ) ]
45
47
pub struct LspError {
@@ -63,6 +65,53 @@ impl fmt::Display for LspError {
63
65
64
66
impl Error for LspError { }
65
67
68
+ fn get_feature_flags ( config : & ServerConfig , connection : & Connection ) -> FeatureFlags {
69
+ let mut ff = FeatureFlags :: default ( ) ;
70
+ for ( flag, & value) in & config. feature_flags {
71
+ if ff. set ( flag. as_str ( ) , value) . is_err ( ) {
72
+ log:: error!( "unknown feature flag: {:?}" , flag) ;
73
+ show_message (
74
+ req:: MessageType :: Error ,
75
+ format ! ( "unknown feature flag: {:?}" , flag) ,
76
+ & connection. sender ,
77
+ ) ;
78
+ }
79
+ }
80
+ log:: info!( "feature_flags: {:#?}" , ff) ;
81
+ ff
82
+ }
83
+
84
+ fn get_options (
85
+ config : & ServerConfig ,
86
+ text_document_caps : Option < & TextDocumentClientCapabilities > ,
87
+ ) -> Options {
88
+ Options {
89
+ publish_decorations : config. publish_decorations ,
90
+ supports_location_link : text_document_caps
91
+ . and_then ( |it| it. definition )
92
+ . and_then ( |it| it. link_support )
93
+ . unwrap_or ( false ) ,
94
+ line_folding_only : text_document_caps
95
+ . and_then ( |it| it. folding_range . as_ref ( ) )
96
+ . and_then ( |it| it. line_folding_only )
97
+ . unwrap_or ( false ) ,
98
+ inlay_hints : InlayHintsOptions {
99
+ type_hints : config. inlay_hints_type ,
100
+ parameter_hints : config. inlay_hints_parameter ,
101
+ chaining_hints : config. inlay_hints_chaining ,
102
+ max_length : config. inlay_hints_max_length ,
103
+ } ,
104
+ cargo_watch : CheckOptions {
105
+ enable : config. cargo_watch_enable ,
106
+ args : config. cargo_watch_args . clone ( ) ,
107
+ command : config. cargo_watch_command . clone ( ) ,
108
+ all_targets : config. cargo_watch_all_targets ,
109
+ } ,
110
+ rustfmt_args : config. rustfmt_args . clone ( ) ,
111
+ vscode_lldb : config. vscode_lldb ,
112
+ }
113
+ }
114
+
66
115
pub fn main_loop (
67
116
ws_roots : Vec < PathBuf > ,
68
117
client_caps : ClientCapabilities ,
@@ -90,23 +139,10 @@ pub fn main_loop(
90
139
SetThreadPriority ( thread, thread_priority_above_normal) ;
91
140
}
92
141
142
+ let text_document_caps = client_caps. text_document . as_ref ( ) ;
93
143
let mut loop_state = LoopState :: default ( ) ;
94
144
let mut world_state = {
95
- let feature_flags = {
96
- let mut ff = FeatureFlags :: default ( ) ;
97
- for ( flag, value) in config. feature_flags {
98
- if ff. set ( flag. as_str ( ) , value) . is_err ( ) {
99
- log:: error!( "unknown feature flag: {:?}" , flag) ;
100
- show_message (
101
- req:: MessageType :: Error ,
102
- format ! ( "unknown feature flag: {:?}" , flag) ,
103
- & connection. sender ,
104
- ) ;
105
- }
106
- }
107
- ff
108
- } ;
109
- log:: info!( "feature_flags: {:#?}" , feature_flags) ;
145
+ let feature_flags = get_feature_flags ( & config, & connection) ;
110
146
111
147
// FIXME: support dynamic workspace loading.
112
148
let workspaces = {
@@ -168,42 +204,13 @@ pub fn main_loop(
168
204
connection. sender . send ( request. into ( ) ) . unwrap ( ) ;
169
205
}
170
206
171
- let options = {
172
- let text_document_caps = client_caps. text_document . as_ref ( ) ;
173
- Options {
174
- publish_decorations : config. publish_decorations ,
175
- supports_location_link : text_document_caps
176
- . and_then ( |it| it. definition )
177
- . and_then ( |it| it. link_support )
178
- . unwrap_or ( false ) ,
179
- line_folding_only : text_document_caps
180
- . and_then ( |it| it. folding_range . as_ref ( ) )
181
- . and_then ( |it| it. line_folding_only )
182
- . unwrap_or ( false ) ,
183
- inlay_hints : InlayHintsOptions {
184
- type_hints : config. inlay_hints_type ,
185
- parameter_hints : config. inlay_hints_parameter ,
186
- chaining_hints : config. inlay_hints_chaining ,
187
- max_length : config. inlay_hints_max_length ,
188
- } ,
189
- cargo_watch : CheckOptions {
190
- enable : config. cargo_watch_enable ,
191
- args : config. cargo_watch_args ,
192
- command : config. cargo_watch_command ,
193
- all_targets : config. cargo_watch_all_targets ,
194
- } ,
195
- rustfmt_args : config. rustfmt_args ,
196
- vscode_lldb : config. vscode_lldb ,
197
- }
198
- } ;
199
-
200
207
WorldState :: new (
201
208
ws_roots,
202
209
workspaces,
203
210
config. lru_capacity ,
204
211
& globs,
205
212
Watch ( !config. use_client_watching ) ,
206
- options ,
213
+ get_options ( & config , text_document_caps ) ,
207
214
feature_flags,
208
215
)
209
216
} ;
@@ -247,6 +254,7 @@ pub fn main_loop(
247
254
& task_sender,
248
255
& libdata_sender,
249
256
& connection,
257
+ text_document_caps,
250
258
& mut world_state,
251
259
& mut loop_state,
252
260
event,
@@ -336,10 +344,10 @@ struct LoopState {
336
344
in_flight_libraries : usize ,
337
345
pending_libraries : Vec < ( SourceRootId , Vec < ( FileId , RelativePathBuf , Arc < String > ) > ) > ,
338
346
workspace_loaded : bool ,
339
-
340
347
roots_progress_reported : Option < usize > ,
341
348
roots_scanned : usize ,
342
349
roots_total : usize ,
350
+ configuration_request_id : Option < RequestId > ,
343
351
}
344
352
345
353
impl LoopState {
@@ -357,6 +365,7 @@ fn loop_turn(
357
365
task_sender : & Sender < Task > ,
358
366
libdata_sender : & Sender < LibraryData > ,
359
367
connection : & Connection ,
368
+ text_document_caps : Option < & TextDocumentClientCapabilities > ,
360
369
world_state : & mut WorldState ,
361
370
loop_state : & mut LoopState ,
362
371
event : Event ,
@@ -397,19 +406,47 @@ fn loop_turn(
397
406
req,
398
407
) ?,
399
408
Message :: Notification ( not) => {
400
- on_notification (
401
- & connection. sender ,
402
- world_state,
403
- & mut loop_state. pending_requests ,
404
- & mut loop_state. subscriptions ,
405
- not,
406
- ) ?;
409
+ on_notification ( & connection. sender , world_state, loop_state, not) ?;
407
410
}
408
411
Message :: Response ( resp) => {
409
412
let removed = loop_state. pending_responses . remove ( & resp. id ) ;
410
413
if !removed {
411
414
log:: error!( "unexpected response: {:?}" , resp)
412
415
}
416
+
417
+ if Some ( & resp. id ) == loop_state. configuration_request_id . as_ref ( ) {
418
+ loop_state. configuration_request_id = None ;
419
+ log:: debug!( "config update response: '{:?}" , resp) ;
420
+ let Response { error, result, .. } = resp;
421
+
422
+ match (
423
+ error,
424
+ result. map ( |result| serde_json:: from_value :: < Vec < ServerConfig > > ( result) ) ,
425
+ ) {
426
+ ( Some ( err) , _) => {
427
+ log:: error!( "failed to fetch the server settings: {:?}" , err)
428
+ }
429
+ ( None , Some ( Ok ( new_config) ) ) => {
430
+ let new_config = new_config
431
+ . first ( )
432
+ . expect (
433
+ "the client is expected to always send a non-empty config data" ,
434
+ )
435
+ . to_owned ( ) ;
436
+ world_state. update_configuration (
437
+ new_config. lru_capacity ,
438
+ get_options ( & new_config, text_document_caps) ,
439
+ get_feature_flags ( & new_config, connection) ,
440
+ ) ;
441
+ }
442
+ ( None , Some ( Err ( e) ) ) => {
443
+ log:: error!( "failed to parse client config response: {}" , e)
444
+ }
445
+ ( None , None ) => {
446
+ log:: error!( "received empty server settings response from the client" )
447
+ }
448
+ }
449
+ }
413
450
}
414
451
} ,
415
452
} ;
@@ -569,8 +606,7 @@ fn on_request(
569
606
fn on_notification (
570
607
msg_sender : & Sender < Message > ,
571
608
state : & mut WorldState ,
572
- pending_requests : & mut PendingRequests ,
573
- subs : & mut Subscriptions ,
609
+ loop_state : & mut LoopState ,
574
610
not : Notification ,
575
611
) -> Result < ( ) > {
576
612
let not = match notification_cast :: < req:: Cancel > ( not) {
@@ -579,7 +615,7 @@ fn on_notification(
579
615
NumberOrString :: Number ( id) => id. into ( ) ,
580
616
NumberOrString :: String ( id) => id. into ( ) ,
581
617
} ;
582
- if pending_requests. cancel ( & id) {
618
+ if loop_state . pending_requests . cancel ( & id) {
583
619
let response = Response :: new_err (
584
620
id,
585
621
ErrorCode :: RequestCanceled as i32 ,
@@ -598,7 +634,7 @@ fn on_notification(
598
634
if let Some ( file_id) =
599
635
state. vfs . write ( ) . add_file_overlay ( & path, params. text_document . text )
600
636
{
601
- subs . add_sub ( FileId ( file_id. 0 ) ) ;
637
+ loop_state . subscriptions . add_sub ( FileId ( file_id. 0 ) ) ;
602
638
}
603
639
return Ok ( ( ) ) ;
604
640
}
@@ -629,7 +665,7 @@ fn on_notification(
629
665
let uri = params. text_document . uri ;
630
666
let path = uri. to_file_path ( ) . map_err ( |( ) | format ! ( "invalid uri: {}" , uri) ) ?;
631
667
if let Some ( file_id) = state. vfs . write ( ) . remove_file_overlay ( path. as_path ( ) ) {
632
- subs . remove_sub ( FileId ( file_id. 0 ) ) ;
668
+ loop_state . subscriptions . remove_sub ( FileId ( file_id. 0 ) ) ;
633
669
}
634
670
let params =
635
671
req:: PublishDiagnosticsParams { uri, diagnostics : Vec :: new ( ) , version : None } ;
@@ -640,7 +676,17 @@ fn on_notification(
640
676
Err ( not) => not,
641
677
} ;
642
678
let not = match notification_cast :: < req:: DidChangeConfiguration > ( not) {
643
- Ok ( _params) => {
679
+ Ok ( _) => {
680
+ // As stated in https://github.com/microsoft/language-server-protocol/issues/676,
681
+ // this notification's parameters should be ignored and the actual config queried separately.
682
+ let request_id = loop_state. next_request_id ( ) ;
683
+ let request = request_new :: < req:: WorkspaceConfiguration > (
684
+ request_id. clone ( ) ,
685
+ ConfigurationParams :: default ( ) ,
686
+ ) ;
687
+ msg_sender. send ( request. into ( ) ) ?;
688
+ loop_state. configuration_request_id = Some ( request_id) ;
689
+
644
690
return Ok ( ( ) ) ;
645
691
}
646
692
Err ( not) => not,
0 commit comments