diff options
Diffstat (limited to 'crates/rust-analyzer/src/main_loop.rs')
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 101 |
1 files changed, 59 insertions, 42 deletions
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index e88f16cc1..a5655116b 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | //! requests/replies and notifications back to the client. | 2 | //! requests/replies and notifications back to the client. |
3 | use std::{ | 3 | use std::{ |
4 | env, fmt, | 4 | env, fmt, |
5 | sync::Arc, | ||
5 | time::{Duration, Instant}, | 6 | time::{Duration, Instant}, |
6 | }; | 7 | }; |
7 | 8 | ||
@@ -12,6 +13,7 @@ use ide::{Canceled, FileId}; | |||
12 | use ide_db::base_db::VfsPath; | 13 | use ide_db::base_db::VfsPath; |
13 | use lsp_server::{Connection, Notification, Request, Response}; | 14 | use lsp_server::{Connection, Notification, Request, Response}; |
14 | use lsp_types::notification::Notification as _; | 15 | use lsp_types::notification::Notification as _; |
16 | use project_model::BuildDataCollector; | ||
15 | use vfs::ChangeKind; | 17 | use vfs::ChangeKind; |
16 | 18 | ||
17 | use crate::{ | 19 | use crate::{ |
@@ -19,7 +21,7 @@ use crate::{ | |||
19 | dispatch::{NotificationDispatcher, RequestDispatcher}, | 21 | dispatch::{NotificationDispatcher, RequestDispatcher}, |
20 | document::DocumentData, | 22 | document::DocumentData, |
21 | from_proto, | 23 | from_proto, |
22 | global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, | 24 | global_state::{file_id_to_url, url_to_file_id, GlobalState}, |
23 | handlers, lsp_ext, | 25 | handlers, lsp_ext, |
24 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, | 26 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, |
25 | reload::{BuildDataProgress, ProjectWorkspaceProgress}, | 27 | reload::{BuildDataProgress, ProjectWorkspaceProgress}, |
@@ -187,7 +189,7 @@ impl GlobalState { | |||
187 | log::info!("task queue len: {}", task_queue_len); | 189 | log::info!("task queue len: {}", task_queue_len); |
188 | } | 190 | } |
189 | 191 | ||
190 | let mut new_status = self.status; | 192 | let was_quiescent = self.is_quiescent(); |
191 | match event { | 193 | match event { |
192 | Event::Lsp(msg) => match msg { | 194 | Event::Lsp(msg) => match msg { |
193 | lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, | 195 | lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, |
@@ -227,11 +229,24 @@ impl GlobalState { | |||
227 | (Progress::Report, Some(msg)) | 229 | (Progress::Report, Some(msg)) |
228 | } | 230 | } |
229 | ProjectWorkspaceProgress::End(workspaces) => { | 231 | ProjectWorkspaceProgress::End(workspaces) => { |
230 | self.fetch_workspaces_completed(); | 232 | self.fetch_workspaces_completed(workspaces); |
231 | self.switch_workspaces(workspaces, None); | 233 | |
234 | let old = Arc::clone(&self.workspaces); | ||
235 | self.switch_workspaces(); | ||
236 | let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); | ||
237 | |||
238 | if self.config.run_build_scripts() && workspaces_updated { | ||
239 | let mut collector = BuildDataCollector::default(); | ||
240 | for ws in self.workspaces.iter() { | ||
241 | ws.collect_build_data_configs(&mut collector); | ||
242 | } | ||
243 | self.fetch_build_data_request(collector) | ||
244 | } | ||
245 | |||
232 | (Progress::End, None) | 246 | (Progress::End, None) |
233 | } | 247 | } |
234 | }; | 248 | }; |
249 | |||
235 | self.report_progress("fetching", state, msg, None); | 250 | self.report_progress("fetching", state, msg, None); |
236 | } | 251 | } |
237 | Task::FetchBuildData(progress) => { | 252 | Task::FetchBuildData(progress) => { |
@@ -240,19 +255,21 @@ impl GlobalState { | |||
240 | BuildDataProgress::Report(msg) => { | 255 | BuildDataProgress::Report(msg) => { |
241 | (Some(Progress::Report), Some(msg)) | 256 | (Some(Progress::Report), Some(msg)) |
242 | } | 257 | } |
243 | BuildDataProgress::End(collector) => { | 258 | BuildDataProgress::End(build_data_result) => { |
244 | self.fetch_build_data_completed(); | 259 | self.fetch_build_data_completed(build_data_result); |
245 | let workspaces = | 260 | |
246 | (*self.workspaces).clone().into_iter().map(Ok).collect(); | 261 | self.switch_workspaces(); |
247 | self.switch_workspaces(workspaces, Some(collector)); | 262 | |
248 | (Some(Progress::End), None) | 263 | (Some(Progress::End), None) |
249 | } | 264 | } |
250 | }; | 265 | }; |
266 | |||
251 | if let Some(state) = state { | 267 | if let Some(state) = state { |
252 | self.report_progress("loading", state, msg, None); | 268 | self.report_progress("loading", state, msg, None); |
253 | } | 269 | } |
254 | } | 270 | } |
255 | } | 271 | } |
272 | |||
256 | // Coalesce multiple task events into one loop turn | 273 | // Coalesce multiple task events into one loop turn |
257 | task = match self.task_pool.receiver.try_recv() { | 274 | task = match self.task_pool.receiver.try_recv() { |
258 | Ok(task) => task, | 275 | Ok(task) => task, |
@@ -298,30 +315,25 @@ impl GlobalState { | |||
298 | } | 315 | } |
299 | vfs::loader::Message::Progress { n_total, n_done, config_version } => { | 316 | vfs::loader::Message::Progress { n_total, n_done, config_version } => { |
300 | always!(config_version <= self.vfs_config_version); | 317 | always!(config_version <= self.vfs_config_version); |
301 | if n_total == 0 { | 318 | |
302 | new_status = Status::Invalid; | 319 | self.vfs_progress_config_version = config_version; |
320 | self.vfs_progress_n_total = n_total; | ||
321 | self.vfs_progress_n_done = n_done; | ||
322 | |||
323 | let state = if n_done == 0 { | ||
324 | Progress::Begin | ||
325 | } else if n_done < n_total { | ||
326 | Progress::Report | ||
303 | } else { | 327 | } else { |
304 | let state = if n_done == 0 { | 328 | assert_eq!(n_done, n_total); |
305 | new_status = Status::Loading; | 329 | Progress::End |
306 | Progress::Begin | 330 | }; |
307 | } else if n_done < n_total { | 331 | self.report_progress( |
308 | Progress::Report | 332 | "roots scanned", |
309 | } else { | 333 | state, |
310 | assert_eq!(n_done, n_total); | 334 | Some(format!("{}/{}", n_done, n_total)), |
311 | new_status = Status::Ready { | 335 | Some(Progress::fraction(n_done, n_total)), |
312 | partial: self.config.run_build_scripts() | 336 | ) |
313 | && self.workspace_build_data.is_none() | ||
314 | || config_version < self.vfs_config_version, | ||
315 | }; | ||
316 | Progress::End | ||
317 | }; | ||
318 | self.report_progress( | ||
319 | "roots scanned", | ||
320 | state, | ||
321 | Some(format!("{}/{}", n_done, n_total)), | ||
322 | Some(Progress::fraction(n_done, n_total)), | ||
323 | ) | ||
324 | } | ||
325 | } | 337 | } |
326 | } | 338 | } |
327 | // Coalesce many VFS event into a single loop turn | 339 | // Coalesce many VFS event into a single loop turn |
@@ -397,18 +409,14 @@ impl GlobalState { | |||
397 | } | 409 | } |
398 | 410 | ||
399 | let state_changed = self.process_changes(); | 411 | let state_changed = self.process_changes(); |
400 | let prev_status = self.status; | 412 | |
401 | if prev_status != new_status { | 413 | if self.is_quiescent() && !was_quiescent { |
402 | self.transition(new_status); | ||
403 | } | ||
404 | let is_ready = matches!(self.status, Status::Ready { .. }); | ||
405 | if prev_status == Status::Loading && is_ready { | ||
406 | for flycheck in &self.flycheck { | 414 | for flycheck in &self.flycheck { |
407 | flycheck.update(); | 415 | flycheck.update(); |
408 | } | 416 | } |
409 | } | 417 | } |
410 | 418 | ||
411 | if is_ready && (state_changed || prev_status == Status::Loading) { | 419 | if self.is_quiescent() && (!was_quiescent || state_changed) { |
412 | self.update_file_notifications_on_threadpool(); | 420 | self.update_file_notifications_on_threadpool(); |
413 | 421 | ||
414 | // Refresh semantic tokens if the client supports it. | 422 | // Refresh semantic tokens if the client supports it. |
@@ -437,9 +445,13 @@ impl GlobalState { | |||
437 | } | 445 | } |
438 | } | 446 | } |
439 | 447 | ||
440 | self.fetch_workspaces_if_needed(); | 448 | if self.config.cargo_autoreload() { |
449 | self.fetch_workspaces_if_needed(); | ||
450 | } | ||
441 | self.fetch_build_data_if_needed(); | 451 | self.fetch_build_data_if_needed(); |
442 | 452 | ||
453 | self.report_new_status_if_needed(); | ||
454 | |||
443 | let loop_duration = loop_start.elapsed(); | 455 | let loop_duration = loop_start.elapsed(); |
444 | if loop_duration > Duration::from_millis(100) { | 456 | if loop_duration > Duration::from_millis(100) { |
445 | log::warn!("overly long loop turn: {:?}", loop_duration); | 457 | log::warn!("overly long loop turn: {:?}", loop_duration); |
@@ -466,7 +478,8 @@ impl GlobalState { | |||
466 | return Ok(()); | 478 | return Ok(()); |
467 | } | 479 | } |
468 | 480 | ||
469 | if self.status == Status::Loading && req.method != "shutdown" { | 481 | // Avoid flashing a bunch of unresolved references during initial load. |
482 | if self.workspaces.is_empty() && !self.is_quiescent() { | ||
470 | self.respond(lsp_server::Response::new_err( | 483 | self.respond(lsp_server::Response::new_err( |
471 | req.id, | 484 | req.id, |
472 | // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) | 485 | // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) |
@@ -477,7 +490,11 @@ impl GlobalState { | |||
477 | } | 490 | } |
478 | 491 | ||
479 | RequestDispatcher { req: Some(req), global_state: self } | 492 | RequestDispatcher { req: Some(req), global_state: self } |
480 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))? | 493 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| { |
494 | s.fetch_workspaces_request(); | ||
495 | s.fetch_workspaces_if_needed(); | ||
496 | Ok(()) | ||
497 | })? | ||
481 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? | 498 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? |
482 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? | 499 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? |
483 | .on_sync::<lsp_types::request::Shutdown>(|s, ()| { | 500 | .on_sync::<lsp_types::request::Shutdown>(|s, ()| { |