diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-30 13:45:49 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-30 13:45:49 +0100 |
commit | 671926ac93f0ff921758a919eaf87c056979189f (patch) | |
tree | 111c2cc751cb7fcca38eb7518e1d39af394ee243 | |
parent | 9e12b9e6fdc03ea6bc35a88cfb5d5d6751672ec8 (diff) | |
parent | 4c897d8d2dd047e0906d585318866c9ae7a21610 (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.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide_db/src/lib.rs | 12 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 168 | ||||
-rw-r--r-- | crates/rust-analyzer/src/req.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/world.rs | 46 | ||||
-rw-r--r-- | editors/code/src/client.ts | 49 | ||||
-rw-r--r-- | editors/code/src/config.ts | 6 | ||||
-rw-r--r-- | editors/code/src/ctx.ts | 3 | ||||
-rw-r--r-- | editors/code/src/inlay_hints.ts | 8 | ||||
-rw-r--r-- | editors/code/src/main.ts | 6 |
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 | ||
126 | impl salsa::ParallelDatabase for RootDatabase { | 130 | impl 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::{ | |||
17 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; | 17 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; |
18 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; | 18 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; |
19 | use lsp_types::{ | 19 | use lsp_types::{ |
20 | ClientCapabilities, NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, | 20 | ClientCapabilities, NumberOrString, TextDocumentClientCapabilities, WorkDoneProgress, |
21 | WorkDoneProgressCreateParams, WorkDoneProgressEnd, WorkDoneProgressReport, | 21 | WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd, |
22 | WorkDoneProgressReport, | ||
22 | }; | 23 | }; |
23 | use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; | 24 | use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; |
24 | use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId}; | 25 | use 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 | }; |
44 | use req::ConfigurationParams; | ||
43 | 45 | ||
44 | #[derive(Debug)] | 46 | #[derive(Debug)] |
45 | pub struct LspError { | 47 | pub struct LspError { |
@@ -63,6 +65,53 @@ impl fmt::Display for LspError { | |||
63 | 65 | ||
64 | impl Error for LspError {} | 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 | pub fn main_loop( | 115 | pub 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 | ||
345 | impl LoopState { | 353 | impl 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( | |||
569 | fn on_notification( | 606 | fn 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 | ||
7 | pub use lsp_types::{ | 7 | pub 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::{ | |||
31 | use ra_db::ExternSourceId; | 31 | use ra_db::ExternSourceId; |
32 | use rustc_hash::{FxHashMap, FxHashSet}; | 32 | use rustc_hash::{FxHashMap, FxHashSet}; |
33 | 33 | ||
34 | fn 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)] |
35 | pub struct Options { | 53 | pub 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'; | |||
5 | import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; | 5 | import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; |
6 | import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; | 6 | import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; |
7 | 7 | ||
8 | export 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 | |||
8 | export async function createClient(config: Config, serverPath: string): Promise<lc.LanguageClient> { | 33 | export 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'; | |||
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | 3 | ||
4 | import { Config } from './config'; | 4 | import { Config } from './config'; |
5 | import { createClient } from './client'; | 5 | import { createClient, configToServerOptions } from './client'; |
6 | import { isRustEditor, RustEditor } from './util'; | 6 | import { isRustEditor, RustEditor } from './util'; |
7 | 7 | ||
8 | export class Ctx { | 8 | export 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 | ||
96 | export async function deactivate() { | 102 | export async function deactivate() { |