Skip to content

Add flexible configuration for runnables #5954

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 4 commits into from
Oct 2, 2020
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
18 changes: 18 additions & 0 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub struct Config {
pub cargo: CargoConfig,
pub rustfmt: RustfmtConfig,
pub flycheck: Option<FlycheckConfig>,
pub runnables: RunnablesConfig,

pub inlay_hints: InlayHintsConfig,
pub completion: CompletionConfig,
Expand Down Expand Up @@ -124,6 +125,15 @@ pub enum RustfmtConfig {
CustomCommand { command: String, args: Vec<String> },
}

/// Configuration for runnable items, such as `main` function or tests.
#[derive(Debug, Clone, Default)]
pub struct RunnablesConfig {
/// Custom command to be executed instead of `cargo` for runnables.
pub override_cargo: Option<String>,
/// Additional arguments for the `cargo`, e.g. `--release`.
pub cargo_extra_args: Vec<String>,
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
pub location_link: bool,
Expand Down Expand Up @@ -164,6 +174,7 @@ impl Config {
extra_args: Vec::new(),
features: Vec::new(),
}),
runnables: RunnablesConfig::default(),

inlay_hints: InlayHintsConfig {
type_hints: true,
Expand Down Expand Up @@ -220,6 +231,10 @@ impl Config {
load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck,
target: data.cargo_target.clone(),
};
self.runnables = RunnablesConfig {
override_cargo: data.runnables_overrideCargo,
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()]))
Expand Down Expand Up @@ -474,6 +489,9 @@ config_data! {
notifications_cargoTomlNotFound: bool = true,
procMacro_enable: bool = false,

runnables_overrideCargo: Option<String> = None,
runnables_cargoExtraArgs: Vec<String> = Vec::new(),

rustfmt_extraArgs: Vec<String> = Vec::new(),
rustfmt_overrideCommand: Option<Vec<String>> = None,

Expand Down
5 changes: 5 additions & 0 deletions crates/rust-analyzer/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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()),
override_cargo: config.override_cargo.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,
},
Expand All @@ -519,7 +522,9 @@ pub(crate) fn handle_runnables(
kind: lsp_ext::RunnableKind::Cargo,
args: lsp_ext::CargoRunnable {
workspace_root: None,
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(),
expect_test: None,
},
Expand Down
4 changes: 4 additions & 0 deletions crates/rust-analyzer/src/lsp_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,14 @@ pub enum RunnableKind {
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CargoRunnable {
// command to be executed instead of cargo
pub override_cargo: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub workspace_root: Option<PathBuf>,
// command, --package and --lib stuff
pub cargo_args: Vec<String>,
// user-specified additional cargo args, like `--release`.
pub cargo_extra_args: Vec<String>,
// stuff after --
pub executable_args: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
3 changes: 3 additions & 0 deletions crates/rust-analyzer/src/to_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ pub(crate) fn runnable(
file_id: FileId,
runnable: Runnable,
) -> Result<lsp_ext::Runnable> {
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());
Expand All @@ -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()),
override_cargo: config.override_cargo.clone(),
cargo_args,
cargo_extra_args: config.cargo_extra_args.clone(),
executable_args,
expect_test: None,
},
Expand Down
6 changes: 6 additions & 0 deletions crates/rust-analyzer/tests/rust-analyzer/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -127,6 +129,8 @@ fn main() {}
"args": {
"cargoArgs": ["check", "--package", "foo", "--all-targets"],
"executableArgs": [],
"cargoExtraArgs": [],
"overrideCargo": null,
"workspaceRoot": server.path().join("foo")
},
"kind": "cargo",
Expand All @@ -136,6 +140,8 @@ fn main() {}
"args": {
"cargoArgs": ["test", "--package", "foo", "--all-targets"],
"executableArgs": [],
"cargoExtraArgs": [],
"overrideCargo": null,
"workspaceRoot": server.path().join("foo")
},
"kind": "cargo",
Expand Down
16 changes: 16 additions & 0 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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'"
}
}
},
Expand Down
2 changes: 2 additions & 0 deletions editors/code/src/lsp_ext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<RunnablesParams, Runnable[], void>("experimental/runnables");
Expand Down
2 changes: 2 additions & 0 deletions editors/code/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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()
Expand Down
10 changes: 9 additions & 1 deletion editors/code/src/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down
3 changes: 2 additions & 1 deletion editors/code/tests/unit/runnable_env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ function makeRunnable(label: string): ra.Runnable {
kind: "cargo",
args: {
cargoArgs: [],
executableArgs: []
executableArgs: [],
cargoExtraArgs: []
}
};
}
Expand Down