From 2c125f3c638e17837ad44b4a5fd7a96b32018018 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 5 Sep 2020 12:52:27 +0300 Subject: [PATCH 1/4] Add support of runnables arguments in Rust Analyzer --- crates/rust-analyzer/src/config.rs | 18 ++++++++++++++++++ crates/rust-analyzer/src/handlers.rs | 5 +++++ crates/rust-analyzer/src/lsp_ext.rs | 4 ++++ crates/rust-analyzer/src/to_proto.rs | 3 +++ 4 files changed, 30 insertions(+) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 42e1ad376ce..c5dd00706d5 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -38,6 +38,7 @@ pub struct Config { pub cargo: CargoConfig, pub rustfmt: RustfmtConfig, pub flycheck: Option, + pub runnables: RunnablesConfig, pub inlay_hints: InlayHintsConfig, pub completion: CompletionConfig, @@ -124,6 +125,15 @@ pub enum RustfmtConfig { CustomCommand { command: String, args: Vec }, } +/// Configuration for runnable items, such as `main` function or tests. +#[derive(Debug, Clone, Default)] +pub struct RunnablesConfig { + /// Stuff to be inserted before `cargo`, e.g. `RUST_LOG=info`. + pub cargo_prefix: Vec, + /// Additional arguments for the `cargo`, e.g. `--release`. + pub cargo_extra_args: Vec, +} + #[derive(Debug, Clone, Default)] pub struct ClientCapsConfig { pub location_link: bool, @@ -164,6 +174,7 @@ pub fn new(root_path: AbsPathBuf) -> Self { extra_args: Vec::new(), features: Vec::new(), }), + runnables: RunnablesConfig::default(), inlay_hints: InlayHintsConfig { type_hints: true, @@ -220,6 +231,10 @@ pub fn update(&mut self, json: serde_json::Value) { load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck, target: data.cargo_target.clone(), }; + self.runnables = RunnablesConfig { + cargo_prefix: data.runnables_cargoPrefix, + cargo_extra_args: data.runnables_cargoExtraArgs, + }; self.proc_macro_srv = if data.procMacro_enable { std::env::current_exe().ok().map(|path| (path, vec!["proc-macro".into()])) @@ -474,6 +489,9 @@ struct ConfigData { notifications_cargoTomlNotFound: bool = true, procMacro_enable: bool = false, + runnables_cargoPrefix: Vec = Vec::new(), + runnables_cargoExtraArgs: Vec = Vec::new(), + rustfmt_extraArgs: Vec = Vec::new(), rustfmt_overrideCommand: Option> = None, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index afcec63ad16..2a8eca1460a 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -491,6 +491,7 @@ pub(crate) fn handle_runnables( } // Add `cargo check` and `cargo test` for all targets of the whole package + let config = &snap.config.runnables; match cargo_spec { Some(spec) => { for &cmd in ["check", "test"].iter() { @@ -500,12 +501,14 @@ pub(crate) fn handle_runnables( kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { workspace_root: Some(spec.workspace_root.clone().into()), + cargo_prefix: config.cargo_prefix.clone(), cargo_args: vec![ cmd.to_string(), "--package".to_string(), spec.package.clone(), "--all-targets".to_string(), ], + cargo_extra_args: config.cargo_extra_args.clone(), executable_args: Vec::new(), expect_test: None, }, @@ -519,7 +522,9 @@ pub(crate) fn handle_runnables( kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { workspace_root: None, + cargo_prefix: config.cargo_prefix.clone(), cargo_args: vec!["check".to_string(), "--workspace".to_string()], + cargo_extra_args: config.cargo_extra_args.clone(), executable_args: Vec::new(), expect_test: None, }, diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 43ff191dab5..72c4ebfd3c8 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -171,10 +171,14 @@ pub enum RunnableKind { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct CargoRunnable { + // stuff before `cargo` command, e.g. `RUST_LOG=info` + pub cargo_prefix: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub workspace_root: Option, // command, --package and --lib stuff pub cargo_args: Vec, + // user-specified additional cargo args, like `--release`. + pub cargo_extra_args: Vec, // stuff after -- pub executable_args: Vec, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 59e780b7d2e..5dca520c307 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -740,6 +740,7 @@ pub(crate) fn runnable( file_id: FileId, runnable: Runnable, ) -> Result { + let config = &snap.config.runnables; let spec = CargoTargetSpec::for_file(snap, file_id)?; let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); let target = spec.as_ref().map(|s| s.target.clone()); @@ -754,7 +755,9 @@ pub(crate) fn runnable( kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { workspace_root: workspace_root.map(|it| it.into()), + cargo_prefix: config.cargo_prefix.clone(), cargo_args, + cargo_extra_args: config.cargo_extra_args.clone(), executable_args, expect_test: None, }, From 4a1b4b23bb58398a7e2a955e0be43ff2c09fe9e5 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 5 Sep 2020 16:20:33 +0300 Subject: [PATCH 2/4] Replace 'cargo_prefix' option with 'override_cargo' --- crates/rust-analyzer/src/config.rs | 10 +++++----- crates/rust-analyzer/src/handlers.rs | 4 ++-- crates/rust-analyzer/src/lsp_ext.rs | 4 ++-- crates/rust-analyzer/src/to_proto.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c5dd00706d5..0ab4c37bfff 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -128,8 +128,8 @@ pub enum RustfmtConfig { /// Configuration for runnable items, such as `main` function or tests. #[derive(Debug, Clone, Default)] pub struct RunnablesConfig { - /// Stuff to be inserted before `cargo`, e.g. `RUST_LOG=info`. - pub cargo_prefix: Vec, + /// Custom command to be executed instead of `cargo` for runnables. + pub override_cargo: Option, /// Additional arguments for the `cargo`, e.g. `--release`. pub cargo_extra_args: Vec, } @@ -232,7 +232,7 @@ pub fn update(&mut self, json: serde_json::Value) { target: data.cargo_target.clone(), }; self.runnables = RunnablesConfig { - cargo_prefix: data.runnables_cargoPrefix, + override_cargo: data.runnables_overrideCargo, cargo_extra_args: data.runnables_cargoExtraArgs, }; @@ -489,8 +489,8 @@ struct ConfigData { notifications_cargoTomlNotFound: bool = true, procMacro_enable: bool = false, - runnables_cargoPrefix: Vec = Vec::new(), - runnables_cargoExtraArgs: Vec = Vec::new(), + runnables_overrideCargo: Option = None, + runnables_cargoExtraArgs: Vec = Vec::new(), rustfmt_extraArgs: Vec = Vec::new(), rustfmt_overrideCommand: Option> = None, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 2a8eca1460a..e970abb7c08 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -501,7 +501,7 @@ pub(crate) fn handle_runnables( kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { workspace_root: Some(spec.workspace_root.clone().into()), - cargo_prefix: config.cargo_prefix.clone(), + override_cargo: config.override_cargo.clone(), cargo_args: vec![ cmd.to_string(), "--package".to_string(), @@ -522,7 +522,7 @@ pub(crate) fn handle_runnables( kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { workspace_root: None, - cargo_prefix: config.cargo_prefix.clone(), + override_cargo: config.override_cargo.clone(), cargo_args: vec!["check".to_string(), "--workspace".to_string()], cargo_extra_args: config.cargo_extra_args.clone(), executable_args: Vec::new(), diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 72c4ebfd3c8..fee0bb69c70 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -171,8 +171,8 @@ pub enum RunnableKind { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct CargoRunnable { - // stuff before `cargo` command, e.g. `RUST_LOG=info` - pub cargo_prefix: Vec, + // command to be executed instead of cargo + pub override_cargo: Option, #[serde(skip_serializing_if = "Option::is_none")] pub workspace_root: Option, // command, --package and --lib stuff diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 5dca520c307..aeacde0f7a2 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -755,7 +755,7 @@ pub(crate) fn runnable( kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { workspace_root: workspace_root.map(|it| it.into()), - cargo_prefix: config.cargo_prefix.clone(), + override_cargo: config.override_cargo.clone(), cargo_args, cargo_extra_args: config.cargo_extra_args.clone(), executable_args, From 5b26629a4d8ca388db1b272a7c8b8ea37f45c9f9 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 5 Sep 2020 16:21:14 +0300 Subject: [PATCH 3/4] Support 'runnables' options in the vs code extension --- editors/code/package.json | 16 ++++++++++++++++ editors/code/src/lsp_ext.ts | 2 ++ editors/code/src/run.ts | 2 ++ editors/code/src/tasks.ts | 10 +++++++++- editors/code/tests/unit/runnable_env.test.ts | 3 ++- 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index bdd8a0c298f..cc2ac3bd269 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -651,6 +651,22 @@ ], "default": "full", "description": "The strategy to use when inserting new imports or merging imports." + }, + "rust-analyzer.runnables.overrideCargo": { + "type": [ + "null", + "string" + ], + "default": null, + "description": "Command to be executed instead of 'cargo' for runnables." + }, + "rust-analyzer.runnables.cargoExtraArgs": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be '--release'" } } }, diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index eb422d3e759..f286b68a685 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -69,8 +69,10 @@ export interface Runnable { args: { workspaceRoot?: string; cargoArgs: string[]; + cargoExtraArgs: string[]; executableArgs: string[]; expectTest?: boolean; + overrideCargo?: string; }; } export const runnables = new lc.RequestType("experimental/runnables"); diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index de68f27aec5..459b7f250d2 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -129,6 +129,7 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise } const args = [...runnable.args.cargoArgs]; // should be a copy! + args.push(...runnable.args.cargoExtraArgs); // Append user-specified cargo options. if (runnable.args.executableArgs.length > 0) { args.push('--', ...runnable.args.executableArgs); } @@ -139,6 +140,7 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise args: args.slice(1), cwd: runnable.args.workspaceRoot || ".", env: prepareEnv(runnable, config.runnableEnv), + overrideCargo: runnable.args.overrideCargo, }; const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index 14abbd5b794..a3ff1510256 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts @@ -13,6 +13,7 @@ export interface CargoTaskDefinition extends vscode.TaskDefinition { args?: string[]; cwd?: string; env?: { [key: string]: string }; + overrideCargo?: string; } class CargoTaskProvider implements vscode.TaskProvider { @@ -98,7 +99,14 @@ export async function buildCargoTask( } if (!exec) { - exec = new vscode.ShellExecution(toolchain.cargoPath(), args, definition); + // Check whether we must use a user-defined substitute for cargo. + const cargoCommand = definition.overrideCargo ? definition.overrideCargo : toolchain.cargoPath(); + + // Prepare the whole command as one line. It is required if user has provided override command which contains spaces, + // for example "wrapper cargo". Without manual preparation the overridden command will be quoted and fail to execute. + const fullCommand = [cargoCommand, ...args].join(" "); + + exec = new vscode.ShellExecution(fullCommand, definition); } return new vscode.Task( diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts index f2f53e91ad9..c5600cf64f3 100644 --- a/editors/code/tests/unit/runnable_env.test.ts +++ b/editors/code/tests/unit/runnable_env.test.ts @@ -9,7 +9,8 @@ function makeRunnable(label: string): ra.Runnable { kind: "cargo", args: { cargoArgs: [], - executableArgs: [] + executableArgs: [], + cargoExtraArgs: [] } }; } From 4ebacf9024d82349c4b95826a4a791bdf384d0df Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 5 Sep 2020 17:16:32 +0300 Subject: [PATCH 4/4] Fix failing test --- crates/rust-analyzer/tests/rust-analyzer/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs index 06726f9576e..e51eb262615 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/main.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs @@ -107,6 +107,8 @@ fn main() {} "args": { "cargoArgs": ["test", "--package", "foo", "--test", "spam"], "executableArgs": ["test_eggs", "--exact", "--nocapture"], + "cargoExtraArgs": [], + "overrideCargo": null, "workspaceRoot": server.path().join("foo") }, "kind": "cargo", @@ -127,6 +129,8 @@ fn main() {} "args": { "cargoArgs": ["check", "--package", "foo", "--all-targets"], "executableArgs": [], + "cargoExtraArgs": [], + "overrideCargo": null, "workspaceRoot": server.path().join("foo") }, "kind": "cargo", @@ -136,6 +140,8 @@ fn main() {} "args": { "cargoArgs": ["test", "--package", "foo", "--all-targets"], "executableArgs": [], + "cargoExtraArgs": [], + "overrideCargo": null, "workspaceRoot": server.path().join("foo") }, "kind": "cargo",