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 | 99 |
1 files changed, 91 insertions, 8 deletions
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index a5e74763d7..3263d49176 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, iter, sync}; +use std::{collections::VecDeque, fmt, fs, io::BufRead, iter, sync}; use anyhow::{format_err, Context}; use base_db::{ @@ -115,9 +115,55 @@ pub enum ProjectWorkspace { target_layout: TargetLayoutLoadResult, /// A set of cfg overrides for the files. cfg_overrides: CfgOverrides, + /// Is this file a cargo script file? + cargo_script: Option<CargoWorkspace>, }, } +/// 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. @@ -174,10 +220,12 @@ impl fmt::Debug for ProjectWorkspace { toolchain, target_layout, cfg_overrides, + cargo_script, } => f .debug_struct("DetachedFiles") .field("n_files", &files.len()) .field("sysroot", &sysroot.is_ok()) + .field("cargo_script", &cargo_script.is_some()) .field("n_rustc_cfg", &rustc_cfg.len()) .field("toolchain", &toolchain) .field("data_layout", &target_layout) @@ -431,6 +479,7 @@ 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() @@ -469,6 +518,23 @@ impl ProjectWorkspace { 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); + + for file in &detached_files { + cargo_script_tomls.track_file(file.clone()); + } + Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, @@ -476,6 +542,7 @@ impl ProjectWorkspace { 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), }) } @@ -788,14 +855,27 @@ impl ProjectWorkspace { toolchain: _, target_layout: _, cfg_overrides, + cargo_script, } => ( - detached_files_to_crate_graph( - rustc_cfg.clone(), - load, - files, - sysroot.as_ref().ok(), - cfg_overrides, - ), + if let Some(cargo) = cargo_script { + cargo_to_crate_graph( + load, + None, + cargo, + sysroot.as_ref().ok(), + rustc_cfg.clone(), + cfg_overrides, + &WorkspaceBuildScripts::default(), + ) + } else { + detached_files_to_crate_graph( + rustc_cfg.clone(), + load, + files, + sysroot.as_ref().ok(), + cfg_overrides, + ) + }, sysroot, ), }; @@ -873,6 +953,7 @@ impl ProjectWorkspace { files, sysroot, rustc_cfg, + cargo_script, toolchain, target_layout, cfg_overrides, @@ -881,6 +962,7 @@ impl ProjectWorkspace { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg, + cargo_script: o_cargo_script, toolchain: o_toolchain, target_layout: o_target_layout, cfg_overrides: o_cfg_overrides, @@ -892,6 +974,7 @@ impl ProjectWorkspace { && toolchain == o_toolchain && target_layout == o_target_layout && cfg_overrides == o_cfg_overrides + && cargo_script == o_cargo_script } _ => false, } |