Skip to content

Commit f012eda

Browse files
committed
tasks/rust: Add support for running examples as binary targets
1 parent 89e4639 commit f012eda

File tree

1 file changed

+64
-12
lines changed

1 file changed

+64
-12
lines changed

crates/languages/src/rust.rs

Lines changed: 64 additions & 12 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(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
}

0 commit comments

Comments
 (0)