mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Add config option to use rust-analyzer
specific target dir
Adds a Rust Analyzer configuration option to set a custom target directory for builds. This is a workaround for Rust Analyzer blocking debug builds while running `cargo check`. This change should close #6007
This commit is contained in:
parent
7e9b25bff7
commit
aeef7b644b
3 changed files with 190 additions and 34 deletions
|
@ -480,6 +480,13 @@ config_data! {
|
||||||
/// tests or binaries. For example, it may be `--release`.
|
/// tests or binaries. For example, it may be `--release`.
|
||||||
runnables_extraArgs: Vec<String> = "[]",
|
runnables_extraArgs: Vec<String> = "[]",
|
||||||
|
|
||||||
|
/// Optional path to a rust-analyzer specific target directory.
|
||||||
|
/// This is useful to prevent rust-analyzer's `cargo check` from blocking builds.
|
||||||
|
///
|
||||||
|
/// Set to `true` to use a subdirectory of the existing target directory or
|
||||||
|
/// set to a path to use that path.
|
||||||
|
rust_analyzerTargetDir: Option<TargetDirectory> = "null",
|
||||||
|
|
||||||
/// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
|
/// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
|
||||||
/// projects, or "discover" to try to automatically find it if the `rustc-dev` component
|
/// projects, or "discover" to try to automatically find it if the `rustc-dev` component
|
||||||
/// is installed.
|
/// is installed.
|
||||||
|
@ -1192,6 +1199,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cargo(&self) -> CargoConfig {
|
pub fn cargo(&self) -> CargoConfig {
|
||||||
|
let target_directory = self.target_dir_from_config();
|
||||||
let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| {
|
let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| {
|
||||||
if rustc_src == "discover" {
|
if rustc_src == "discover" {
|
||||||
RustLibSource::Discover
|
RustLibSource::Discover
|
||||||
|
@ -1209,6 +1217,10 @@ impl Config {
|
||||||
let sysroot_src =
|
let sysroot_src =
|
||||||
self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot));
|
self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot));
|
||||||
|
|
||||||
|
let mut extra_args = self.data.cargo_extraArgs.clone();
|
||||||
|
|
||||||
|
add_target_dir_to_args(&mut extra_args, target_directory);
|
||||||
|
|
||||||
CargoConfig {
|
CargoConfig {
|
||||||
features: match &self.data.cargo_features {
|
features: match &self.data.cargo_features {
|
||||||
CargoFeaturesDef::All => CargoFeatures::All,
|
CargoFeaturesDef::All => CargoFeatures::All,
|
||||||
|
@ -1261,7 +1273,7 @@ impl Config {
|
||||||
InvocationLocation::Workspace => project_model::InvocationLocation::Workspace,
|
InvocationLocation::Workspace => project_model::InvocationLocation::Workspace,
|
||||||
},
|
},
|
||||||
run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
|
run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
|
||||||
extra_args: self.data.cargo_extraArgs.clone(),
|
extra_args,
|
||||||
extra_env: self.data.cargo_extraEnv.clone(),
|
extra_env: self.data.cargo_extraEnv.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1281,10 +1293,14 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flycheck(&self) -> FlycheckConfig {
|
pub fn flycheck(&self) -> FlycheckConfig {
|
||||||
|
let target_directory = self.target_dir_from_config();
|
||||||
|
|
||||||
match &self.data.check_overrideCommand {
|
match &self.data.check_overrideCommand {
|
||||||
Some(args) if !args.is_empty() => {
|
Some(args) if !args.is_empty() => {
|
||||||
let mut args = args.clone();
|
let mut args = args.clone();
|
||||||
let command = args.remove(0);
|
let command = args.remove(0);
|
||||||
|
add_target_dir_to_args(&mut args, target_directory);
|
||||||
|
|
||||||
FlycheckConfig::CustomCommand {
|
FlycheckConfig::CustomCommand {
|
||||||
command,
|
command,
|
||||||
args,
|
args,
|
||||||
|
@ -1303,42 +1319,61 @@ impl Config {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(_) | None => FlycheckConfig::CargoCommand {
|
Some(_) | None => {
|
||||||
command: self.data.check_command.clone(),
|
let mut extra_args = self.check_extra_args();
|
||||||
target_triples: self
|
add_target_dir_to_args(&mut extra_args, target_directory);
|
||||||
.data
|
|
||||||
.check_targets
|
FlycheckConfig::CargoCommand {
|
||||||
.clone()
|
command: self.data.check_command.clone(),
|
||||||
.and_then(|targets| match &targets.0[..] {
|
target_triples: self
|
||||||
[] => None,
|
.data
|
||||||
targets => Some(targets.into()),
|
.check_targets
|
||||||
})
|
.clone()
|
||||||
.unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()),
|
.and_then(|targets| match &targets.0[..] {
|
||||||
all_targets: self.data.check_allTargets,
|
[] => None,
|
||||||
no_default_features: self
|
targets => Some(targets.into()),
|
||||||
.data
|
})
|
||||||
.check_noDefaultFeatures
|
.unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()),
|
||||||
.unwrap_or(self.data.cargo_noDefaultFeatures),
|
all_targets: self.data.check_allTargets,
|
||||||
all_features: matches!(
|
no_default_features: self
|
||||||
self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features),
|
.data
|
||||||
CargoFeaturesDef::All
|
.check_noDefaultFeatures
|
||||||
),
|
.unwrap_or(self.data.cargo_noDefaultFeatures),
|
||||||
features: match self
|
all_features: matches!(
|
||||||
.data
|
self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features),
|
||||||
.check_features
|
CargoFeaturesDef::All
|
||||||
.clone()
|
),
|
||||||
.unwrap_or_else(|| self.data.cargo_features.clone())
|
features: match self
|
||||||
{
|
.data
|
||||||
CargoFeaturesDef::All => vec![],
|
.check_features
|
||||||
CargoFeaturesDef::Selected(it) => it,
|
.clone()
|
||||||
},
|
.unwrap_or_else(|| self.data.cargo_features.clone())
|
||||||
extra_args: self.check_extra_args(),
|
{
|
||||||
extra_env: self.check_extra_env(),
|
CargoFeaturesDef::All => vec![],
|
||||||
ansi_color_output: self.color_diagnostic_output(),
|
CargoFeaturesDef::Selected(it) => it,
|
||||||
},
|
},
|
||||||
|
extra_args,
|
||||||
|
extra_env: self.check_extra_env(),
|
||||||
|
ansi_color_output: self.color_diagnostic_output(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn target_dir_from_config(&self) -> Option<String> {
|
||||||
|
self.data
|
||||||
|
.rust_analyzerTargetDir
|
||||||
|
.as_ref()
|
||||||
|
.map(|target_dir| match target_dir {
|
||||||
|
TargetDirectory::UseSubdirectory(yes) if *yes => {
|
||||||
|
Some(String::from("target/rust-analyzer"))
|
||||||
|
}
|
||||||
|
TargetDirectory::UseSubdirectory(_) => None,
|
||||||
|
TargetDirectory::Directory(dir) => Some(dir.clone()),
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_on_save(&self) -> bool {
|
pub fn check_on_save(&self) -> bool {
|
||||||
self.data.checkOnSave
|
self.data.checkOnSave
|
||||||
}
|
}
|
||||||
|
@ -1690,6 +1725,13 @@ impl Config {
|
||||||
self.is_visual_studio_code
|
self.is_visual_studio_code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_target_dir_to_args(args: &mut Vec<String>, target_dir: Option<String>) {
|
||||||
|
if let Some(target_dir) = target_dir {
|
||||||
|
args.push(format!("--target-dir={}", target_dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Deserialization definitions
|
// Deserialization definitions
|
||||||
|
|
||||||
macro_rules! create_bool_or_string_de {
|
macro_rules! create_bool_or_string_de {
|
||||||
|
@ -2037,6 +2079,14 @@ pub enum MemoryLayoutHoverRenderKindDef {
|
||||||
Both,
|
Both,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum TargetDirectory {
|
||||||
|
UseSubdirectory(bool),
|
||||||
|
Directory(String),
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! _config_data {
|
macro_rules! _config_data {
|
||||||
(struct $name:ident {
|
(struct $name:ident {
|
||||||
$(
|
$(
|
||||||
|
@ -2465,6 +2515,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"Option<TargetDirectory>" => set! {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
_ => panic!("missing entry for {ty}: {default}"),
|
_ => panic!("missing entry for {ty}: {default}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2625,4 +2688,73 @@ mod tests {
|
||||||
Some(AbsPathBuf::try_from(project_root().join("./server")).unwrap())
|
Some(AbsPathBuf::try_from(project_root().join("./server")).unwrap())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cargo_target_dir_unset() {
|
||||||
|
let mut config = Config::new(
|
||||||
|
AbsPathBuf::try_from(project_root()).unwrap(),
|
||||||
|
Default::default(),
|
||||||
|
vec![],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
config
|
||||||
|
.update(serde_json::json!({
|
||||||
|
"rust": { "analyzerTargetDir": null }
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(config.data.rust_analyzerTargetDir, None);
|
||||||
|
assert_eq!(config.cargo().extra_args.len(), 0);
|
||||||
|
assert!(
|
||||||
|
matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args.is_empty())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cargo_target_dir_subdir() {
|
||||||
|
let mut config = Config::new(
|
||||||
|
AbsPathBuf::try_from(project_root()).unwrap(),
|
||||||
|
Default::default(),
|
||||||
|
vec![],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
config
|
||||||
|
.update(serde_json::json!({
|
||||||
|
"rust": { "analyzerTargetDir": true }
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
config.data.rust_analyzerTargetDir,
|
||||||
|
Some(TargetDirectory::UseSubdirectory(true))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
config.cargo().extra_args,
|
||||||
|
vec!["--target-dir=target/rust-analyzer".to_string()]
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args == vec!["--target-dir=target/rust-analyzer".to_string()])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cargo_target_dir_relative_dir() {
|
||||||
|
let mut config = Config::new(
|
||||||
|
AbsPathBuf::try_from(project_root()).unwrap(),
|
||||||
|
Default::default(),
|
||||||
|
vec![],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
config
|
||||||
|
.update(serde_json::json!({
|
||||||
|
"rust": { "analyzerTargetDir": "other_folder" }
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
config.data.rust_analyzerTargetDir,
|
||||||
|
Some(TargetDirectory::Directory("other_folder".to_string()))
|
||||||
|
);
|
||||||
|
assert_eq!(config.cargo().extra_args, vec!["--target-dir=other_folder".to_string()]);
|
||||||
|
assert!(
|
||||||
|
matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args == vec!["--target-dir=other_folder".to_string()])
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -757,6 +757,15 @@ Command to be executed instead of 'cargo' for runnables.
|
||||||
Additional arguments to be passed to cargo for runnables such as
|
Additional arguments to be passed to cargo for runnables such as
|
||||||
tests or binaries. For example, it may be `--release`.
|
tests or binaries. For example, it may be `--release`.
|
||||||
--
|
--
|
||||||
|
[[rust-analyzer.rust.analyzerTargetDir]]rust-analyzer.rust.analyzerTargetDir (default: `null`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
Optional path to a rust-analyzer specific target directory.
|
||||||
|
This is useful to prevent rust-analyzer's `cargo check` from blocking builds.
|
||||||
|
|
||||||
|
Set to `true` to use a subdirectory of the existing target directory or
|
||||||
|
set to a path to use that path.
|
||||||
|
--
|
||||||
[[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`)::
|
[[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`)::
|
||||||
+
|
+
|
||||||
--
|
--
|
||||||
|
|
|
@ -1488,6 +1488,21 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rust-analyzer.rust.analyzerTargetDir": {
|
||||||
|
"markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis is useful to prevent rust-analyzer's `cargo check` from blocking builds.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path to use that path.",
|
||||||
|
"default": null,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"rust-analyzer.rustc.source": {
|
"rust-analyzer.rustc.source": {
|
||||||
"markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.",
|
"markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.",
|
||||||
"default": null,
|
"default": null,
|
||||||
|
|
Loading…
Reference in a new issue