aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/main_loop.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/rust-analyzer/src/main_loop.rs')
-rw-r--r--crates/rust-analyzer/src/main_loop.rs101
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.
3use std::{ 3use 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};
12use ide_db::base_db::VfsPath; 13use ide_db::base_db::VfsPath;
13use lsp_server::{Connection, Notification, Request, Response}; 14use lsp_server::{Connection, Notification, Request, Response};
14use lsp_types::notification::Notification as _; 15use lsp_types::notification::Notification as _;
16use project_model::BuildDataCollector;
15use vfs::ChangeKind; 17use vfs::ChangeKind;
16 18
17use crate::{ 19use 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, ()| {