@@ -17,8 +17,9 @@ use std::{
1717use crossbeam_channel:: { never, select, unbounded, RecvError , Sender } ;
1818use lsp_server:: { Connection , ErrorCode , Message , Notification , Request , RequestId , Response } ;
1919use lsp_types:: {
20- ClientCapabilities , NumberOrString , WorkDoneProgress , WorkDoneProgressBegin ,
21- WorkDoneProgressCreateParams , WorkDoneProgressEnd , WorkDoneProgressReport ,
20+ ClientCapabilities , NumberOrString , TextDocumentClientCapabilities , WorkDoneProgress ,
21+ WorkDoneProgressBegin , WorkDoneProgressCreateParams , WorkDoneProgressEnd ,
22+ WorkDoneProgressReport ,
2223} ;
2324use ra_cargo_watch:: { url_from_path_with_drive_lowercasing, CheckOptions , CheckTask } ;
2425use ra_ide:: { Canceled , FileId , InlayHintsOptions , LibraryData , SourceRootId } ;
@@ -40,6 +41,7 @@ use crate::{
4041 world:: { Options , WorldSnapshot , WorldState } ,
4142 Result , ServerConfig ,
4243} ;
44+ use req:: ConfigurationParams ;
4345
4446#[ derive( Debug ) ]
4547pub struct LspError {
@@ -63,6 +65,53 @@ impl fmt::Display for LspError {
6365
6466impl Error for LspError { }
6567
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+
66115pub fn main_loop (
67116 ws_roots : Vec < PathBuf > ,
68117 client_caps : ClientCapabilities ,
@@ -90,23 +139,10 @@ pub fn main_loop(
90139 SetThreadPriority ( thread, thread_priority_above_normal) ;
91140 }
92141
142+ let text_document_caps = client_caps. text_document . as_ref ( ) ;
93143 let mut loop_state = LoopState :: default ( ) ;
94144 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) ;
110146
111147 // FIXME: support dynamic workspace loading.
112148 let workspaces = {
@@ -168,42 +204,13 @@ pub fn main_loop(
168204 connection. sender . send ( request. into ( ) ) . unwrap ( ) ;
169205 }
170206
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-
200207 WorldState :: new (
201208 ws_roots,
202209 workspaces,
203210 config. lru_capacity ,
204211 & globs,
205212 Watch ( !config. use_client_watching ) ,
206- options ,
213+ get_options ( & config , text_document_caps ) ,
207214 feature_flags,
208215 )
209216 } ;
@@ -247,6 +254,7 @@ pub fn main_loop(
247254 & task_sender,
248255 & libdata_sender,
249256 & connection,
257+ text_document_caps,
250258 & mut world_state,
251259 & mut loop_state,
252260 event,
@@ -336,10 +344,10 @@ struct LoopState {
336344 in_flight_libraries : usize ,
337345 pending_libraries : Vec < ( SourceRootId , Vec < ( FileId , RelativePathBuf , Arc < String > ) > ) > ,
338346 workspace_loaded : bool ,
339-
340347 roots_progress_reported : Option < usize > ,
341348 roots_scanned : usize ,
342349 roots_total : usize ,
350+ configuration_request_id : Option < RequestId > ,
343351}
344352
345353impl LoopState {
@@ -357,6 +365,7 @@ fn loop_turn(
357365 task_sender : & Sender < Task > ,
358366 libdata_sender : & Sender < LibraryData > ,
359367 connection : & Connection ,
368+ text_document_caps : Option < & TextDocumentClientCapabilities > ,
360369 world_state : & mut WorldState ,
361370 loop_state : & mut LoopState ,
362371 event : Event ,
@@ -397,19 +406,47 @@ fn loop_turn(
397406 req,
398407 ) ?,
399408 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) ?;
407410 }
408411 Message :: Response ( resp) => {
409412 let removed = loop_state. pending_responses . remove ( & resp. id ) ;
410413 if !removed {
411414 log:: error!( "unexpected response: {:?}" , resp)
412415 }
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+ }
413450 }
414451 } ,
415452 } ;
@@ -569,8 +606,7 @@ fn on_request(
569606fn on_notification (
570607 msg_sender : & Sender < Message > ,
571608 state : & mut WorldState ,
572- pending_requests : & mut PendingRequests ,
573- subs : & mut Subscriptions ,
609+ loop_state : & mut LoopState ,
574610 not : Notification ,
575611) -> Result < ( ) > {
576612 let not = match notification_cast :: < req:: Cancel > ( not) {
@@ -579,7 +615,7 @@ fn on_notification(
579615 NumberOrString :: Number ( id) => id. into ( ) ,
580616 NumberOrString :: String ( id) => id. into ( ) ,
581617 } ;
582- if pending_requests. cancel ( & id) {
618+ if loop_state . pending_requests . cancel ( & id) {
583619 let response = Response :: new_err (
584620 id,
585621 ErrorCode :: RequestCanceled as i32 ,
@@ -598,7 +634,7 @@ fn on_notification(
598634 if let Some ( file_id) =
599635 state. vfs . write ( ) . add_file_overlay ( & path, params. text_document . text )
600636 {
601- subs . add_sub ( FileId ( file_id. 0 ) ) ;
637+ loop_state . subscriptions . add_sub ( FileId ( file_id. 0 ) ) ;
602638 }
603639 return Ok ( ( ) ) ;
604640 }
@@ -629,7 +665,7 @@ fn on_notification(
629665 let uri = params. text_document . uri ;
630666 let path = uri. to_file_path ( ) . map_err ( |( ) | format ! ( "invalid uri: {}" , uri) ) ?;
631667 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 ) ) ;
633669 }
634670 let params =
635671 req:: PublishDiagnosticsParams { uri, diagnostics : Vec :: new ( ) , version : None } ;
@@ -640,7 +676,17 @@ fn on_notification(
640676 Err ( not) => not,
641677 } ;
642678 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+
644690 return Ok ( ( ) ) ;
645691 }
646692 Err ( not) => not,
0 commit comments