Skip to content

Commit 95a047c

Browse files
authored
tasks/rust: Add support for running examples as binary targets (#21412)
Closes #21044 Release Notes: - Added support for running Rust examples as tasks.
1 parent dbe4182 commit 95a047c

File tree

1 file changed

+80
-14
lines changed

1 file changed

+80
-14
lines changed

crates/languages/src/rust.rs

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub use language::*;
1010
use lsp::{LanguageServerBinary, LanguageServerName};
1111
use regex::Regex;
1212
use smol::fs::{self};
13+
use std::fmt::Display;
1314
use std::{
1415
any::Any,
1516
borrow::Cow,
@@ -444,6 +445,10 @@ const RUST_PACKAGE_TASK_VARIABLE: VariableName =
444445
const RUST_BIN_NAME_TASK_VARIABLE: VariableName =
445446
VariableName::Custom(Cow::Borrowed("RUST_BIN_NAME"));
446447

448+
/// The bin kind (bin/example) corresponding to the current file in Cargo.toml
449+
const RUST_BIN_KIND_TASK_VARIABLE: VariableName =
450+
VariableName::Custom(Cow::Borrowed("RUST_BIN_KIND"));
451+
447452
const RUST_MAIN_FUNCTION_TASK_VARIABLE: VariableName =
448453
VariableName::Custom(Cow::Borrowed("_rust_main_function_end"));
449454

@@ -469,12 +474,16 @@ impl ContextProvider for RustContextProvider {
469474
.is_some();
470475

471476
if is_main_function {
472-
if let Some((package_name, bin_name)) = local_abs_path.and_then(|path| {
477+
if let Some(target) = local_abs_path.and_then(|path| {
473478
package_name_and_bin_name_from_abs_path(path, project_env.as_ref())
474479
}) {
475480
return Task::ready(Ok(TaskVariables::from_iter([
476-
(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name),
477-
(RUST_BIN_NAME_TASK_VARIABLE.clone(), bin_name),
481+
(RUST_PACKAGE_TASK_VARIABLE.clone(), target.package_name),
482+
(RUST_BIN_NAME_TASK_VARIABLE.clone(), target.target_name),
483+
(
484+
RUST_BIN_KIND_TASK_VARIABLE.clone(),
485+
target.target_kind.to_string(),
486+
),
478487
])));
479488
}
480489
}
@@ -568,16 +577,17 @@ impl ContextProvider for RustContextProvider {
568577
},
569578
TaskTemplate {
570579
label: format!(
571-
"cargo run -p {} --bin {}",
580+
"cargo run -p {} --{} {}",
572581
RUST_PACKAGE_TASK_VARIABLE.template_value(),
582+
RUST_BIN_KIND_TASK_VARIABLE.template_value(),
573583
RUST_BIN_NAME_TASK_VARIABLE.template_value(),
574584
),
575585
command: "cargo".into(),
576586
args: vec![
577587
"run".into(),
578588
"-p".into(),
579589
RUST_PACKAGE_TASK_VARIABLE.template_value(),
580-
"--bin".into(),
590+
format!("--{}", RUST_BIN_KIND_TASK_VARIABLE.template_value()),
581591
RUST_BIN_NAME_TASK_VARIABLE.template_value(),
582592
],
583593
cwd: Some("$ZED_DIRNAME".to_owned()),
@@ -635,10 +645,42 @@ struct CargoTarget {
635645
src_path: String,
636646
}
637647

648+
#[derive(Debug, PartialEq)]
649+
enum TargetKind {
650+
Bin,
651+
Example,
652+
}
653+
654+
impl Display for TargetKind {
655+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
656+
match self {
657+
TargetKind::Bin => write!(f, "bin"),
658+
TargetKind::Example => write!(f, "example"),
659+
}
660+
}
661+
}
662+
663+
impl TryFrom<&str> for TargetKind {
664+
type Error = ();
665+
fn try_from(value: &str) -> Result<Self, ()> {
666+
match value {
667+
"bin" => Ok(Self::Bin),
668+
"example" => Ok(Self::Example),
669+
_ => Err(()),
670+
}
671+
}
672+
}
673+
/// Which package and binary target are we in?
674+
struct TargetInfo {
675+
package_name: String,
676+
target_name: String,
677+
target_kind: TargetKind,
678+
}
679+
638680
fn package_name_and_bin_name_from_abs_path(
639681
abs_path: &Path,
640682
project_env: Option<&HashMap<String, String>>,
641-
) -> Option<(String, String)> {
683+
) -> Option<TargetInfo> {
642684
let mut command = util::command::new_std_command("cargo");
643685
if let Some(envs) = project_env {
644686
command.envs(envs);
@@ -656,24 +698,34 @@ fn package_name_and_bin_name_from_abs_path(
656698
let metadata: CargoMetadata = serde_json::from_slice(&output).log_err()?;
657699

658700
retrieve_package_id_and_bin_name_from_metadata(metadata, abs_path).and_then(
659-
|(package_id, bin_name)| {
701+
|(package_id, bin_name, target_kind)| {
660702
let package_name = package_name_from_pkgid(&package_id);
661703

662-
package_name.map(|package_name| (package_name.to_owned(), bin_name))
704+
package_name.map(|package_name| TargetInfo {
705+
package_name: package_name.to_owned(),
706+
target_name: bin_name,
707+
target_kind,
708+
})
663709
},
664710
)
665711
}
666712

667713
fn retrieve_package_id_and_bin_name_from_metadata(
668714
metadata: CargoMetadata,
669715
abs_path: &Path,
670-
) -> Option<(String, String)> {
716+
) -> Option<(String, String, TargetKind)> {
671717
for package in metadata.packages {
672718
for target in package.targets {
673-
let is_bin = target.kind.iter().any(|kind| kind == "bin");
719+
let Some(bin_kind) = target
720+
.kind
721+
.iter()
722+
.find_map(|kind| TargetKind::try_from(kind.as_ref()).ok())
723+
else {
724+
continue;
725+
};
674726
let target_path = PathBuf::from(target.src_path);
675-
if target_path == abs_path && is_bin {
676-
return Some((package.id, target.name));
727+
if target_path == abs_path {
728+
return Some((package.id, target.name, bin_kind));
677729
}
678730
}
679731
}
@@ -1066,14 +1118,28 @@ mod tests {
10661118
(
10671119
r#"{"packages":[{"id":"path+file:///path/to/zed/crates/zed#0.131.0","targets":[{"name":"zed","kind":["bin"],"src_path":"/path/to/zed/src/main.rs"}]}]}"#,
10681120
"/path/to/zed/src/main.rs",
1069-
Some(("path+file:///path/to/zed/crates/zed#0.131.0", "zed")),
1121+
Some((
1122+
"path+file:///path/to/zed/crates/zed#0.131.0",
1123+
"zed",
1124+
TargetKind::Bin,
1125+
)),
10701126
),
10711127
(
10721128
r#"{"packages":[{"id":"path+file:///path/to/custom-package#[email protected]","targets":[{"name":"my-custom-bin","kind":["bin"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#,
10731129
"/path/to/custom-package/src/main.rs",
10741130
Some((
10751131
"path+file:///path/to/custom-package#[email protected]",
10761132
"my-custom-bin",
1133+
TargetKind::Bin,
1134+
)),
1135+
),
1136+
(
1137+
r#"{"packages":[{"id":"path+file:///path/to/custom-package#[email protected]","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#,
1138+
"/path/to/custom-package/src/main.rs",
1139+
Some((
1140+
"path+file:///path/to/custom-package#[email protected]",
1141+
"my-custom-bin",
1142+
TargetKind::Example,
10771143
)),
10781144
),
10791145
(
@@ -1088,7 +1154,7 @@ mod tests {
10881154

10891155
assert_eq!(
10901156
retrieve_package_id_and_bin_name_from_metadata(metadata, absolute_path),
1091-
expected.map(|(pkgid, bin)| (pkgid.to_owned(), bin.to_owned()))
1157+
expected.map(|(pkgid, name, kind)| (pkgid.to_owned(), name.to_owned(), kind))
10921158
);
10931159
}
10941160
}

0 commit comments

Comments
 (0)