Skip to content

Commit 804bcd8

Browse files
authored
Merge pull request #22295 from sunshowers/runnable-kind
Use runnable kind to disambiguate between cargo and shell commands
2 parents 75aa859 + 626137b commit 804bcd8

4 files changed

Lines changed: 94 additions & 17 deletions

File tree

crates/rust-analyzer/src/handlers/request.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,6 @@ pub(crate) fn handle_runnables(
10491049
all_targets = if all_targets { " --all-targets" } else { "" }
10501050
),
10511051
location: None,
1052-
kind: lsp_ext::RunnableKind::Cargo,
10531052
args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
10541053
workspace_root: Some(spec.workspace_root.clone().into()),
10551054
cwd: cwd.into(),
@@ -1076,7 +1075,6 @@ pub(crate) fn handle_runnables(
10761075
res.push(lsp_ext::Runnable {
10771076
label: "cargo check --workspace".to_owned(),
10781077
location: None,
1079-
kind: lsp_ext::RunnableKind::Cargo,
10801078
args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
10811079
workspace_root: None,
10821080
cwd: path.as_path().unwrap().to_path_buf().into(),

crates/rust-analyzer/src/lsp/ext.rs

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -451,25 +451,17 @@ pub struct Runnable {
451451
pub label: String,
452452
#[serde(skip_serializing_if = "Option::is_none")]
453453
pub location: Option<lsp_types::LocationLink>,
454-
pub kind: RunnableKind,
454+
#[serde(flatten)]
455455
pub args: RunnableArgs,
456456
}
457457

458458
#[derive(Deserialize, Serialize, Debug, Clone)]
459-
#[serde(rename_all = "camelCase")]
460-
#[serde(untagged)]
459+
#[serde(tag = "kind", content = "args", rename_all = "lowercase")]
461460
pub enum RunnableArgs {
462461
Cargo(CargoRunnableArgs),
463462
Shell(ShellRunnableArgs),
464463
}
465464

466-
#[derive(Serialize, Deserialize, Debug, Clone)]
467-
#[serde(rename_all = "lowercase")]
468-
pub enum RunnableKind {
469-
Cargo,
470-
Shell,
471-
}
472-
473465
#[derive(Deserialize, Serialize, Debug, Clone)]
474466
#[serde(rename_all = "camelCase")]
475467
pub struct CargoRunnableArgs {
@@ -881,3 +873,94 @@ impl Request for GetFailedObligations {
881873
type Result = String;
882874
const METHOD: &'static str = "rust-analyzer/getFailedObligations";
883875
}
876+
877+
#[cfg(test)]
878+
mod tests {
879+
use super::*;
880+
use serde_json::json;
881+
882+
#[test]
883+
fn cargo_runnable_round_trips() {
884+
let runnable = Runnable {
885+
label: "cargo test -p my-crate".to_owned(),
886+
location: None,
887+
args: RunnableArgs::Cargo(CargoRunnableArgs {
888+
environment: [("RUSTC_TOOLCHAIN".to_owned(), "/toolchain".to_owned())]
889+
.into_iter()
890+
.collect(),
891+
cwd: "/project".into(),
892+
override_cargo: None,
893+
workspace_root: Some("/project".into()),
894+
cargo_args: vec![
895+
"test".into(),
896+
"--package".into(),
897+
"my-crate".into(),
898+
"--lib".into(),
899+
],
900+
executable_args: vec!["my_test".into(), "--exact".into()],
901+
}),
902+
};
903+
let expected = json!({
904+
"label": "cargo test -p my-crate",
905+
"kind": "cargo",
906+
"args": {
907+
"environment": {"RUSTC_TOOLCHAIN": "/toolchain"},
908+
"cwd": "/project",
909+
"overrideCargo": null,
910+
"workspaceRoot": "/project",
911+
"cargoArgs": ["test", "--package", "my-crate", "--lib"],
912+
"executableArgs": ["my_test", "--exact"],
913+
}
914+
});
915+
916+
let serialized = serde_json::to_value(&runnable).expect("serialized runnable");
917+
assert_eq!(serialized, expected);
918+
919+
let deserialized: Runnable =
920+
serde_json::from_value(expected).expect("cargo runnable should deserialize");
921+
let RunnableArgs::Cargo(cargo) = &deserialized.args else {
922+
panic!("expected Cargo variant, got {:?}", deserialized.args);
923+
};
924+
assert_eq!(cargo.cargo_args, vec!["test", "--package", "my-crate", "--lib"]);
925+
assert_eq!(cargo.executable_args, vec!["my_test", "--exact"]);
926+
}
927+
928+
#[test]
929+
fn shell_runnable_round_trips() {
930+
let runnable = Runnable {
931+
label: "nextest test_one".to_owned(),
932+
location: None,
933+
args: RunnableArgs::Shell(ShellRunnableArgs {
934+
environment: [("RUSTC_TOOLCHAIN".to_owned(), "/toolchain".to_owned())]
935+
.into_iter()
936+
.collect(),
937+
cwd: "/project".into(),
938+
program: "cargo".into(),
939+
args: vec!["nextest".into(), "run".into(), "--package".into(), "my-crate".into()],
940+
}),
941+
};
942+
let expected = json!({
943+
"label": "nextest test_one",
944+
"kind": "shell",
945+
"args": {
946+
"environment": {"RUSTC_TOOLCHAIN": "/toolchain"},
947+
"cwd": "/project",
948+
"program": "cargo",
949+
"args": ["nextest", "run", "--package", "my-crate"],
950+
}
951+
});
952+
953+
let serialized = serde_json::to_value(&runnable).expect("serialized runnable");
954+
assert_eq!(serialized, expected);
955+
956+
// Every shell runnable is a structurally valid cargo runnable if the `kind` tag isn't
957+
// used. This test ensures that the `kind` tag is used.
958+
let deserialized: Runnable =
959+
serde_json::from_value(expected).expect("shell runnable should deserialize");
960+
let RunnableArgs::Shell(shell) = &deserialized.args else {
961+
panic!("expected Shell variant, got {:?}", deserialized.args);
962+
};
963+
assert_eq!(shell.program, "cargo");
964+
assert_eq!(shell.args, vec!["nextest", "run", "--package", "my-crate"]);
965+
}
966+
}

crates/rust-analyzer/src/lsp/to_proto.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,7 +1608,6 @@ pub(crate) fn runnable(
16081608
Some((program, args)) => Some(lsp_ext::Runnable {
16091609
label,
16101610
location: Some(location),
1611-
kind: lsp_ext::RunnableKind::Shell,
16121611
args: lsp_ext::RunnableArgs::Shell(lsp_ext::ShellRunnableArgs {
16131612
environment,
16141613
cwd: cwd.into(),
@@ -1621,7 +1620,6 @@ pub(crate) fn runnable(
16211620
None => Some(lsp_ext::Runnable {
16221621
label,
16231622
location: Some(location),
1624-
kind: lsp_ext::RunnableKind::Cargo,
16251623
args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
16261624
workspace_root: Some(workspace_root.into()),
16271625
override_cargo: config.override_cargo,
@@ -1648,7 +1646,6 @@ pub(crate) fn runnable(
16481646
Ok(Some(lsp_ext::Runnable {
16491647
label,
16501648
location: Some(location),
1651-
kind: lsp_ext::RunnableKind::Shell,
16521649
args: lsp_ext::RunnableArgs::Shell(runnable_args),
16531650
}))
16541651
}
@@ -1668,7 +1665,6 @@ pub(crate) fn runnable(
16681665
Ok(Some(lsp_ext::Runnable {
16691666
label,
16701667
location: Some(location),
1671-
kind: lsp_ext::RunnableKind::Cargo,
16721668
args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
16731669
workspace_root: None,
16741670
override_cargo: config.override_cargo,

docs/book/src/contributing/lsp-extensions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!---
2-
lsp/ext.rs hash: edab2f3c124dc28e
2+
lsp/ext.rs hash: 57ae57d2a5c65b14
33
44
If you need to change the above hash to make the test pass, please check if you
55
need to adjust this doc as well and ping this issue:

0 commit comments

Comments
 (0)