aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-30 13:45:49 +0100
committerGitHub <[email protected]>2020-03-30 13:45:49 +0100
commit671926ac93f0ff921758a919eaf87c056979189f (patch)
tree111c2cc751cb7fcca38eb7518e1d39af394ee243
parent9e12b9e6fdc03ea6bc35a88cfb5d5d6751672ec8 (diff)
parent4c897d8d2dd047e0906d585318866c9ae7a21610 (diff)
Merge #3666
3666: Reload part of the server configuration without restarts r=matklad a=SomeoneToIgnore Partially addresses https://github.com/rust-analyzer/rust-analyzer/issues/2857 Closes #3751 Reloads all server configuration that's not related to VFS without restarts. The VFS-related parameters are not considered, since VFS is planned to be rewritten/replaced in the future and I have a suspicion that with the current code, swapping the VFS and the file watchers on the fly will cause big troubles. I have to store and process the config request id separately, since the `workspace/configuration` response returns `any[]` (https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration), if there's a better way to handle those responses, let me know. Co-authored-by: Kirill Bulatov <[email protected]>
-rw-r--r--crates/ra_cargo_watch/src/lib.rs10
-rw-r--r--crates/ra_ide/src/lib.rs5
-rw-r--r--crates/ra_ide_db/src/lib.rs12
-rw-r--r--crates/rust-analyzer/src/main_loop.rs168
-rw-r--r--crates/rust-analyzer/src/req.rs2
-rw-r--r--crates/rust-analyzer/src/world.rs46
-rw-r--r--editors/code/src/client.ts49
-rw-r--r--editors/code/src/config.ts6
-rw-r--r--editors/code/src/ctx.ts3
-rw-r--r--editors/code/src/inlay_hints.ts8
-rw-r--r--editors/code/src/main.ts6
11 files changed, 205 insertions, 110 deletions
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index c67ec39d4..2692c1bf5 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -95,6 +95,9 @@ impl CheckWatcherThread {
95 } 95 }
96 96
97 fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) { 97 fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) {
98 // If we rerun the thread, we need to discard the previous check results first
99 self.clean_previous_results(task_send);
100
98 loop { 101 loop {
99 select! { 102 select! {
100 recv(&cmd_recv) -> cmd => match cmd { 103 recv(&cmd_recv) -> cmd => match cmd {
@@ -127,6 +130,13 @@ impl CheckWatcherThread {
127 } 130 }
128 } 131 }
129 132
133 fn clean_previous_results(&self, task_send: &Sender<CheckTask>) {
134 task_send.send(CheckTask::ClearDiagnostics).unwrap();
135 task_send
136 .send(CheckTask::Status(WorkDoneProgress::End(WorkDoneProgressEnd { message: None })))
137 .unwrap();
138 }
139
130 fn should_recheck(&mut self) -> bool { 140 fn should_recheck(&mut self) -> bool {
131 if let Some(_last_update_req) = &self.last_update_req { 141 if let Some(_last_update_req) = &self.last_update_req {
132 // We currently only request an update on save, as we need up to 142 // We currently only request an update on save, as we need up to
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index e43414985..937c9caa5 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -138,6 +138,11 @@ impl AnalysisHost {
138 pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { 138 pub fn new(lru_capacity: Option<usize>) -> AnalysisHost {
139 AnalysisHost { db: RootDatabase::new(lru_capacity) } 139 AnalysisHost { db: RootDatabase::new(lru_capacity) }
140 } 140 }
141
142 pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
143 self.db.update_lru_capacity(lru_capacity);
144 }
145
141 /// Returns a snapshot of the current state, which you can query for 146 /// Returns a snapshot of the current state, which you can query for
142 /// semantic information. 147 /// semantic information.
143 pub fn analysis(&self) -> Analysis { 148 pub fn analysis(&self) -> Analysis {
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index 4faeefa8d..e6f2d36e9 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -115,12 +115,16 @@ impl RootDatabase {
115 db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); 115 db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
116 db.set_local_roots_with_durability(Default::default(), Durability::HIGH); 116 db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
117 db.set_library_roots_with_durability(Default::default(), Durability::HIGH); 117 db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
118 let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP); 118 db.update_lru_capacity(lru_capacity);
119 db.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_capacity);
120 db.query_mut(hir::db::ParseMacroQuery).set_lru_capacity(lru_capacity);
121 db.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity);
122 db 119 db
123 } 120 }
121
122 pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
123 let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP);
124 self.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_capacity);
125 self.query_mut(hir::db::ParseMacroQuery).set_lru_capacity(lru_capacity);
126 self.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity);
127 }
124} 128}
125 129
126impl salsa::ParallelDatabase for RootDatabase { 130impl salsa::ParallelDatabase for RootDatabase {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index c899ff677..79ea90cc9 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -17,8 +17,9 @@ use std::{
17use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; 17use crossbeam_channel::{never, select, unbounded, RecvError, Sender};
18use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 18use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
19use lsp_types::{ 19use lsp_types::{
20 ClientCapabilities, NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, 20 ClientCapabilities, NumberOrString, TextDocumentClientCapabilities, WorkDoneProgress,
21 WorkDoneProgressCreateParams, WorkDoneProgressEnd, WorkDoneProgressReport, 21 WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd,
22 WorkDoneProgressReport,
22}; 23};
23use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; 24use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask};
24use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId}; 25use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId};
@@ -40,6 +41,7 @@ use crate::{
40 world::{Options, WorldSnapshot, WorldState}, 41 world::{Options, WorldSnapshot, WorldState},
41 Result, ServerConfig, 42 Result, ServerConfig,
42}; 43};
44use req::ConfigurationParams;
43 45
44#[derive(Debug)] 46#[derive(Debug)]
45pub struct LspError { 47pub struct LspError {
@@ -63,6 +65,53 @@ impl fmt::Display for LspError {
63 65
64impl Error for LspError {} 66impl Error for LspError {}
65 67
68fn 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
84fn 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
66pub fn main_loop( 115pub fn main_loop(
67 ws_roots: Vec<PathBuf>, 116 ws_roots: Vec<PathBuf>,
68 client_caps: ClientCapabilities, 117 client_caps: ClientCapabilities,
@@ -90,23 +139,10 @@ pub fn main_loop(
90 SetThreadPriority(thread, thread_priority_above_normal); 139 SetThreadPriority(thread, thread_priority_above_normal);
91 } 140 }
92 141
142 let text_document_caps = client_caps.text_document.as_ref();
93 let mut loop_state = LoopState::default(); 143 let mut loop_state = LoopState::default();
94 let mut world_state = { 144 let mut world_state = {
95 let feature_flags = { 145 let feature_flags = get_feature_flags(&config, &connection);
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);
110 146
111 // FIXME: support dynamic workspace loading. 147 // FIXME: support dynamic workspace loading.
112 let workspaces = { 148 let workspaces = {
@@ -168,42 +204,13 @@ pub fn main_loop(
168 connection.sender.send(request.into()).unwrap(); 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 WorldState::new( 207 WorldState::new(
201 ws_roots, 208 ws_roots,
202 workspaces, 209 workspaces,
203 config.lru_capacity, 210 config.lru_capacity,
204 &globs, 211 &globs,
205 Watch(!config.use_client_watching), 212 Watch(!config.use_client_watching),
206 options, 213 get_options(&config, text_document_caps),
207 feature_flags, 214 feature_flags,
208 ) 215 )
209 }; 216 };
@@ -247,6 +254,7 @@ pub fn main_loop(
247 &task_sender, 254 &task_sender,
248 &libdata_sender, 255 &libdata_sender,
249 &connection, 256 &connection,
257 text_document_caps,
250 &mut world_state, 258 &mut world_state,
251 &mut loop_state, 259 &mut loop_state,
252 event, 260 event,
@@ -336,10 +344,10 @@ struct LoopState {
336 in_flight_libraries: usize, 344 in_flight_libraries: usize,
337 pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>, 345 pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>,
338 workspace_loaded: bool, 346 workspace_loaded: bool,
339
340 roots_progress_reported: Option<usize>, 347 roots_progress_reported: Option<usize>,
341 roots_scanned: usize, 348 roots_scanned: usize,
342 roots_total: usize, 349 roots_total: usize,
350 configuration_request_id: Option<RequestId>,
343} 351}
344 352
345impl LoopState { 353impl LoopState {
@@ -357,6 +365,7 @@ fn loop_turn(
357 task_sender: &Sender<Task>, 365 task_sender: &Sender<Task>,
358 libdata_sender: &Sender<LibraryData>, 366 libdata_sender: &Sender<LibraryData>,
359 connection: &Connection, 367 connection: &Connection,
368 text_document_caps: Option<&TextDocumentClientCapabilities>,
360 world_state: &mut WorldState, 369 world_state: &mut WorldState,
361 loop_state: &mut LoopState, 370 loop_state: &mut LoopState,
362 event: Event, 371 event: Event,
@@ -397,19 +406,47 @@ fn loop_turn(
397 req, 406 req,
398 )?, 407 )?,
399 Message::Notification(not) => { 408 Message::Notification(not) => {
400 on_notification( 409 on_notification(&connection.sender, world_state, loop_state, not)?;
401 &connection.sender,
402 world_state,
403 &mut loop_state.pending_requests,
404 &mut loop_state.subscriptions,
405 not,
406 )?;
407 } 410 }
408 Message::Response(resp) => { 411 Message::Response(resp) => {
409 let removed = loop_state.pending_responses.remove(&resp.id); 412 let removed = loop_state.pending_responses.remove(&resp.id);
410 if !removed { 413 if !removed {
411 log::error!("unexpected response: {:?}", resp) 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(
569fn on_notification( 606fn on_notification(
570 msg_sender: &Sender<Message>, 607 msg_sender: &Sender<Message>,
571 state: &mut WorldState, 608 state: &mut WorldState,
572 pending_requests: &mut PendingRequests, 609 loop_state: &mut LoopState,
573 subs: &mut Subscriptions,
574 not: Notification, 610 not: Notification,
575) -> Result<()> { 611) -> Result<()> {
576 let not = match notification_cast::<req::Cancel>(not) { 612 let not = match notification_cast::<req::Cancel>(not) {
@@ -579,7 +615,7 @@ fn on_notification(
579 NumberOrString::Number(id) => id.into(), 615 NumberOrString::Number(id) => id.into(),
580 NumberOrString::String(id) => id.into(), 616 NumberOrString::String(id) => id.into(),
581 }; 617 };
582 if pending_requests.cancel(&id) { 618 if loop_state.pending_requests.cancel(&id) {
583 let response = Response::new_err( 619 let response = Response::new_err(
584 id, 620 id,
585 ErrorCode::RequestCanceled as i32, 621 ErrorCode::RequestCanceled as i32,
@@ -598,7 +634,7 @@ fn on_notification(
598 if let Some(file_id) = 634 if let Some(file_id) =
599 state.vfs.write().add_file_overlay(&path, params.text_document.text) 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 return Ok(()); 639 return Ok(());
604 } 640 }
@@ -629,7 +665,7 @@ fn on_notification(
629 let uri = params.text_document.uri; 665 let uri = params.text_document.uri;
630 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; 666 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
631 if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) { 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 let params = 670 let params =
635 req::PublishDiagnosticsParams { uri, diagnostics: Vec::new(), version: None }; 671 req::PublishDiagnosticsParams { uri, diagnostics: Vec::new(), version: None };
@@ -640,7 +676,17 @@ fn on_notification(
640 Err(not) => not, 676 Err(not) => not,
641 }; 677 };
642 let not = match notification_cast::<req::DidChangeConfiguration>(not) { 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 return Ok(()); 690 return Ok(());
645 } 691 }
646 Err(not) => not, 692 Err(not) => not,
diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs
index 8557294f6..994f0ed61 100644
--- a/crates/rust-analyzer/src/req.rs
+++ b/crates/rust-analyzer/src/req.rs
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
6 6
7pub use lsp_types::{ 7pub use lsp_types::{
8 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, 8 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens,
9 CodeLensParams, CompletionParams, CompletionResponse, DiagnosticTag, 9 CodeLensParams, CompletionParams, CompletionResponse, ConfigurationParams, DiagnosticTag,
10 DidChangeConfigurationParams, DidChangeWatchedFilesParams, 10 DidChangeConfigurationParams, DidChangeWatchedFilesParams,
11 DidChangeWatchedFilesRegistrationOptions, DocumentOnTypeFormattingParams, DocumentSymbolParams, 11 DidChangeWatchedFilesRegistrationOptions, DocumentOnTypeFormattingParams, DocumentSymbolParams,
12 DocumentSymbolResponse, FileSystemWatcher, Hover, InitializeResult, MessageType, 12 DocumentSymbolResponse, FileSystemWatcher, Hover, InitializeResult, MessageType,
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs
index ca045f93c..ad096a1d8 100644
--- a/crates/rust-analyzer/src/world.rs
+++ b/crates/rust-analyzer/src/world.rs
@@ -31,6 +31,24 @@ use crate::{
31use ra_db::ExternSourceId; 31use ra_db::ExternSourceId;
32use rustc_hash::{FxHashMap, FxHashSet}; 32use rustc_hash::{FxHashMap, FxHashSet};
33 33
34fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> Option<CheckWatcher> {
35 // FIXME: Figure out the multi-workspace situation
36 workspaces
37 .iter()
38 .find_map(|w| match w {
39 ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
40 ProjectWorkspace::Json { .. } => None,
41 })
42 .map(|cargo| {
43 let cargo_project_root = cargo.workspace_root().to_path_buf();
44 Some(CheckWatcher::new(&options.cargo_watch, cargo_project_root))
45 })
46 .unwrap_or_else(|| {
47 log::warn!("Cargo check watching only supported for cargo workspaces, disabling");
48 None
49 })
50}
51
34#[derive(Debug, Clone)] 52#[derive(Debug, Clone)]
35pub struct Options { 53pub struct Options {
36 pub publish_decorations: bool, 54 pub publish_decorations: bool,
@@ -167,21 +185,7 @@ impl WorldState {
167 }); 185 });
168 change.set_crate_graph(crate_graph); 186 change.set_crate_graph(crate_graph);
169 187
170 // FIXME: Figure out the multi-workspace situation 188 let check_watcher = create_watcher(&workspaces, &options);
171 let check_watcher = workspaces
172 .iter()
173 .find_map(|w| match w {
174 ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
175 ProjectWorkspace::Json { .. } => None,
176 })
177 .map(|cargo| {
178 let cargo_project_root = cargo.workspace_root().to_path_buf();
179 Some(CheckWatcher::new(&options.cargo_watch, cargo_project_root))
180 })
181 .unwrap_or_else(|| {
182 log::warn!("Cargo check watching only supported for cargo workspaces, disabling");
183 None
184 });
185 189
186 let mut analysis_host = AnalysisHost::new(lru_capacity); 190 let mut analysis_host = AnalysisHost::new(lru_capacity);
187 analysis_host.apply_change(change); 191 analysis_host.apply_change(change);
@@ -199,6 +203,18 @@ impl WorldState {
199 } 203 }
200 } 204 }
201 205
206 pub fn update_configuration(
207 &mut self,
208 lru_capacity: Option<usize>,
209 options: Options,
210 feature_flags: FeatureFlags,
211 ) {
212 self.feature_flags = Arc::new(feature_flags);
213 self.analysis_host.update_lru_capacity(lru_capacity);
214 self.check_watcher = create_watcher(&self.workspaces, &options);
215 self.options = options;
216 }
217
202 /// Returns a vec of libraries 218 /// Returns a vec of libraries
203 /// FIXME: better API here 219 /// FIXME: better API here
204 pub fn process_changes( 220 pub fn process_changes(
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 98f2f232f..d72ecc58f 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -5,6 +5,31 @@ import { Config } from './config';
5import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; 5import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed';
6import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; 6import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed';
7 7
8export function configToServerOptions(config: Config) {
9 return {
10 publishDecorations: !config.highlightingSemanticTokens,
11 lruCapacity: config.lruCapacity,
12
13 inlayHintsType: config.inlayHints.typeHints,
14 inlayHintsParameter: config.inlayHints.parameterHints,
15 inlayHintsChaining: config.inlayHints.chainingHints,
16 inlayHintsMaxLength: config.inlayHints.maxLength,
17
18 cargoWatchEnable: config.cargoWatchOptions.enable,
19 cargoWatchArgs: config.cargoWatchOptions.arguments,
20 cargoWatchCommand: config.cargoWatchOptions.command,
21 cargoWatchAllTargets: config.cargoWatchOptions.allTargets,
22
23 excludeGlobs: config.excludeGlobs,
24 useClientWatching: config.useClientWatching,
25 featureFlags: config.featureFlags,
26 withSysroot: config.withSysroot,
27 cargoFeatures: config.cargoFeatures,
28 rustfmtArgs: config.rustfmtArgs,
29 vscodeLldb: vscode.extensions.getExtension("vadimcn.vscode-lldb") != null,
30 };
31}
32
8export async function createClient(config: Config, serverPath: string): Promise<lc.LanguageClient> { 33export async function createClient(config: Config, serverPath: string): Promise<lc.LanguageClient> {
9 // '.' Is the fallback if no folder is open 34 // '.' Is the fallback if no folder is open
10 // TODO?: Workspace folders support Uri's (eg: file://test.txt). 35 // TODO?: Workspace folders support Uri's (eg: file://test.txt).
@@ -22,32 +47,10 @@ export async function createClient(config: Config, serverPath: string): Promise<
22 const traceOutputChannel = vscode.window.createOutputChannel( 47 const traceOutputChannel = vscode.window.createOutputChannel(
23 'Rust Analyzer Language Server Trace', 48 'Rust Analyzer Language Server Trace',
24 ); 49 );
25 const cargoWatchOpts = config.cargoWatchOptions;
26 50
27 const clientOptions: lc.LanguageClientOptions = { 51 const clientOptions: lc.LanguageClientOptions = {
28 documentSelector: [{ scheme: 'file', language: 'rust' }], 52 documentSelector: [{ scheme: 'file', language: 'rust' }],
29 initializationOptions: { 53 initializationOptions: configToServerOptions(config),
30 publishDecorations: !config.highlightingSemanticTokens,
31 lruCapacity: config.lruCapacity,
32
33 inlayHintsType: config.inlayHints.typeHints,
34 inlayHintsParameter: config.inlayHints.parameterHints,
35 inlayHintsChaining: config.inlayHints.chainingHints,
36 inlayHintsMaxLength: config.inlayHints.maxLength,
37
38 cargoWatchEnable: cargoWatchOpts.enable,
39 cargoWatchArgs: cargoWatchOpts.arguments,
40 cargoWatchCommand: cargoWatchOpts.command,
41 cargoWatchAllTargets: cargoWatchOpts.allTargets,
42
43 excludeGlobs: config.excludeGlobs,
44 useClientWatching: config.useClientWatching,
45 featureFlags: config.featureFlags,
46 withSysroot: config.withSysroot,
47 cargoFeatures: config.cargoFeatures,
48 rustfmtArgs: config.rustfmtArgs,
49 vscodeLldb: vscode.extensions.getExtension("vadimcn.vscode-lldb") != null,
50 },
51 traceOutputChannel, 54 traceOutputChannel,
52 middleware: { 55 middleware: {
53 // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576 56 // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index e77462c1b..501997fef 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -12,9 +12,9 @@ export class Config {
12 private readonly requiresReloadOpts = [ 12 private readonly requiresReloadOpts = [
13 "serverPath", 13 "serverPath",
14 "cargoFeatures", 14 "cargoFeatures",
15 "cargo-watch", 15 "excludeGlobs",
16 "highlighting.semanticTokens", 16 "useClientWatching",
17 "inlayHints", 17 "highlighting",
18 "updates.channel", 18 "updates.channel",
19 ] 19 ]
20 .map(opt => `${this.rootSection}.${opt}`); 20 .map(opt => `${this.rootSection}.${opt}`);
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 84c170ea8..d2f49cd23 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -2,7 +2,7 @@ import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3 3
4import { Config } from './config'; 4import { Config } from './config';
5import { createClient } from './client'; 5import { createClient, configToServerOptions } from './client';
6import { isRustEditor, RustEditor } from './util'; 6import { isRustEditor, RustEditor } from './util';
7 7
8export class Ctx { 8export class Ctx {
@@ -20,6 +20,7 @@ export class Ctx {
20 const res = new Ctx(config, extCtx, client, serverPath); 20 const res = new Ctx(config, extCtx, client, serverPath);
21 res.pushCleanup(client.start()); 21 res.pushCleanup(client.start());
22 await client.onReady(); 22 await client.onReady();
23 client.onRequest('workspace/configuration', _ => [configToServerOptions(config)]);
23 return res; 24 return res;
24 } 25 }
25 26
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index 542d1f367..6a8bd942e 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -17,7 +17,11 @@ export function activateInlayHints(ctx: Ctx) {
17 ) { 17 ) {
18 return this.dispose(); 18 return this.dispose();
19 } 19 }
20 if (!this.updater) this.updater = new HintsUpdater(ctx); 20 if (this.updater) {
21 this.updater.syncCacheAndRenderHints();
22 } else {
23 this.updater = new HintsUpdater(ctx);
24 }
21 }, 25 },
22 dispose() { 26 dispose() {
23 this.updater?.dispose(); 27 this.updater?.dispose();
@@ -124,7 +128,7 @@ class HintsUpdater implements Disposable {
124 this.syncCacheAndRenderHints(); 128 this.syncCacheAndRenderHints();
125 } 129 }
126 130
127 private syncCacheAndRenderHints() { 131 syncCacheAndRenderHints() {
128 // FIXME: make inlayHints request pass an array of files? 132 // FIXME: make inlayHints request pass an array of files?
129 this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => { 133 this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => {
130 if (!hints) return; 134 if (!hints) return;
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 980ed925b..a46dbde33 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -91,6 +91,12 @@ export async function activate(context: vscode.ExtensionContext) {
91 activateHighlighting(ctx); 91 activateHighlighting(ctx);
92 } 92 }
93 activateInlayHints(ctx); 93 activateInlayHints(ctx);
94
95 vscode.workspace.onDidChangeConfiguration(
96 _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }),
97 null,
98 ctx.subscriptions,
99 );
94} 100}
95 101
96export async function deactivate() { 102export async function deactivate() {