aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/reload.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-04-06 12:16:35 +0100
committerAleksey Kladov <[email protected]>2021-04-06 13:45:31 +0100
commit8fe20b19d4702fc6d6933c31abddc8539d2581f0 (patch)
tree8aca2a3aa2b059bb47cc235b1b557d4b4de93a24 /crates/rust-analyzer/src/reload.rs
parent9143e3925cd95d30af72745f25e185f65a686d32 (diff)
More robust status notifications
Diffstat (limited to 'crates/rust-analyzer/src/reload.rs')
-rw-r--r--crates/rust-analyzer/src/reload.rs119
1 files changed, 67 insertions, 52 deletions
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 5ff60c22a..301c7003b 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -9,11 +9,10 @@ use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
9 9
10use crate::{ 10use crate::{
11 config::{Config, FilesWatcher, LinkedProject}, 11 config::{Config, FilesWatcher, LinkedProject},
12 global_state::{GlobalState, Status}, 12 global_state::GlobalState,
13 lsp_ext, 13 lsp_ext,
14 main_loop::Task, 14 main_loop::Task,
15}; 15};
16use lsp_ext::StatusParams;
17 16
18#[derive(Debug)] 17#[derive(Debug)]
19pub(crate) enum ProjectWorkspaceProgress { 18pub(crate) enum ProjectWorkspaceProgress {
@@ -30,6 +29,13 @@ pub(crate) enum BuildDataProgress {
30} 29}
31 30
32impl GlobalState { 31impl GlobalState {
32 pub(crate) fn is_quiescent(&self) -> bool {
33 !(self.fetch_workspaces_queue.op_in_progress()
34 || self.fetch_build_data_queue.op_in_progress()
35 || self.vfs_progress_config_version < self.vfs_config_version
36 || self.vfs_progress_n_done < self.vfs_progress_n_total)
37 }
38
33 pub(crate) fn update_configuration(&mut self, config: Config) { 39 pub(crate) fn update_configuration(&mut self, config: Config) {
34 let _p = profile::span("GlobalState::update_configuration"); 40 let _p = profile::span("GlobalState::update_configuration");
35 let old_config = mem::replace(&mut self.config, Arc::new(config)); 41 let old_config = mem::replace(&mut self.config, Arc::new(config));
@@ -46,17 +52,13 @@ impl GlobalState {
46 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { 52 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) {
47 return; 53 return;
48 } 54 }
49 match self.status {
50 Status::Loading | Status::NeedsReload => return,
51 Status::Ready { .. } | Status::Invalid => (),
52 }
53 log::info!( 55 log::info!(
54 "Reloading workspace because of the following changes: {}", 56 "Requesting workspace reload because of the following changes: {}",
55 itertools::join( 57 itertools::join(
56 changes 58 changes
57 .iter() 59 .iter()
58 .filter(|(path, kind)| is_interesting(path, *kind)) 60 .filter(|(path, kind)| is_interesting(path, *kind))
59 .map(|(path, kind)| format!("{}/{:?}", path.display(), kind)), 61 .map(|(path, kind)| format!("{}: {:?}", path.display(), kind)),
60 ", " 62 ", "
61 ) 63 )
62 ); 64 );
@@ -97,19 +99,31 @@ impl GlobalState {
97 false 99 false
98 } 100 }
99 } 101 }
100 pub(crate) fn transition(&mut self, new_status: Status) { 102 pub(crate) fn report_new_status_if_needed(&mut self) {
101 self.status = new_status; 103 if !self.config.server_status_notification() {
102 if self.config.status_notification() { 104 return;
103 let lsp_status = match new_status { 105 }
104 Status::Loading => lsp_ext::Status::Loading, 106
105 Status::Ready { partial: true } => lsp_ext::Status::ReadyPartial, 107 let mut status = lsp_ext::ServerStatusParams {
106 Status::Ready { partial: false } => lsp_ext::Status::Ready, 108 health: lsp_ext::Health::Ok,
107 Status::Invalid => lsp_ext::Status::Invalid, 109 quiescent: self.is_quiescent(),
108 Status::NeedsReload => lsp_ext::Status::NeedsReload, 110 message: None,
109 }; 111 };
110 self.send_notification::<lsp_ext::StatusNotification>(StatusParams { 112 if !self.config.cargo_autoreload()
111 status: lsp_status, 113 && self.is_quiescent()
112 }); 114 && self.fetch_workspaces_queue.op_requested()
115 {
116 status.health = lsp_ext::Health::Warning;
117 status.message = Some("Workspace reload required".to_string())
118 }
119 if let Some(error) = self.loading_error() {
120 status.health = lsp_ext::Health::Error;
121 status.message = Some(format!("Workspace reload failed: {}", error))
122 }
123
124 if self.last_reported_status.as_ref() != Some(&status) {
125 self.last_reported_status = Some(status.clone());
126 self.send_notification::<lsp_ext::ServerStatusNotification>(status);
113 } 127 }
114 } 128 }
115 129
@@ -201,45 +215,28 @@ impl GlobalState {
201 215
202 pub(crate) fn switch_workspaces(&mut self) { 216 pub(crate) fn switch_workspaces(&mut self) {
203 let _p = profile::span("GlobalState::switch_workspaces"); 217 let _p = profile::span("GlobalState::switch_workspaces");
204 let workspaces = self.fetch_workspaces_queue.last_op_result(); 218 log::info!("will switch workspaces");
205 log::info!("will switch workspaces: {:?}", workspaces); 219
220 if let Some(error_message) = self.loading_error() {
221 log::error!("failed to switch workspaces: {}", error_message);
222 self.show_message(lsp_types::MessageType::Error, error_message);
223 if !self.workspaces.is_empty() {
224 return;
225 }
226 }
206 227
207 let mut error_message = None; 228 let workspaces = self
208 let workspaces = workspaces 229 .fetch_workspaces_queue
230 .last_op_result()
209 .iter() 231 .iter()
210 .filter_map(|res| match res { 232 .filter_map(|res| res.as_ref().ok().cloned())
211 Ok(it) => Some(it.clone()),
212 Err(err) => {
213 log::error!("failed to load workspace: {:#}", err);
214 let message = error_message.get_or_insert_with(String::new);
215 stdx::format_to!(
216 message,
217 "rust-analyzer failed to load workspace: {:#}\n",
218 err
219 );
220 None
221 }
222 })
223 .collect::<Vec<_>>(); 233 .collect::<Vec<_>>();
224 234
225 let workspace_build_data = match self.fetch_build_data_queue.last_op_result() { 235 let workspace_build_data = match self.fetch_build_data_queue.last_op_result() {
226 Some(Ok(it)) => Some(it.clone()), 236 Some(Ok(it)) => Some(it.clone()),
227 None => None, 237 None | Some(Err(_)) => None,
228 Some(Err(err)) => {
229 log::error!("failed to fetch build data: {:#}", err);
230 let message = error_message.get_or_insert_with(String::new);
231 stdx::format_to!(message, "rust-analyzer failed to fetch build data: {:#}\n", err);
232 None
233 }
234 }; 238 };
235 239
236 if let Some(error_message) = error_message {
237 self.show_message(lsp_types::MessageType::Error, error_message);
238 if !self.workspaces.is_empty() {
239 return;
240 }
241 }
242
243 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data { 240 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data {
244 return; 241 return;
245 } 242 }
@@ -346,6 +343,24 @@ impl GlobalState {
346 log::info!("did switch workspaces"); 343 log::info!("did switch workspaces");
347 } 344 }
348 345
346 fn loading_error(&self) -> Option<String> {
347 let mut message = None;
348
349 for ws in self.fetch_workspaces_queue.last_op_result() {
350 if let Err(err) = ws {
351 let message = message.get_or_insert_with(String::new);
352 stdx::format_to!(message, "rust-analyzer failed to load workspace: {:#}\n", err);
353 }
354 }
355
356 if let Some(Err(err)) = self.fetch_build_data_queue.last_op_result() {
357 let message = message.get_or_insert_with(String::new);
358 stdx::format_to!(message, "rust-analyzer failed to fetch build data: {:#}\n", err);
359 }
360
361 message
362 }
363
349 fn reload_flycheck(&mut self) { 364 fn reload_flycheck(&mut self) {
350 let _p = profile::span("GlobalState::reload_flycheck"); 365 let _p = profile::span("GlobalState::reload_flycheck");
351 let config = match self.config.flycheck() { 366 let config = match self.config.flycheck() {