From cb9a5b9549cb5bb7f8f946643555398ae180937b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 6 Feb 2023 12:07:33 +0100 Subject: [PATCH] Support sysroot library source being defined inside the workspace --- crates/project-model/src/cargo_workspace.rs | 1 + crates/project-model/src/sysroot.rs | 11 ++++++ crates/project-model/src/workspace.rs | 41 ++++++++++++++++----- crates/rust-analyzer/src/config.rs | 8 ++++ docs/user/generated_config.adoc | 8 ++++ editors/code/package.json | 8 ++++ 6 files changed, 68 insertions(+), 9 deletions(-) diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 467cf09178..fdc7859eb9 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -96,6 +96,7 @@ pub struct CargoConfig { pub target: Option, /// Sysroot loading behavior pub sysroot: Option, + pub sysroot_src: Option, /// rustc private crate source pub rustc_source: Option, /// crates to disable `#[cfg(test)]` on diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index e1dde12bad..328d2fbcf3 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -76,6 +76,7 @@ impl Sysroot { } } +// FIXME: Expose a builder api as loading the sysroot got way too modular and complicated. impl Sysroot { /// Attempts to discover the toolchain's sysroot from the given `dir`. pub fn discover(dir: &AbsPath, extra_env: &FxHashMap) -> Result { @@ -86,6 +87,16 @@ impl Sysroot { Ok(Sysroot::load(sysroot_dir, sysroot_src_dir)) } + pub fn discover_with_src_override( + dir: &AbsPath, + extra_env: &FxHashMap, + src: AbsPathBuf, + ) -> Result { + tracing::debug!("discovering sysroot for {}", dir.display()); + let sysroot_dir = discover_sysroot_dir(dir, extra_env)?; + Ok(Sysroot::load(sysroot_dir, src)) + } + pub fn discover_rustc( cargo_toml: &ManifestPath, extra_env: &FxHashMap, diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index d784d3d0e9..2a11f1e8eb 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -190,8 +190,8 @@ impl ProjectWorkspace { })?; let cargo = CargoWorkspace::new(meta); - let sysroot = match &config.sysroot { - Some(RustcSource::Path(path)) => { + let sysroot = match (&config.sysroot, &config.sysroot_src) { + (Some(RustcSource::Path(path)), None) => { match Sysroot::with_sysroot_dir(path.clone()) { Ok(it) => Some(it), Err(e) => { @@ -200,7 +200,7 @@ impl ProjectWorkspace { } } } - Some(RustcSource::Discover) => { + (Some(RustcSource::Discover), None) => { match Sysroot::discover(cargo_toml.parent(), &config.extra_env) { Ok(it) => Some(it), Err(e) => { @@ -213,8 +213,29 @@ impl ProjectWorkspace { } } } - None => None, + (Some(RustcSource::Path(sysroot)), Some(sysroot_src)) => { + Some(Sysroot::load(sysroot.clone(), sysroot_src.clone())) + } + (Some(RustcSource::Discover), Some(sysroot_src)) => { + match Sysroot::discover_with_src_override( + cargo_toml.parent(), + &config.extra_env, + sysroot_src.clone(), + ) { + Ok(it) => Some(it), + Err(e) => { + tracing::error!( + %e, + "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?", + cargo_toml.display() + ); + None + } + } + } + (None, _) => None, }; + if let Some(sysroot) = &sysroot { tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot"); } @@ -440,9 +461,11 @@ impl ProjectWorkspace { /// The return type contains the path and whether or not /// the root is a member of the current workspace pub fn to_roots(&self) -> Vec { - let mk_sysroot = |sysroot: Option<&Sysroot>| { + let mk_sysroot = |sysroot: Option<&Sysroot>, project_root: Option<&AbsPath>| { sysroot.map(|sysroot| PackageRoot { - is_local: false, + // mark the sysroot as mutable if it is located inside of the project + is_local: project_root + .map_or(false, |project_root| sysroot.src_root().starts_with(project_root)), include: vec![sysroot.src_root().to_path_buf()], exclude: Vec::new(), }) @@ -457,7 +480,7 @@ impl ProjectWorkspace { }) .collect::>() .into_iter() - .chain(mk_sysroot(sysroot.as_ref())) + .chain(mk_sysroot(sysroot.as_ref(), Some(project.path()))) .collect::>(), ProjectWorkspace::Cargo { cargo, @@ -507,7 +530,7 @@ impl ProjectWorkspace { } PackageRoot { is_local, include, exclude } }) - .chain(mk_sysroot(sysroot.as_ref())) + .chain(mk_sysroot(sysroot.as_ref(), Some(cargo.workspace_root()))) .chain(rustc.iter().flat_map(|rustc| { rustc.packages().map(move |krate| PackageRoot { is_local: false, @@ -524,7 +547,7 @@ impl ProjectWorkspace { include: vec![detached_file.clone()], exclude: Vec::new(), }) - .chain(mk_sysroot(sysroot.as_ref())) + .chain(mk_sysroot(sysroot.as_ref(), None)) .collect(), } } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8ea161dbdc..c8075aefbb 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -117,6 +117,11 @@ config_data! { /// /// This option does not take effect until rust-analyzer is restarted. cargo_sysroot: Option = "\"discover\"", + /// Relative path to the sysroot library sources. If left unset, this will default to + /// `{cargo.sysroot}/lib/rustlib/src/rust/library`. + /// + /// This option does not take effect until rust-analyzer is restarted. + cargo_sysrootSrc: Option = "null", /// Compilation target override (target triple). // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work // than `checkOnSave_target` @@ -1103,6 +1108,8 @@ impl Config { RustcSource::Path(self.root_path.join(sysroot)) } }); + let sysroot_src = + self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot)); CargoConfig { features: match &self.data.cargo_features { @@ -1114,6 +1121,7 @@ impl Config { }, target: self.data.cargo_target.clone(), sysroot, + sysroot_src, rustc_source, unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()), wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper, diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 1bfb8a917a..d5fdedfe3a 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -97,6 +97,14 @@ Relative path to the sysroot, or "discover" to try to automatically find it via Unsetting this disables sysroot loading. +This option does not take effect until rust-analyzer is restarted. +-- +[[rust-analyzer.cargo.sysrootSrc]]rust-analyzer.cargo.sysrootSrc (default: `null`):: ++ +-- +Relative path to the sysroot library sources. If left unset, this will default to +`{cargo.sysroot}/lib/rustlib/src/rust/library`. + This option does not take effect until rust-analyzer is restarted. -- [[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`):: diff --git a/editors/code/package.json b/editors/code/package.json index 599e9c5a7b..7160781b6f 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -539,6 +539,14 @@ "string" ] }, + "rust-analyzer.cargo.sysrootSrc": { + "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.", + "default": null, + "type": [ + "null", + "string" + ] + }, "rust-analyzer.cargo.target": { "markdownDescription": "Compilation target override (target triple).", "default": null,