Skip to content

Add config option to use rust-analyzer specific target dir #15681

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/flycheck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub enum FlycheckConfig {
extra_args: Vec<String>,
extra_env: FxHashMap<String, String>,
ansi_color_output: bool,
target_dir: Option<PathBuf>,
},
CustomCommand {
command: String,
Expand Down Expand Up @@ -308,6 +309,7 @@ impl FlycheckActor {
features,
extra_env,
ansi_color_output,
target_dir,
} => {
let mut cmd = Command::new(toolchain::cargo());
cmd.arg(command);
Expand Down Expand Up @@ -340,6 +342,9 @@ impl FlycheckActor {
cmd.arg(features.join(" "));
}
}
if let Some(target_dir) = target_dir {
cmd.arg("--target-dir").arg(target_dir);
}
cmd.envs(extra_env);
(cmd, extra_args)
}
Expand Down
4 changes: 4 additions & 0 deletions crates/project-model/src/build_scripts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ impl WorkspaceBuildScripts {
cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
cmd.args(&config.extra_args);

if let Some(target_dir) = &config.target_dir {
cmd.arg("--target-dir").arg(target_dir);
}

// --all-targets includes tests, benches and examples in addition to the
// default lib and bins. This is an independent concept from the --target
// flag below.
Expand Down
2 changes: 2 additions & 0 deletions crates/project-model/src/cargo_workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pub struct CargoConfig {
pub extra_env: FxHashMap<String, String>,
pub invocation_strategy: InvocationStrategy,
pub invocation_location: InvocationLocation,
/// Optional path to use instead of `target` when building
pub target_dir: Option<PathBuf>,
}

pub type Package = Idx<PackageData>;
Expand Down
104 changes: 104 additions & 0 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,14 @@ config_data! {
/// tests or binaries. For example, it may be `--release`.
runnables_extraArgs: Vec<String> = "[]",

/// Optional path to a rust-analyzer specific target directory.
/// This prevents rust-analyzer's `cargo check` from locking the `Cargo.lock`
/// at the expense of duplicating build artifacts.
///
/// Set to `true` to use a subdirectory of the existing target directory or
/// set to a path relative to the workspace to use that path.
rust_analyzerTargetDir: Option<TargetDirectory> = "null",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would have made sense to call this cargo_ instead.


/// 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
/// is installed.
Expand Down Expand Up @@ -1263,6 +1271,7 @@ impl Config {
run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
extra_args: self.data.cargo_extraArgs.clone(),
extra_env: self.data.cargo_extraEnv.clone(),
target_dir: self.target_dir_from_config(),
}
}

Expand Down Expand Up @@ -1335,10 +1344,21 @@ impl Config {
extra_args: self.check_extra_args(),
extra_env: self.check_extra_env(),
ansi_color_output: self.color_diagnostic_output(),
target_dir: self.target_dir_from_config(),
},
}
}

fn target_dir_from_config(&self) -> Option<PathBuf> {
self.data.rust_analyzerTargetDir.as_ref().and_then(|target_dir| match target_dir {
TargetDirectory::UseSubdirectory(yes) if *yes => {
Some(PathBuf::from("target/rust-analyzer"))
}
TargetDirectory::UseSubdirectory(_) => None,
TargetDirectory::Directory(dir) => Some(dir.clone()),
})
}

pub fn check_on_save(&self) -> bool {
self.data.checkOnSave
}
Expand Down Expand Up @@ -2037,6 +2057,14 @@ pub enum MemoryLayoutHoverRenderKindDef {
Both,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(untagged)]
pub enum TargetDirectory {
UseSubdirectory(bool),
Directory(PathBuf),
}

macro_rules! _config_data {
(struct $name:ident {
$(
Expand Down Expand Up @@ -2465,6 +2493,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}"),
}

Expand Down Expand Up @@ -2625,4 +2666,67 @@ mod tests {
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!(
matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == None)
);
}

#[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!(
matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("target/rust-analyzer")))
);
}

#[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(PathBuf::from("other_folder")))
);
assert!(
matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("other_folder")))
);
}
}
10 changes: 10 additions & 0 deletions docs/user/generated_config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,16 @@ Command to be executed instead of 'cargo' for runnables.
Additional arguments to be passed to cargo for runnables such as
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 prevents rust-analyzer's `cargo check` from locking the `Cargo.lock`
at the expense of duplicating build artifacts.

Set to `true` to use a subdirectory of the existing target directory or
set to a path relative to the workspace to use that path.
--
[[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`)::
+
--
Expand Down
15 changes: 15 additions & 0 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,21 @@
"type": "string"
}
},
"rust-analyzer.rust.analyzerTargetDir": {
"markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis prevents rust-analyzer's `cargo check` from locking the `Cargo.lock`\nat the expense of duplicating build artifacts.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.",
"default": null,
"anyOf": [
{
"type": "null"
},
{
"type": "boolean"
},
{
"type": "string"
}
]
},
"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.",
"default": null,
Expand Down