Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21308 from dfireBird/runnable-subcommand-config
feat: implement configuration to change sub command for test, bench and doctest
| -rw-r--r-- | crates/rust-analyzer/src/config.rs | 40 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/lsp/to_proto.rs | 53 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/target_spec.rs | 61 | ||||
| -rw-r--r-- | docs/book/src/configuration_generated.md | 50 | ||||
| -rw-r--r-- | editors/code/package.json | 68 |
5 files changed, 250 insertions, 22 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1b2d8c8d14..e39569e108 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -904,8 +904,24 @@ config_data! { /// This config takes a map of crate names with the exported proc-macro names to ignore as values. procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>> = FxHashMap::default(), + /// Subcommand used for bench runnables instead of `bench`. + runnables_bench_command: String = "bench".to_owned(), + /// Override the command used for bench runnables. + /// The first element of the array should be the program to execute (for example, `cargo`). + /// + /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically + /// replace the package name, target option (such as `--bin` or `--example`), the target name and + /// the test name (name of test function or test mod path). + runnables_bench_overrideCommand: Option<Vec<String>> = None, /// Command to be executed instead of 'cargo' for runnables. runnables_command: Option<String> = None, + /// Override the command used for bench runnables. + /// The first element of the array should be the program to execute (for example, `cargo`). + /// + /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically + /// replace the package name, target option (such as `--bin` or `--example`), the target name and + /// the test name (name of test function or test mod path). + runnables_doctest_overrideCommand: Option<Vec<String>> = None, /// Additional arguments to be passed to cargo for runnables such as /// tests or binaries. For example, it may be `--release`. runnables_extraArgs: Vec<String> = vec![], @@ -917,6 +933,15 @@ config_data! { /// they will end up being interpreted as options to /// [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments). runnables_extraTestBinaryArgs: Vec<String> = vec!["--nocapture".to_owned()], + /// Subcommand used for test runnables instead of `test`. + runnables_test_command: String = "test".to_owned(), + /// Override the command used for test runnables. + /// The first element of the array should be the program to execute (for example, `cargo`). + /// + /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically + /// replace the package name, target option (such as `--bin` or `--example`), the target name and + /// the test name (name of test function or test mod path). + runnables_test_overrideCommand: Option<Vec<String>> = None, /// 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 @@ -1568,6 +1593,16 @@ pub struct RunnablesConfig { pub cargo_extra_args: Vec<String>, /// Additional arguments for the binary being run, if it is a test or benchmark. pub extra_test_binary_args: Vec<String>, + /// Subcommand used for doctest runnables instead of `test`. + pub test_command: String, + /// Override the command used for test runnables. + pub test_override_command: Option<Vec<String>>, + /// Subcommand used for doctest runnables instead of `bench`. + pub bench_command: String, + /// Override the command used for bench runnables. + pub bench_override_command: Option<Vec<String>>, + /// Override the command used for doctest runnables. + pub doc_test_override_command: Option<Vec<String>>, } /// Configuration for workspace symbol search requests. @@ -2494,6 +2529,11 @@ impl Config { override_cargo: self.runnables_command(source_root).clone(), cargo_extra_args: self.runnables_extraArgs(source_root).clone(), extra_test_binary_args: self.runnables_extraTestBinaryArgs(source_root).clone(), + test_command: self.runnables_test_command(source_root).clone(), + test_override_command: self.runnables_test_overrideCommand(source_root).clone(), + bench_command: self.runnables_bench_command(source_root).clone(), + bench_override_command: self.runnables_bench_overrideCommand(source_root).clone(), + doc_test_override_command: self.runnables_doctest_overrideCommand(source_root).clone(), } } diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index 86a35c7d11..6f0f57725f 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -1561,6 +1561,9 @@ pub(crate) fn runnable( let target = spec.target.clone(); + let override_command = + CargoTargetSpec::override_command(snap, Some(spec.clone()), &runnable.kind); + let (cargo_args, executable_args) = CargoTargetSpec::runnable_args( snap, Some(spec.clone()), @@ -1576,23 +1579,41 @@ pub(crate) fn runnable( let label = runnable.label(Some(&target)); let location = location_link(snap, None, runnable.nav)?; - Ok(Some(lsp_ext::Runnable { - label, - location: Some(location), - kind: lsp_ext::RunnableKind::Cargo, - args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { - workspace_root: Some(workspace_root.into()), - override_cargo: config.override_cargo, - cargo_args, - cwd: cwd.into(), - executable_args, - environment: spec - .sysroot_root - .map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string())) - .into_iter() - .collect(), + let environment = spec + .sysroot_root + .map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string())) + .into_iter() + .collect(); + + Ok(match override_command { + Some(override_command) => match override_command.split_first() { + Some((program, args)) => Some(lsp_ext::Runnable { + label, + location: Some(location), + kind: lsp_ext::RunnableKind::Shell, + args: lsp_ext::RunnableArgs::Shell(lsp_ext::ShellRunnableArgs { + environment, + cwd: cwd.into(), + program: program.to_string(), + args: args.to_vec(), + }), + }), + _ => None, + }, + None => Some(lsp_ext::Runnable { + label, + location: Some(location), + kind: lsp_ext::RunnableKind::Cargo, + args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { + workspace_root: Some(workspace_root.into()), + override_cargo: config.override_cargo, + cargo_args, + cwd: cwd.into(), + executable_args, + environment, + }), }), - })) + }) } Some(TargetSpec::ProjectJson(spec)) => { let label = runnable.label(Some(&spec.label)); diff --git a/crates/rust-analyzer/src/target_spec.rs b/crates/rust-analyzer/src/target_spec.rs index e532d15553..e0f95a7830 100644 --- a/crates/rust-analyzer/src/target_spec.rs +++ b/crates/rust-analyzer/src/target_spec.rs @@ -123,7 +123,7 @@ impl CargoTargetSpec { match kind { RunnableKind::Test { test_id, attr } => { - cargo_args.push("test".to_owned()); + cargo_args.push(config.test_command); executable_args.push(test_id.to_string()); if let TestId::Path(_) = test_id { executable_args.push("--exact".to_owned()); @@ -134,12 +134,12 @@ impl CargoTargetSpec { } } RunnableKind::TestMod { path } => { - cargo_args.push("test".to_owned()); + cargo_args.push(config.test_command); executable_args.push(path.clone()); executable_args.extend(extra_test_binary_args); } RunnableKind::Bench { test_id } => { - cargo_args.push("bench".to_owned()); + cargo_args.push(config.bench_command); executable_args.push(test_id.to_string()); if let TestId::Path(_) = test_id { executable_args.push("--exact".to_owned()); @@ -154,10 +154,12 @@ impl CargoTargetSpec { } RunnableKind::Bin => { let subcommand = match spec { - Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => "test", - _ => "run", + Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => { + config.test_command + } + _ => "run".to_owned(), }; - cargo_args.push(subcommand.to_owned()); + cargo_args.push(subcommand); } } @@ -206,6 +208,53 @@ impl CargoTargetSpec { (cargo_args, executable_args) } + pub(crate) fn override_command( + snap: &GlobalStateSnapshot, + spec: Option<CargoTargetSpec>, + kind: &RunnableKind, + ) -> Option<Vec<String>> { + let config = snap.config.runnables(None); + let (args, test_name) = match kind { + RunnableKind::Test { test_id, .. } => { + (config.test_override_command, Some(test_id.to_string())) + } + RunnableKind::TestMod { path } => (config.test_override_command, Some(path.clone())), + RunnableKind::Bench { test_id } => { + (config.bench_override_command, Some(test_id.to_string())) + } + RunnableKind::DocTest { test_id } => { + (config.doc_test_override_command, Some(test_id.to_string())) + } + RunnableKind::Bin => match spec { + Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => { + (config.test_override_command, None) + } + _ => (None, None), + }, + }; + let test_name = test_name.unwrap_or_default(); + + let target_arg = |kind| match kind { + TargetKind::Bin => "--bin", + TargetKind::Test => "--test", + TargetKind::Bench => "--bench", + TargetKind::Example => "--example", + TargetKind::Lib { .. } => "--lib", + TargetKind::BuildScript | TargetKind::Other => "", + }; + + let replace_placeholders = |arg: String| match &spec { + Some(spec) => arg + .replace("${package}", &spec.package) + .replace("${target_arg}", target_arg(spec.target_kind)) + .replace("${target}", &spec.target) + .replace("${test_name}", &test_name), + _ => arg, + }; + + args.map(|args| args.into_iter().map(replace_placeholders).collect()) + } + pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) { buf.push("--package".to_owned()); buf.push(self.package); diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index e208dbadea..58b6363345 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md @@ -1348,6 +1348,25 @@ Default: `true` Whether to warn when a rename will cause conflicts (change the meaning of the code). +## rust-analyzer.runnables.bench.command {#runnables.bench.command} + +Default: `"bench"` + +Subcommand used for bench runnables instead of `bench`. + + +## rust-analyzer.runnables.bench.overrideCommand {#runnables.bench.overrideCommand} + +Default: `null` + +Override the command used for bench runnables. +The first element of the array should be the program to execute (for example, `cargo`). + +Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically +replace the package name, target option (such as `--bin` or `--example`), the target name and +the test name (name of test function or test mod path). + + ## rust-analyzer.runnables.command {#runnables.command} Default: `null` @@ -1355,6 +1374,18 @@ Default: `null` Command to be executed instead of 'cargo' for runnables. +## rust-analyzer.runnables.doctest.overrideCommand {#runnables.doctest.overrideCommand} + +Default: `null` + +Override the command used for bench runnables. +The first element of the array should be the program to execute (for example, `cargo`). + +Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically +replace the package name, target option (such as `--bin` or `--example`), the target name and +the test name (name of test function or test mod path). + + ## rust-analyzer.runnables.extraArgs {#runnables.extraArgs} Default: `[]` @@ -1381,6 +1412,25 @@ they will end up being interpreted as options to [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments). +## rust-analyzer.runnables.test.command {#runnables.test.command} + +Default: `"test"` + +Subcommand used for test runnables instead of `test`. + + +## rust-analyzer.runnables.test.overrideCommand {#runnables.test.overrideCommand} + +Default: `null` + +Override the command used for test runnables. +The first element of the array should be the program to execute (for example, `cargo`). + +Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically +replace the package name, target option (such as `--bin` or `--example`), the target name and +the test name (name of test function or test mod path). + + ## rust-analyzer.rustc.source {#rustc.source} Default: `null` diff --git a/editors/code/package.json b/editors/code/package.json index 4817218962..2157cbd486 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -2829,6 +2829,32 @@ { "title": "Runnables", "properties": { + "rust-analyzer.runnables.bench.command": { + "markdownDescription": "Subcommand used for bench runnables instead of `bench`.", + "default": "bench", + "type": "string" + } + } + }, + { + "title": "Runnables", + "properties": { + "rust-analyzer.runnables.bench.overrideCommand": { + "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + } + } + }, + { + "title": "Runnables", + "properties": { "rust-analyzer.runnables.command": { "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", "default": null, @@ -2842,6 +2868,22 @@ { "title": "Runnables", "properties": { + "rust-analyzer.runnables.doctest.overrideCommand": { + "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + } + } + }, + { + "title": "Runnables", + "properties": { "rust-analyzer.runnables.extraArgs": { "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.", "default": [], @@ -2868,6 +2910,32 @@ } }, { + "title": "Runnables", + "properties": { + "rust-analyzer.runnables.test.command": { + "markdownDescription": "Subcommand used for test runnables instead of `test`.", + "default": "test", + "type": "string" + } + } + }, + { + "title": "Runnables", + "properties": { + "rust-analyzer.runnables.test.overrideCommand": { + "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + } + } + }, + { "title": "Rustc", "properties": { "rust-analyzer.rustc.source": { |