diff options
-rw-r--r-- | crates/base_db/src/input.rs | 28 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ide/src/prime_caches.rs | 43 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 42 | ||||
-rw-r--r-- | crates/rust-analyzer/src/thread_pool.rs | 11 |
5 files changed, 119 insertions, 13 deletions
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index c330314d4..215ac4b41 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -221,6 +221,34 @@ impl CrateGraph { | |||
221 | deps.into_iter() | 221 | deps.into_iter() |
222 | } | 222 | } |
223 | 223 | ||
224 | /// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate | ||
225 | /// come before the crate itself). | ||
226 | pub fn crates_in_topological_order(&self) -> Vec<CrateId> { | ||
227 | let mut res = Vec::new(); | ||
228 | let mut visited = FxHashSet::default(); | ||
229 | |||
230 | for krate in self.arena.keys().copied() { | ||
231 | go(self, &mut visited, &mut res, krate); | ||
232 | } | ||
233 | |||
234 | return res; | ||
235 | |||
236 | fn go( | ||
237 | graph: &CrateGraph, | ||
238 | visited: &mut FxHashSet<CrateId>, | ||
239 | res: &mut Vec<CrateId>, | ||
240 | source: CrateId, | ||
241 | ) { | ||
242 | if !visited.insert(source) { | ||
243 | return; | ||
244 | } | ||
245 | for dep in graph[source].dependencies.iter() { | ||
246 | go(graph, visited, res, dep.crate_id) | ||
247 | } | ||
248 | res.push(source) | ||
249 | } | ||
250 | } | ||
251 | |||
224 | // FIXME: this only finds one crate with the given root; we could have multiple | 252 | // FIXME: this only finds one crate with the given root; we could have multiple |
225 | pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { | 253 | pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { |
226 | let (&crate_id, _) = | 254 | let (&crate_id, _) = |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 686cee3a1..aaf9b3b4b 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -77,6 +77,7 @@ pub use crate::{ | |||
77 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, | 77 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, |
78 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, | 78 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, |
79 | markup::Markup, | 79 | markup::Markup, |
80 | prime_caches::PrimeCachesProgress, | ||
80 | references::{ | 81 | references::{ |
81 | Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError, | 82 | Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError, |
82 | }, | 83 | }, |
@@ -223,8 +224,11 @@ impl Analysis { | |||
223 | self.with_db(|db| status::status(&*db, file_id)) | 224 | self.with_db(|db| status::status(&*db, file_id)) |
224 | } | 225 | } |
225 | 226 | ||
226 | pub fn prime_caches(&self, files: Vec<FileId>) -> Cancelable<()> { | 227 | pub fn prime_caches<F>(&self, cb: F) -> Cancelable<()> |
227 | self.with_db(|db| prime_caches::prime_caches(db, files)) | 228 | where |
229 | F: Fn(PrimeCachesProgress) + Sync + std::panic::UnwindSafe, | ||
230 | { | ||
231 | self.with_db(move |db| prime_caches::prime_caches(db, &cb)) | ||
228 | } | 232 | } |
229 | 233 | ||
230 | /// Gets the text of the source file. | 234 | /// Gets the text of the source file. |
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs index c5ab5a1d8..9687c2734 100644 --- a/crates/ide/src/prime_caches.rs +++ b/crates/ide/src/prime_caches.rs | |||
@@ -3,10 +3,45 @@ | |||
3 | //! request takes longer to compute. This modules implemented prepopulating of | 3 | //! request takes longer to compute. This modules implemented prepopulating of |
4 | //! various caches, it's not really advanced at the moment. | 4 | //! various caches, it's not really advanced at the moment. |
5 | 5 | ||
6 | use crate::{FileId, RootDatabase}; | 6 | use base_db::SourceDatabase; |
7 | use hir::db::DefDatabase; | ||
7 | 8 | ||
8 | pub(crate) fn prime_caches(db: &RootDatabase, files: Vec<FileId>) { | 9 | use crate::RootDatabase; |
9 | for file in files { | 10 | |
10 | let _ = crate::syntax_highlighting::highlight(db, file, None, false); | 11 | #[derive(Debug)] |
12 | pub enum PrimeCachesProgress { | ||
13 | Started, | ||
14 | /// We started indexing a crate. | ||
15 | StartedOnCrate { | ||
16 | on_crate: String, | ||
17 | n_done: usize, | ||
18 | n_total: usize, | ||
19 | }, | ||
20 | /// We finished indexing all crates. | ||
21 | Finished, | ||
22 | } | ||
23 | |||
24 | pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) + Sync)) { | ||
25 | let _p = profile::span("prime_caches"); | ||
26 | let graph = db.crate_graph(); | ||
27 | let topo = &graph.crates_in_topological_order(); | ||
28 | |||
29 | cb(PrimeCachesProgress::Started); | ||
30 | |||
31 | // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that. | ||
32 | // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks | ||
33 | // cancellation, so we cannot use rayon. | ||
34 | for (i, krate) in topo.iter().enumerate() { | ||
35 | let crate_name = | ||
36 | graph[*krate].declaration_name.as_ref().map(ToString::to_string).unwrap_or_default(); | ||
37 | |||
38 | cb(PrimeCachesProgress::StartedOnCrate { | ||
39 | on_crate: crate_name, | ||
40 | n_done: i, | ||
41 | n_total: topo.len(), | ||
42 | }); | ||
43 | db.crate_def_map(*krate); | ||
11 | } | 44 | } |
45 | |||
46 | cb(PrimeCachesProgress::Finished); | ||
12 | } | 47 | } |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 06b38d99c..fb18f9014 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -7,6 +7,7 @@ use std::{ | |||
7 | 7 | ||
8 | use base_db::VfsPath; | 8 | use base_db::VfsPath; |
9 | use crossbeam_channel::{select, Receiver}; | 9 | use crossbeam_channel::{select, Receiver}; |
10 | use ide::PrimeCachesProgress; | ||
10 | use ide::{Canceled, FileId}; | 11 | use ide::{Canceled, FileId}; |
11 | use lsp_server::{Connection, Notification, Request, Response}; | 12 | use lsp_server::{Connection, Notification, Request, Response}; |
12 | use lsp_types::notification::Notification as _; | 13 | use lsp_types::notification::Notification as _; |
@@ -61,7 +62,7 @@ pub(crate) enum Task { | |||
61 | Response(Response), | 62 | Response(Response), |
62 | Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), | 63 | Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), |
63 | Workspaces(Vec<anyhow::Result<ProjectWorkspace>>), | 64 | Workspaces(Vec<anyhow::Result<ProjectWorkspace>>), |
64 | Unit, | 65 | PrimeCaches(PrimeCachesProgress), |
65 | } | 66 | } |
66 | 67 | ||
67 | impl fmt::Debug for Event { | 68 | impl fmt::Debug for Event { |
@@ -197,7 +198,28 @@ impl GlobalState { | |||
197 | } | 198 | } |
198 | } | 199 | } |
199 | Task::Workspaces(workspaces) => self.switch_workspaces(workspaces), | 200 | Task::Workspaces(workspaces) => self.switch_workspaces(workspaces), |
200 | Task::Unit => (), | 201 | Task::PrimeCaches(progress) => { |
202 | let (state, message, fraction); | ||
203 | match progress { | ||
204 | PrimeCachesProgress::Started => { | ||
205 | state = Progress::Begin; | ||
206 | message = None; | ||
207 | fraction = 0.0; | ||
208 | } | ||
209 | PrimeCachesProgress::StartedOnCrate { on_crate, n_done, n_total } => { | ||
210 | state = Progress::Report; | ||
211 | message = Some(format!("{}/{} ({})", n_done, n_total, on_crate)); | ||
212 | fraction = Progress::fraction(n_done, n_total); | ||
213 | } | ||
214 | PrimeCachesProgress::Finished => { | ||
215 | state = Progress::End; | ||
216 | message = None; | ||
217 | fraction = 1.0; | ||
218 | } | ||
219 | }; | ||
220 | |||
221 | self.report_progress("indexing", state, message, Some(fraction)); | ||
222 | } | ||
201 | }, | 223 | }, |
202 | Event::Vfs(mut task) => { | 224 | Event::Vfs(mut task) => { |
203 | let _p = profile::span("GlobalState::handle_event/vfs"); | 225 | let _p = profile::span("GlobalState::handle_event/vfs"); |
@@ -573,12 +595,18 @@ impl GlobalState { | |||
573 | Task::Diagnostics(diagnostics) | 595 | Task::Diagnostics(diagnostics) |
574 | }) | 596 | }) |
575 | } | 597 | } |
576 | self.task_pool.handle.spawn({ | 598 | self.task_pool.handle.spawn_with_sender({ |
577 | let subs = subscriptions; | ||
578 | let snap = self.snapshot(); | 599 | let snap = self.snapshot(); |
579 | move || { | 600 | move |sender| { |
580 | snap.analysis.prime_caches(subs).unwrap_or_else(|_: Canceled| ()); | 601 | snap.analysis |
581 | Task::Unit | 602 | .prime_caches(|progress| { |
603 | sender.send(Task::PrimeCaches(progress)).unwrap(); | ||
604 | }) | ||
605 | .unwrap_or_else(|_: Canceled| { | ||
606 | // Pretend that we're done, so that the progress bar is removed. Otherwise | ||
607 | // the editor may complain about it already existing. | ||
608 | sender.send(Task::PrimeCaches(PrimeCachesProgress::Finished)).unwrap() | ||
609 | }); | ||
582 | } | 610 | } |
583 | }); | 611 | }); |
584 | } | 612 | } |
diff --git a/crates/rust-analyzer/src/thread_pool.rs b/crates/rust-analyzer/src/thread_pool.rs index 4fa502925..833893739 100644 --- a/crates/rust-analyzer/src/thread_pool.rs +++ b/crates/rust-analyzer/src/thread_pool.rs | |||
@@ -23,6 +23,17 @@ impl<T> TaskPool<T> { | |||
23 | }) | 23 | }) |
24 | } | 24 | } |
25 | 25 | ||
26 | pub(crate) fn spawn_with_sender<F>(&mut self, task: F) | ||
27 | where | ||
28 | F: FnOnce(Sender<T>) + Send + 'static, | ||
29 | T: Send + 'static, | ||
30 | { | ||
31 | self.inner.execute({ | ||
32 | let sender = self.sender.clone(); | ||
33 | move || task(sender) | ||
34 | }) | ||
35 | } | ||
36 | |||
26 | pub(crate) fn len(&self) -> usize { | 37 | pub(crate) fn len(&self) -> usize { |
27 | self.inner.queued_count() | 38 | self.inner.queued_count() |
28 | } | 39 | } |