about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/project_model/src/cargo_workspace.rs26
-rw-r--r--crates/project_model/src/workspace.rs22
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs1
-rw-r--r--crates/rust-analyzer/src/main_loop.rs12
-rw-r--r--crates/rust-analyzer/src/reload.rs34
5 files changed, 77 insertions, 18 deletions
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index 0e667954244..2ee4e88b2e0 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -3,9 +3,10 @@
 use std::{
     convert::TryInto,
     ffi::OsStr,
+    io::BufReader,
     ops,
     path::{Path, PathBuf},
-    process::Command,
+    process::{Command, Stdio},
 };
 
 use anyhow::{Context, Result};
@@ -15,6 +16,7 @@ use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}
 use itertools::Itertools;
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
+use stdx::JodChild;
 
 use crate::cfg_flag::CfgFlag;
 use crate::utf8_stdout;
@@ -171,6 +173,7 @@ impl CargoWorkspace {
     pub fn from_cargo_metadata(
         cargo_toml: &AbsPath,
         config: &CargoConfig,
+        progress: &dyn Fn(String),
     ) -> Result<CargoWorkspace> {
         let mut meta = MetadataCommand::new();
         meta.cargo_path(toolchain::cargo());
@@ -220,6 +223,9 @@ impl CargoWorkspace {
             meta.other_options(vec![String::from("--filter-platform"), target]);
         }
 
+        // FIXME: Currently MetadataCommand is not based on parse_stream,
+        // So we just report it as a whole
+        progress("metadata".to_string());
         let mut meta = meta.exec().with_context(|| {
             let cwd: Option<AbsPathBuf> =
                 std::env::current_dir().ok().and_then(|p| p.try_into().ok());
@@ -243,7 +249,7 @@ impl CargoWorkspace {
         let mut envs = FxHashMap::default();
         let mut proc_macro_dylib_paths = FxHashMap::default();
         if config.load_out_dirs_from_check {
-            let resources = load_extern_resources(cargo_toml, config)?;
+            let resources = load_extern_resources(cargo_toml, config, progress)?;
             out_dir_by_id = resources.out_dirs;
             cfgs = resources.cfgs;
             envs = resources.env;
@@ -368,6 +374,7 @@ pub(crate) struct ExternResources {
 pub(crate) fn load_extern_resources(
     cargo_toml: &Path,
     cargo_features: &CargoConfig,
+    progress: &dyn Fn(String),
 ) -> Result<ExternResources> {
     let mut cmd = Command::new(toolchain::cargo());
     cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
@@ -395,11 +402,14 @@ pub(crate) fn load_extern_resources(
         }
     }
 
-    let output = cmd.output()?;
+    cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
 
-    let mut res = ExternResources::default();
+    let mut child = cmd.spawn().map(JodChild)?;
+    let child_stdout = child.stdout.take().unwrap();
+    let stdout = BufReader::new(child_stdout);
 
-    for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) {
+    let mut res = ExternResources::default();
+    for message in cargo_metadata::Message::parse_stream(stdout) {
         if let Ok(message) = message {
             match message {
                 Message::BuildScriptExecuted(BuildScript {
@@ -432,6 +442,8 @@ pub(crate) fn load_extern_resources(
                     res.env.insert(package_id, env);
                 }
                 Message::CompilerArtifact(message) => {
+                    progress(format!("metadata {}", message.target.name));
+
                     if message.target.kind.contains(&"proc-macro".to_string()) {
                         let package_id = message.package_id;
                         // Skip rmeta file
@@ -442,7 +454,9 @@ pub(crate) fn load_extern_resources(
                         }
                     }
                 }
-                Message::CompilerMessage(_) => (),
+                Message::CompilerMessage(message) => {
+                    progress(message.target.name.clone());
+                }
                 Message::Unknown => (),
                 Message::BuildFinished(_) => {}
                 Message::TextLine(_) => {}
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 68a235ce3c3..06a0be284a0 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -64,7 +64,11 @@ impl fmt::Debug for ProjectWorkspace {
 }
 
 impl ProjectWorkspace {
-    pub fn load(manifest: ProjectManifest, config: &CargoConfig) -> Result<ProjectWorkspace> {
+    pub fn load(
+        manifest: ProjectManifest,
+        config: &CargoConfig,
+        progress: &dyn Fn(String),
+    ) -> Result<ProjectWorkspace> {
         let res = match manifest {
             ProjectManifest::ProjectJson(project_json) => {
                 let file = fs::read_to_string(&project_json).with_context(|| {
@@ -84,15 +88,14 @@ impl ProjectWorkspace {
                     cmd
                 })?;
 
-                let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config).with_context(
-                    || {
+                let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress)
+                    .with_context(|| {
                         format!(
                             "Failed to read Cargo metadata from Cargo.toml file {}, {}",
                             cargo_toml.display(),
                             cargo_version
                         )
-                    },
-                )?;
+                    })?;
                 let sysroot = if config.no_sysroot {
                     Sysroot::default()
                 } else {
@@ -105,9 +108,12 @@ impl ProjectWorkspace {
                 };
 
                 let rustc = if let Some(rustc_dir) = &config.rustc_source {
-                    Some(CargoWorkspace::from_cargo_metadata(&rustc_dir, config).with_context(
-                        || format!("Failed to read Cargo metadata for Rust sources"),
-                    )?)
+                    Some(
+                        CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
+                            .with_context(|| {
+                                format!("Failed to read Cargo metadata for Rust sources")
+                            })?,
+                    )
                 } else {
                     None
                 };
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index e5ab6c73bba..31a16ca4647 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -21,6 +21,7 @@ pub fn load_cargo(
     let ws = ProjectWorkspace::load(
         root,
         &CargoConfig { load_out_dirs_from_check, ..Default::default() },
+        &|_| {},
     )?;
 
     let (sender, receiver) = unbounded();
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 7ac6acf708d..22ee96775cb 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -22,6 +22,7 @@ use crate::{
     global_state::{file_id_to_url, url_to_file_id, GlobalState, Status},
     handlers, lsp_ext,
     lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
+    reload::ProjectWorkspaceProgress,
     Result,
 };
 
@@ -63,6 +64,7 @@ pub(crate) enum Task {
     Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
     Workspaces(Vec<anyhow::Result<ProjectWorkspace>>),
     PrimeCaches(PrimeCachesProgress),
+    FetchWorkspace(ProjectWorkspaceProgress),
 }
 
 impl fmt::Debug for Event {
@@ -216,6 +218,16 @@ impl GlobalState {
                             }
                             PrimeCachesProgress::Finished => prime_caches_progress.push(progress),
                         },
+                        Task::FetchWorkspace(progress) => {
+                            let (state, msg) = match progress {
+                                ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
+                                ProjectWorkspaceProgress::Report(msg) => {
+                                    (Progress::Report, Some(msg))
+                                }
+                                ProjectWorkspaceProgress::End => (Progress::End, None),
+                            };
+                            self.report_progress("fetching", state, msg, None);
+                        }
                     }
                     // Coalesce multiple task events into one loop turn
                     task = match self.task_pool.receiver.try_recv() {
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 76b50931ad6..f4e084741b6 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -15,6 +15,13 @@ use crate::{
 };
 use lsp_ext::StatusParams;
 
+#[derive(Debug)]
+pub(crate) enum ProjectWorkspaceProgress {
+    Begin,
+    Report(String),
+    End,
+}
+
 impl GlobalState {
     pub(crate) fn update_configuration(&mut self, config: Config) {
         let _p = profile::span("GlobalState::update_configuration");
@@ -93,23 +100,42 @@ impl GlobalState {
     }
     pub(crate) fn fetch_workspaces(&mut self) {
         log::info!("will fetch workspaces");
-        self.task_pool.handle.spawn({
+
+        self.task_pool.handle.spawn_with_sender({
             let linked_projects = self.config.linked_projects();
             let cargo_config = self.config.cargo();
-            move || {
+
+            move |sender| {
+                let progress = {
+                    let sender = sender.clone();
+                    move |msg| {
+                        sender
+                            .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg)))
+                            .unwrap()
+                    }
+                };
+
+                sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap();
+
                 let workspaces = linked_projects
                     .iter()
                     .map(|project| match project {
                         LinkedProject::ProjectManifest(manifest) => {
-                            project_model::ProjectWorkspace::load(manifest.clone(), &cargo_config)
+                            project_model::ProjectWorkspace::load(
+                                manifest.clone(),
+                                &cargo_config,
+                                &progress,
+                            )
                         }
                         LinkedProject::InlineJsonProject(it) => {
                             project_model::ProjectWorkspace::load_inline(it.clone())
                         }
                     })
                     .collect::<Vec<_>>();
+
+                sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::End)).unwrap();
                 log::info!("did fetch workspaces {:?}", workspaces);
-                Task::Workspaces(workspaces)
+                sender.send(Task::Workspaces(workspaces)).unwrap()
             }
         });
     }