Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/workspace.rs')
| -rw-r--r-- | crates/project-model/src/workspace.rs | 297 |
1 files changed, 129 insertions, 168 deletions
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 3263d49176..dca2c8d739 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -2,7 +2,7 @@ //! metadata` or `rust-project.json`) into representation stored in the salsa //! database -- `CrateGraph`. -use std::{collections::VecDeque, fmt, fs, io::BufRead, iter, sync}; +use std::{collections::VecDeque, fmt, fs, iter, sync}; use anyhow::{format_err, Context}; use base_db::{ @@ -99,9 +99,9 @@ pub enum ProjectWorkspace { // // /// Project with a set of disjoint files, not belonging to any particular workspace. /// Backed by basic sysroot crates for basic completion and highlighting. - DetachedFiles { - /// The set of detached files. - files: Vec<AbsPathBuf>, + DetachedFile { + /// The file in question. + file: AbsPathBuf, /// The sysroot loaded for this workspace. sysroot: Result<Sysroot, Option<String>>, /// Holds cfg flags for the current target. We get those by running @@ -120,50 +120,6 @@ pub enum ProjectWorkspace { }, } -/// Tracks the cargo toml parts in cargo scripts, to detect if they -/// changed and reload workspace in that case. -pub struct CargoScriptTomls(pub FxHashMap<AbsPathBuf, String>); - -impl CargoScriptTomls { - fn extract_toml_part(p: &AbsPath) -> Option<String> { - let mut r = String::new(); - let f = std::fs::File::open(p).ok()?; - let f = std::io::BufReader::new(f); - let mut started = false; - for line in f.lines() { - let line = line.ok()?; - if started { - if line.trim() == "//! ```" { - return Some(r); - } - r += &line; - } else { - if line.trim() == "//! ```cargo" { - started = true; - } - } - } - None - } - - pub fn track_file(&mut self, p: AbsPathBuf) { - let toml = CargoScriptTomls::extract_toml_part(&p).unwrap_or_default(); - self.0.insert(p, toml); - } - - pub fn need_reload(&mut self, p: &AbsPath) -> bool { - let Some(prev) = self.0.get_mut(p) else { - return false; // File is not tracked - }; - let next = CargoScriptTomls::extract_toml_part(p).unwrap_or_default(); - if *prev == next { - return false; - } - *prev = next; - true - } -} - impl fmt::Debug for ProjectWorkspace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Make sure this isn't too verbose. @@ -213,8 +169,8 @@ impl fmt::Debug for ProjectWorkspace { .field("n_cfg_overrides", &cfg_overrides.len()); debug_struct.finish() } - ProjectWorkspace::DetachedFiles { - files, + ProjectWorkspace::DetachedFile { + file, sysroot, rustc_cfg, toolchain, @@ -223,7 +179,8 @@ impl fmt::Debug for ProjectWorkspace { cargo_script, } => f .debug_struct("DetachedFiles") - .field("n_files", &files.len()) + .field("file", &file) + .field("cargo_script", &cargo_script.is_some()) .field("sysroot", &sysroot.is_ok()) .field("cargo_script", &cargo_script.is_some()) .field("n_rustc_cfg", &rustc_cfg.len()) @@ -479,71 +436,79 @@ impl ProjectWorkspace { pub fn load_detached_files( detached_files: Vec<AbsPathBuf>, config: &CargoConfig, - cargo_script_tomls: &mut CargoScriptTomls, - ) -> anyhow::Result<ProjectWorkspace> { - let dir = detached_files - .first() - .and_then(|it| it.parent()) - .ok_or_else(|| format_err!("No detached files to load"))?; - let sysroot = match &config.sysroot { - Some(RustLibSource::Path(path)) => { - Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) - .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))) - } - Some(RustLibSource::Discover) => Sysroot::discover( - dir, - &config.extra_env, - config.sysroot_query_metadata, - ) - .map_err(|e| { - Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}")) - }), - None => Err(None), - }; + ) -> Vec<anyhow::Result<ProjectWorkspace>> { + dbg!(detached_files + .into_iter() + .map(|detached_file| { + let dir = detached_file + .parent() + .ok_or_else(|| format_err!("detached file has no parent"))?; + let sysroot = match &config.sysroot { + Some(RustLibSource::Path(path)) => { + Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) + .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))) + } + Some(RustLibSource::Discover) => { + Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata) + .map_err(|e| { + Some(format!( + "Failed to find sysroot for {dir}. Is rust-src installed? {e}" + )) + }) + } + None => Err(None), + }; - let sysroot_ref = sysroot.as_ref().ok(); - let toolchain = - match get_toolchain_version(dir, sysroot_ref, Tool::Rustc, &config.extra_env, "rustc ") - { - Ok(it) => it, - Err(e) => { - tracing::error!("{e}"); - None - } - }; + let sysroot_ref = sysroot.as_ref().ok(); + let toolchain = match get_toolchain_version( + dir, + sysroot_ref, + Tool::Rustc, + &config.extra_env, + "rustc ", + ) { + Ok(it) => it, + Err(e) => { + tracing::error!("{e}"); + None + } + }; - let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref)); - let data_layout = target_data_layout::get( - RustcDataLayoutConfig::Rustc(sysroot_ref), - None, - &config.extra_env, - ); - let cargo_toml = ManifestPath::try_from(detached_files[0].clone()).unwrap(); - let meta = CargoWorkspace::fetch_metadata( - &cargo_toml, - cargo_toml.parent(), - config, - sysroot_ref, - &|_| (), - ) - .with_context(|| { - format!("Failed to read Cargo metadata from Cargo.toml file {cargo_toml}") - })?; - let cargo = CargoWorkspace::new(meta); + let rustc_cfg = + rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref)); + let data_layout = target_data_layout::get( + RustcDataLayoutConfig::Rustc(sysroot_ref), + None, + &config.extra_env, + ); - for file in &detached_files { - cargo_script_tomls.track_file(file.clone()); - } + let cargo_script = ManifestPath::try_from(detached_file.clone()) + .ok() + .and_then(|file| { + CargoWorkspace::fetch_metadata( + &file, + file.parent(), + config, + sysroot_ref, + &|_| (), + ) + .ok() + }) + .map(CargoWorkspace::new); - Ok(ProjectWorkspace::DetachedFiles { - files: detached_files, - sysroot, - rustc_cfg, - toolchain, - target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), - cfg_overrides: config.cfg_overrides.clone(), - cargo_script: Some(cargo), - }) + Ok(ProjectWorkspace::DetachedFile { + file: detached_file, + sysroot, + rustc_cfg, + toolchain, + target_layout: data_layout + .map(Arc::from) + .map_err(|it| Arc::from(it.to_string())), + cfg_overrides: config.cfg_overrides.clone(), + cargo_script, + }) + }) + .collect()) } /// Runs the build scripts for this [`ProjectWorkspace`]. @@ -565,7 +530,7 @@ impl ProjectWorkspace { format!("Failed to run build scripts for {}", cargo.workspace_root()) }) } - ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => { + ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFile { .. } => { Ok(WorkspaceBuildScripts::default()) } } @@ -623,11 +588,11 @@ impl ProjectWorkspace { } } - pub fn workspace_definition_path(&self) -> Option<&AbsPath> { + pub fn workspace_definition_path(&self) -> &AbsPath { match self { - ProjectWorkspace::Cargo { cargo, .. } => Some(cargo.workspace_root()), - ProjectWorkspace::Json { project, .. } => Some(project.path()), - ProjectWorkspace::DetachedFiles { .. } => None, + ProjectWorkspace::Cargo { cargo, .. } => cargo.workspace_root(), + ProjectWorkspace::Json { project, .. } => project.path(), + ProjectWorkspace::DetachedFile { file, .. } => file, } } @@ -635,10 +600,10 @@ impl ProjectWorkspace { match self { ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. } | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. } - | ProjectWorkspace::DetachedFiles { sysroot: Ok(sysroot), .. } => { + | ProjectWorkspace::DetachedFile { sysroot: Ok(sysroot), .. } => { sysroot.discover_proc_macro_srv() } - ProjectWorkspace::DetachedFiles { .. } => { + ProjectWorkspace::DetachedFile { .. } => { Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found")) } ProjectWorkspace::Cargo { cargo, .. } => Err(anyhow::format_err!( @@ -769,15 +734,13 @@ impl ProjectWorkspace { })) .collect() } - ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files - .iter() - .map(|detached_file| PackageRoot { - is_local: true, - include: vec![detached_file.clone()], - exclude: Vec::new(), - }) - .chain(mk_sysroot(sysroot.as_ref())) - .collect(), + ProjectWorkspace::DetachedFile { file, sysroot, .. } => iter::once(PackageRoot { + is_local: true, + include: vec![file.clone()], + exclude: Vec::new(), + }) + .chain(mk_sysroot(sysroot.as_ref())) + .collect(), } } @@ -793,9 +756,9 @@ impl ProjectWorkspace { let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); cargo.packages().len() + sysroot_package_len + rustc_package_len } - ProjectWorkspace::DetachedFiles { sysroot, files, .. } => { + ProjectWorkspace::DetachedFile { sysroot, .. } => { let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); - sysroot_package_len + files.len() + sysroot_package_len + 1 } } } @@ -848,8 +811,8 @@ impl ProjectWorkspace { ), sysroot, ), - ProjectWorkspace::DetachedFiles { - files, + ProjectWorkspace::DetachedFile { + file, sysroot, rustc_cfg, toolchain: _, @@ -868,10 +831,10 @@ impl ProjectWorkspace { &WorkspaceBuildScripts::default(), ) } else { - detached_files_to_crate_graph( + detached_file_to_crate_graph( rustc_cfg.clone(), load, - files, + file, sysroot.as_ref().ok(), cfg_overrides, ) @@ -949,8 +912,8 @@ impl ProjectWorkspace { && cfg_overrides == o_cfg_overrides } ( - Self::DetachedFiles { - files, + Self::DetachedFile { + file, sysroot, rustc_cfg, cargo_script, @@ -958,8 +921,8 @@ impl ProjectWorkspace { target_layout, cfg_overrides, }, - Self::DetachedFiles { - files: o_files, + Self::DetachedFile { + file: o_file, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg, cargo_script: o_cargo_script, @@ -968,7 +931,7 @@ impl ProjectWorkspace { cfg_overrides: o_cfg_overrides, }, ) => { - files == o_files + file == o_file && sysroot == o_sysroot && rustc_cfg == o_rustc_cfg && toolchain == o_toolchain @@ -1285,10 +1248,10 @@ fn cargo_to_crate_graph( res } -fn detached_files_to_crate_graph( +fn detached_file_to_crate_graph( rustc_cfg: Vec<CfgFlag>, load: FileLoader<'_>, - detached_files: &[AbsPathBuf], + detached_file: &AbsPathBuf, sysroot: Option<&Sysroot>, override_cfg: &CfgOverrides, ) -> (CrateGraph, ProcMacroPaths) { @@ -1305,34 +1268,32 @@ fn detached_files_to_crate_graph( override_cfg.apply(&mut cfg_options, ""); let cfg_options = Arc::new(cfg_options); - for detached_file in detached_files { - let file_id = match load(detached_file) { - Some(file_id) => file_id, - None => { - tracing::error!("Failed to load detached file {:?}", detached_file); - continue; - } - }; - let display_name = detached_file - .file_stem() - .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_owned())); - let detached_file_crate = crate_graph.add_crate_root( - file_id, - Edition::CURRENT, - display_name.clone(), - None, - cfg_options.clone(), - None, - Env::default(), - false, - CrateOrigin::Local { - repo: None, - name: display_name.map(|n| n.canonical_name().to_owned()), - }, - ); + let file_id = match load(detached_file) { + Some(file_id) => file_id, + None => { + tracing::error!("Failed to load detached file {:?}", detached_file); + return (crate_graph, FxHashMap::default()); + } + }; + let display_name = detached_file + .file_stem() + .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_owned())); + let detached_file_crate = crate_graph.add_crate_root( + file_id, + Edition::CURRENT, + display_name.clone(), + None, + cfg_options.clone(), + None, + Env::default(), + false, + CrateOrigin::Local { + repo: None, + name: display_name.map(|n| n.canonical_name().to_owned()), + }, + ); - public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); - } + public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); (crate_graph, FxHashMap::default()) } |