diff options
| author | bors <bors@rust-lang.org> | 2022-09-18 17:43:46 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-09-18 17:43:46 +0000 |
| commit | 11bf2e7ffbc501aa578b08ff999b8c104341837e (patch) | |
| tree | 5ca358829c2fd9e85e076d97594495f63df86dc6 | |
| parent | 932e63b5d4358de4775649f99a71430ae4318db1 (diff) | |
| parent | c407cc554ee8657081ae5357a05025d3eaca1184 (diff) | |
| download | rust-11bf2e7ffbc501aa578b08ff999b8c104341837e.tar.gz rust-11bf2e7ffbc501aa578b08ff999b8c104341837e.zip | |
Auto merge of #13058 - dpaoliello:extraenv, r=Veykril
Add a new configuration settings to set env vars when running cargo, rustc, etc. commands: cargo.extraEnv and checkOnSave.extraEnv It can be extremely useful to be able to set environment variables when rust-analyzer is running various cargo or rustc commands (such as `cargo check`, `cargo --print cfg` or `cargo metadata`): users may want to set custom `RUSTFLAGS`, change `PATH` to use a custom toolchain or set a different `CARGO_HOME`. There is the existing `server.extraEnv` setting that allows env vars to be set when the rust-analyzer server is launched, but using this as the recommended mechanism to also configure cargo/rust has some drawbacks: - It convolutes configuring the rust-analyzer server with configuring cargo/rustc (one may want to change the `PATH` for cargo/rustc without affecting the rust-analyzer server). - The name `server.extraEnv` doesn't indicate that cargo/rustc will be affected but renaming it to `cargo.extraEnv` doesn't indicate that the rust-analyzer server would be affected. - To make the setting useful, it needs to be dynamically reloaded without requiring that the entire extension is reloaded. It might be possible to do this, but it would require the client communicating to the server what the overwritten env vars were at first launch, which isn't easy to do. This change adds two new configuration settings: `cargo.extraEnv` and `checkOnSave.extraEnv` that can be used to change the environment for the rust-analyzer server after launch (thus affecting any process that rust-analyzer invokes) and the `cargo check` command respectively. `cargo.extraEnv` supports dynamic changes by keeping track of the pre-change values of environment variables, thus it can undo changes made previously before applying the new configuration (and then requesting a workspace reload).
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | crates/flycheck/Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/flycheck/src/lib.rs | 10 | ||||
| -rw-r--r-- | crates/project-model/src/build_scripts.rs | 2 | ||||
| -rw-r--r-- | crates/project-model/src/cargo_workspace.rs | 36 | ||||
| -rw-r--r-- | crates/project-model/src/rustc_cfg.rs | 18 | ||||
| -rw-r--r-- | crates/project-model/src/sysroot.rs | 19 | ||||
| -rw-r--r-- | crates/project-model/src/tests.rs | 22 | ||||
| -rw-r--r-- | crates/project-model/src/workspace.rs | 24 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/cli/analysis_stats.rs | 3 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 4 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/cli/lsif.rs | 3 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/cli/scip.rs | 2 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/config.rs | 23 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 2 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/reload.rs | 7 | ||||
| -rw-r--r-- | docs/user/generated_config.adoc | 11 | ||||
| -rw-r--r-- | editors/code/package.json | 10 |
18 files changed, 155 insertions, 43 deletions
diff --git a/Cargo.lock b/Cargo.lock index eaadcc8b8c6..216cf51447f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,6 +394,7 @@ dependencies = [ "crossbeam-channel", "jod-thread", "paths", + "rustc-hash", "serde", "serde_json", "stdx", diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index d3d180ece51..688e790c536 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -13,6 +13,7 @@ doctest = false crossbeam-channel = "0.5.5" tracing = "0.1.35" cargo_metadata = "0.15.0" +rustc-hash = "1.1.0" serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.81" jod-thread = "0.1.2" diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index d9f4ef5b7ff..fdc03f4053a 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -12,6 +12,7 @@ use std::{ use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; use paths::AbsPathBuf; +use rustc_hash::FxHashMap; use serde::Deserialize; use stdx::{process::streaming_output, JodChild}; @@ -30,10 +31,12 @@ pub enum FlycheckConfig { all_features: bool, features: Vec<String>, extra_args: Vec<String>, + extra_env: FxHashMap<String, String>, }, CustomCommand { command: String, args: Vec<String>, + extra_env: FxHashMap<String, String>, }, } @@ -41,7 +44,7 @@ impl fmt::Display for FlycheckConfig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command), - FlycheckConfig::CustomCommand { command, args } => { + FlycheckConfig::CustomCommand { command, args, .. } => { write!(f, "{} {}", command, args.join(" ")) } } @@ -256,6 +259,7 @@ impl FlycheckActor { all_features, extra_args, features, + extra_env, } => { let mut cmd = Command::new(toolchain::cargo()); cmd.arg(command); @@ -281,11 +285,13 @@ impl FlycheckActor { } } cmd.args(extra_args); + cmd.envs(extra_env); cmd } - FlycheckConfig::CustomCommand { command, args } => { + FlycheckConfig::CustomCommand { command, args, extra_env } => { let mut cmd = Command::new(command); cmd.args(args); + cmd.envs(extra_env); cmd } }; diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index 84e772d1684..837ea016193 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -43,10 +43,12 @@ impl WorkspaceBuildScripts { if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() { let mut cmd = Command::new(program); cmd.args(args); + cmd.envs(&config.extra_env); return cmd; } let mut cmd = Command::new(toolchain::cargo()); + cmd.envs(&config.extra_env); cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]); diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index eed955b42da..736d80041bd 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -2,6 +2,7 @@ use std::iter; use std::path::PathBuf; +use std::str::from_utf8; use std::{ops, process::Command}; use anyhow::{Context, Result}; @@ -98,6 +99,8 @@ pub struct CargoConfig { pub wrap_rustc_in_build_scripts: bool, pub run_build_script_command: Option<Vec<String>>, + + pub extra_env: FxHashMap<String, String>, } impl CargoConfig { @@ -263,8 +266,8 @@ impl CargoWorkspace { let target = config .target .clone() - .or_else(|| cargo_config_build_target(cargo_toml)) - .or_else(|| rustc_discover_host_triple(cargo_toml)); + .or_else(|| cargo_config_build_target(cargo_toml, config)) + .or_else(|| rustc_discover_host_triple(cargo_toml, config)); let mut meta = MetadataCommand::new(); meta.cargo_path(toolchain::cargo()); @@ -292,8 +295,27 @@ impl CargoWorkspace { // unclear whether cargo itself supports it. progress("metadata".to_string()); - let meta = - meta.exec().with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?; + fn exec_with_env( + command: &cargo_metadata::MetadataCommand, + extra_env: &FxHashMap<String, String>, + ) -> Result<cargo_metadata::Metadata, cargo_metadata::Error> { + let mut command = command.cargo_command(); + command.envs(extra_env); + let output = command.output()?; + if !output.status.success() { + return Err(cargo_metadata::Error::CargoMetadata { + stderr: String::from_utf8(output.stderr)?, + }); + } + let stdout = from_utf8(&output.stdout)? + .lines() + .find(|line| line.starts_with('{')) + .ok_or(cargo_metadata::Error::NoJson)?; + cargo_metadata::MetadataCommand::parse(stdout) + } + + let meta = exec_with_env(&meta, &config.extra_env) + .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?; Ok(meta) } @@ -463,8 +485,9 @@ impl CargoWorkspace { } } -fn rustc_discover_host_triple(cargo_toml: &ManifestPath) -> Option<String> { +fn rustc_discover_host_triple(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> { let mut rustc = Command::new(toolchain::rustc()); + rustc.envs(&config.extra_env); rustc.current_dir(cargo_toml.parent()).arg("-vV"); tracing::debug!("Discovering host platform by {:?}", rustc); match utf8_stdout(rustc) { @@ -486,8 +509,9 @@ fn rustc_discover_host_triple(cargo_toml: &ManifestPath) -> Option<String> { } } -fn cargo_config_build_target(cargo_toml: &ManifestPath) -> Option<String> { +fn cargo_config_build_target(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> { let mut cargo_config = Command::new(toolchain::cargo()); + cargo_config.envs(&config.extra_env); cargo_config .current_dir(cargo_toml.parent()) .args(&["-Z", "unstable-options", "config", "get", "build.target"]) diff --git a/crates/project-model/src/rustc_cfg.rs b/crates/project-model/src/rustc_cfg.rs index 17e244d0649..486cb143b80 100644 --- a/crates/project-model/src/rustc_cfg.rs +++ b/crates/project-model/src/rustc_cfg.rs @@ -4,9 +4,13 @@ use std::process::Command; use anyhow::Result; -use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath}; +use crate::{cfg_flag::CfgFlag, utf8_stdout, CargoConfig, ManifestPath}; -pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Vec<CfgFlag> { +pub(crate) fn get( + cargo_toml: Option<&ManifestPath>, + target: Option<&str>, + config: &CargoConfig, +) -> Vec<CfgFlag> { let _p = profile::span("rustc_cfg::get"); let mut res = Vec::with_capacity(6 * 2 + 1); @@ -18,7 +22,7 @@ pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Ve } } - match get_rust_cfgs(cargo_toml, target) { + match get_rust_cfgs(cargo_toml, target, config) { Ok(rustc_cfgs) => { tracing::debug!( "rustc cfgs found: {:?}", @@ -35,9 +39,14 @@ pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Ve res } -fn get_rust_cfgs(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Result<String> { +fn get_rust_cfgs( + cargo_toml: Option<&ManifestPath>, + target: Option<&str>, + config: &CargoConfig, +) -> Result<String> { if let Some(cargo_toml) = cargo_toml { let mut cargo_config = Command::new(toolchain::cargo()); + cargo_config.envs(&config.extra_env); cargo_config .current_dir(cargo_toml.parent()) .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"]) @@ -52,6 +61,7 @@ fn get_rust_cfgs(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Res } // using unstable cargo features failed, fall back to using plain rustc let mut cmd = Command::new(toolchain::rustc()); + cmd.envs(&config.extra_env); cmd.args(&["--print", "cfg", "-O"]); if let Some(target) = target { cmd.args(&["--target", target]); diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 362bb0f5e79..3282719fef3 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -10,7 +10,7 @@ use anyhow::{format_err, Result}; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; -use crate::{utf8_stdout, ManifestPath}; +use crate::{utf8_stdout, CargoConfig, ManifestPath}; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Sysroot { @@ -67,18 +67,20 @@ impl Sysroot { self.crates.iter().map(|(id, _data)| id) } - pub fn discover(dir: &AbsPath) -> Result<Sysroot> { + pub fn discover(dir: &AbsPath, config: &CargoConfig) -> Result<Sysroot> { tracing::debug!("Discovering sysroot for {}", dir.display()); - let sysroot_dir = discover_sysroot_dir(dir)?; - let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir)?; + let sysroot_dir = discover_sysroot_dir(dir, config)?; + let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir, config)?; let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?; Ok(res) } - pub fn discover_rustc(cargo_toml: &ManifestPath) -> Option<ManifestPath> { + pub fn discover_rustc(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<ManifestPath> { tracing::debug!("Discovering rustc source for {}", cargo_toml.display()); let current_dir = cargo_toml.parent(); - discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir)) + discover_sysroot_dir(current_dir, config) + .ok() + .and_then(|sysroot_dir| get_rustc_src(&sysroot_dir)) } pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> { @@ -144,8 +146,9 @@ impl Sysroot { } } -fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> { +fn discover_sysroot_dir(current_dir: &AbsPath, config: &CargoConfig) -> Result<AbsPathBuf> { let mut rustc = Command::new(toolchain::rustc()); + rustc.envs(&config.extra_env); rustc.current_dir(current_dir).args(&["--print", "sysroot"]); tracing::debug!("Discovering sysroot by {:?}", rustc); let stdout = utf8_stdout(rustc)?; @@ -155,6 +158,7 @@ fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> { fn discover_sysroot_src_dir( sysroot_path: &AbsPathBuf, current_dir: &AbsPath, + config: &CargoConfig, ) -> Result<AbsPathBuf> { if let Ok(path) = env::var("RUST_SRC_PATH") { let path = AbsPathBuf::try_from(path.as_str()) @@ -170,6 +174,7 @@ fn discover_sysroot_src_dir( get_rust_src(sysroot_path) .or_else(|| { let mut rustup = Command::new(toolchain::rustup()); + rustup.envs(&config.extra_env); rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]); utf8_stdout(rustup).ok()?; get_rust_src(sysroot_path) diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 9ccb6e9101e..bea624bd541 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -10,8 +10,8 @@ use paths::{AbsPath, AbsPathBuf}; use serde::de::DeserializeOwned; use crate::{ - CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot, - WorkspaceBuildScripts, + CargoConfig, CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, + Sysroot, WorkspaceBuildScripts, }; fn load_cargo(file: &str) -> CrateGraph { @@ -92,13 +92,17 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { } fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { - project_workspace.to_crate_graph(&mut |_, _| Ok(Vec::new()), &mut { - let mut counter = 0; - move |_path| { - counter += 1; - Some(FileId(counter)) - } - }) + project_workspace.to_crate_graph( + &mut |_, _| Ok(Vec::new()), + &mut { + let mut counter = 0; + move |_path| { + counter += 1; + Some(FileId(counter)) + } + }, + &CargoConfig::default(), + ) } fn check_crate_graph(crate_graph: CrateGraph, expect: Expect) { diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 818bbed6af2..bc4ab45daef 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -156,11 +156,12 @@ impl ProjectWorkspace { })?; let project_location = project_json.parent().to_path_buf(); let project_json = ProjectJson::new(&project_location, data); - ProjectWorkspace::load_inline(project_json, config.target.as_deref())? + ProjectWorkspace::load_inline(project_json, config.target.as_deref(), config)? } ProjectManifest::CargoToml(cargo_toml) => { let cargo_version = utf8_stdout({ let mut cmd = Command::new(toolchain::cargo()); + cmd.envs(&config.extra_env); cmd.arg("--version"); cmd })?; @@ -186,7 +187,7 @@ impl ProjectWorkspace { let sysroot = if config.no_sysroot { None } else { - Some(Sysroot::discover(cargo_toml.parent()).with_context(|| { + Some(Sysroot::discover(cargo_toml.parent(), config).with_context(|| { format!( "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?", cargo_toml.display() @@ -196,7 +197,7 @@ impl ProjectWorkspace { let rustc_dir = match &config.rustc_source { Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(), - Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml), + Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml, config), None => None, }; @@ -216,7 +217,7 @@ impl ProjectWorkspace { None => None, }; - let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); + let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), config); let cfg_overrides = config.cfg_overrides(); ProjectWorkspace::Cargo { @@ -237,6 +238,7 @@ impl ProjectWorkspace { pub fn load_inline( project_json: ProjectJson, target: Option<&str>, + config: &CargoConfig, ) -> Result<ProjectWorkspace> { let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?), @@ -258,7 +260,7 @@ impl ProjectWorkspace { (None, None) => None, }; - let rustc_cfg = rustc_cfg::get(None, target); + let rustc_cfg = rustc_cfg::get(None, target, config); Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) } @@ -268,8 +270,9 @@ impl ProjectWorkspace { .first() .and_then(|it| it.parent()) .ok_or_else(|| format_err!("No detached files to load"))?, + &CargoConfig::default(), )?; - let rustc_cfg = rustc_cfg::get(None, None); + let rustc_cfg = rustc_cfg::get(None, None, &CargoConfig::default()); Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg }) } @@ -416,6 +419,7 @@ impl ProjectWorkspace { &self, load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, + config: &CargoConfig, ) -> CrateGraph { let _p = profile::span("ProjectWorkspace::to_crate_graph"); @@ -426,6 +430,7 @@ impl ProjectWorkspace { load, project, sysroot, + config, ), ProjectWorkspace::Cargo { cargo, @@ -464,6 +469,7 @@ fn project_json_to_crate_graph( load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, project: &ProjectJson, sysroot: &Option<Sysroot>, + config: &CargoConfig, ) -> CrateGraph { let mut crate_graph = CrateGraph::default(); let sysroot_deps = sysroot @@ -489,9 +495,9 @@ fn project_json_to_crate_graph( }; let target_cfgs = match krate.target.as_deref() { - Some(target) => { - cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target))) - } + Some(target) => cfg_cache + .entry(target) + .or_insert_with(|| rustc_cfg::get(None, Some(target), config)), None => &rustc_cfg, }; diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index f52e1e75127..80128e43fd3 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -80,7 +80,8 @@ impl flags::AnalysisStats { Some(build_scripts_sw.elapsed()) }; - let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?; + let (host, vfs, _proc_macro) = + load_workspace(workspace, &cargo_config, &load_cargo_config)?; let db = host.raw_database(); eprint!("{:<20} {}", "Database loaded:", db_load_sw.elapsed()); eprint!(" (metadata {}", metadata_time); diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 5d1c013c327..88953096e2b 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -38,7 +38,7 @@ pub fn load_workspace_at( workspace.set_build_scripts(build_scripts) } - load_workspace(workspace, load_config) + load_workspace(workspace, cargo_config, load_config) } // Note: Since this function is used by external tools that use rust-analyzer as a library @@ -48,6 +48,7 @@ pub fn load_workspace_at( // these tools need access to `ProjectWorkspace`, too, which `load_workspace_at` hides. pub fn load_workspace( ws: ProjectWorkspace, + cargo_config: &CargoConfig, load_config: &LoadCargoConfig, ) -> Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroServer>)> { let (sender, receiver) = unbounded(); @@ -75,6 +76,7 @@ pub fn load_workspace( vfs.set_file_contents(path.clone(), contents); vfs.file_id(&path) }, + cargo_config, ); let project_folders = ProjectFolders::new(&[ws], &[]); diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs index 491c55a04f8..79577bf78c8 100644 --- a/crates/rust-analyzer/src/cli/lsif.rs +++ b/crates/rust-analyzer/src/cli/lsif.rs @@ -299,7 +299,8 @@ impl flags::Lsif { let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; - let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?; + let (host, vfs, _proc_macro) = + load_workspace(workspace, &cargo_config, &load_cargo_config)?; let db = host.raw_database(); let analysis = host.analysis(); diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index 65cc993c45e..05c16bb39e3 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -40,7 +40,7 @@ impl flags::Scip { let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; - let (host, vfs, _) = load_workspace(workspace, &load_cargo_config)?; + let (host, vfs, _) = load_workspace(workspace, &cargo_config, &load_cargo_config)?; let db = host.raw_database(); let analysis = host.analysis(); diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3cafbc74335..9ef79e6f381 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -84,6 +84,9 @@ config_data! { /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to /// avoid checking unnecessary things. cargo_buildScripts_useRustcWrapper: bool = "true", + /// Extra environment variables that will be set when running cargo, rustc + /// or other commands within the workspace. Useful for setting RUSTFLAGS. + cargo_extraEnv: FxHashMap<String, String> = "{}", /// List of features to activate. /// /// Set this to `"all"` to pass `--all-features` to cargo. @@ -105,6 +108,8 @@ config_data! { checkOnSave_enable: bool = "true", /// Extra arguments for `cargo check`. checkOnSave_extraArgs: Vec<String> = "[]", + /// Extra environment variables that will be set when running `cargo check`. + checkOnSave_extraEnv: FxHashMap<String, String> = "{}", /// List of features to activate. Defaults to /// `#rust-analyzer.cargo.features#`. /// @@ -956,6 +961,16 @@ impl Config { } } + pub fn extra_env(&self) -> &FxHashMap<String, String> { + &self.data.cargo_extraEnv + } + + pub fn check_on_save_extra_env(&self) -> FxHashMap<String, String> { + let mut extra_env = self.data.cargo_extraEnv.clone(); + extra_env.extend(self.data.checkOnSave_extraEnv.clone()); + extra_env + } + pub fn lru_capacity(&self) -> Option<usize> { self.data.lru_capacity } @@ -1025,6 +1040,7 @@ impl Config { unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()), wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper, run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(), + extra_env: self.data.cargo_extraEnv.clone(), } } @@ -1050,7 +1066,11 @@ impl Config { Some(args) if !args.is_empty() => { let mut args = args.clone(); let command = args.remove(0); - FlycheckConfig::CustomCommand { command, args } + FlycheckConfig::CustomCommand { + command, + args, + extra_env: self.check_on_save_extra_env(), + } } Some(_) | None => FlycheckConfig::CargoCommand { command: self.data.checkOnSave_command.clone(), @@ -1078,6 +1098,7 @@ impl Config { CargoFeatures::Listed(it) => it, }, extra_args: self.data.checkOnSave_extraArgs.clone(), + extra_env: self.check_on_save_extra_env(), }, }; Some(flycheck_config) diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 7dfa32cf374..8c3ea77d061 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1789,6 +1789,7 @@ fn run_rustfmt( let mut command = match snap.config.rustfmt() { RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { let mut cmd = process::Command::new(toolchain::rustfmt()); + cmd.envs(snap.config.extra_env()); cmd.args(extra_args); // try to chdir to the file so we can respect `rustfmt.toml` // FIXME: use `rustfmt --config-path` once @@ -1846,6 +1847,7 @@ fn run_rustfmt( } RustfmtConfig::CustomCommand { command, args } => { let mut cmd = process::Command::new(command); + cmd.envs(snap.config.extra_env()); cmd.args(args); cmd } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index e47f70fff39..4cf5de46c48 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -143,6 +143,7 @@ impl GlobalState { project_model::ProjectWorkspace::load_inline( it.clone(), cargo_config.target.as_deref(), + &cargo_config, ) } }) @@ -398,7 +399,11 @@ impl GlobalState { dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(), ) }; - crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load)); + crate_graph.extend(ws.to_crate_graph( + &mut load_proc_macro, + &mut load, + &self.config.cargo(), + )); } crate_graph }; diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 62671459d7b..996d4c023d7 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -46,6 +46,12 @@ cargo check --quiet --workspace --message-format=json --all-targets Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to avoid checking unnecessary things. -- +[[rust-analyzer.cargo.extraEnv]]rust-analyzer.cargo.extraEnv (default: `{}`):: ++ +-- +Extra environment variables that will be set when running cargo, rustc +or other commands within the workspace. Useful for setting RUSTFLAGS. +-- [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: + -- @@ -93,6 +99,11 @@ Run specified `cargo check` command for diagnostics on save. -- Extra arguments for `cargo check`. -- +[[rust-analyzer.checkOnSave.extraEnv]]rust-analyzer.checkOnSave.extraEnv (default: `{}`):: ++ +-- +Extra environment variables that will be set when running `cargo check`. +-- [[rust-analyzer.checkOnSave.features]]rust-analyzer.checkOnSave.features (default: `null`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index e2cc2c16c92..94b41c049bc 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -437,6 +437,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.cargo.extraEnv": { + "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.", + "default": {}, + "type": "object" + }, "rust-analyzer.cargo.features": { "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.", "default": [], @@ -509,6 +514,11 @@ "type": "string" } }, + "rust-analyzer.checkOnSave.extraEnv": { + "markdownDescription": "Extra environment variables that will be set when running `cargo check`.", + "default": {}, + "type": "object" + }, "rust-analyzer.checkOnSave.features": { "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", "default": null, |
