tasks/rust: Add support for running examples as binary targets (#21412)
Closes #21044 Release Notes: - Added support for running Rust examples as tasks.
This commit is contained in:
parent
dbe41823d9
commit
95a047c11b
1 changed files with 80 additions and 14 deletions
|
@ -10,6 +10,7 @@ pub use language::*;
|
||||||
use lsp::{LanguageServerBinary, LanguageServerName};
|
use lsp::{LanguageServerBinary, LanguageServerName};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use smol::fs::{self};
|
use smol::fs::{self};
|
||||||
|
use std::fmt::Display;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
@ -444,6 +445,10 @@ const RUST_PACKAGE_TASK_VARIABLE: VariableName =
|
||||||
const RUST_BIN_NAME_TASK_VARIABLE: VariableName =
|
const RUST_BIN_NAME_TASK_VARIABLE: VariableName =
|
||||||
VariableName::Custom(Cow::Borrowed("RUST_BIN_NAME"));
|
VariableName::Custom(Cow::Borrowed("RUST_BIN_NAME"));
|
||||||
|
|
||||||
|
/// The bin kind (bin/example) corresponding to the current file in Cargo.toml
|
||||||
|
const RUST_BIN_KIND_TASK_VARIABLE: VariableName =
|
||||||
|
VariableName::Custom(Cow::Borrowed("RUST_BIN_KIND"));
|
||||||
|
|
||||||
const RUST_MAIN_FUNCTION_TASK_VARIABLE: VariableName =
|
const RUST_MAIN_FUNCTION_TASK_VARIABLE: VariableName =
|
||||||
VariableName::Custom(Cow::Borrowed("_rust_main_function_end"));
|
VariableName::Custom(Cow::Borrowed("_rust_main_function_end"));
|
||||||
|
|
||||||
|
@ -469,12 +474,16 @@ impl ContextProvider for RustContextProvider {
|
||||||
.is_some();
|
.is_some();
|
||||||
|
|
||||||
if is_main_function {
|
if is_main_function {
|
||||||
if let Some((package_name, bin_name)) = local_abs_path.and_then(|path| {
|
if let Some(target) = local_abs_path.and_then(|path| {
|
||||||
package_name_and_bin_name_from_abs_path(path, project_env.as_ref())
|
package_name_and_bin_name_from_abs_path(path, project_env.as_ref())
|
||||||
}) {
|
}) {
|
||||||
return Task::ready(Ok(TaskVariables::from_iter([
|
return Task::ready(Ok(TaskVariables::from_iter([
|
||||||
(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name),
|
(RUST_PACKAGE_TASK_VARIABLE.clone(), target.package_name),
|
||||||
(RUST_BIN_NAME_TASK_VARIABLE.clone(), bin_name),
|
(RUST_BIN_NAME_TASK_VARIABLE.clone(), target.target_name),
|
||||||
|
(
|
||||||
|
RUST_BIN_KIND_TASK_VARIABLE.clone(),
|
||||||
|
target.target_kind.to_string(),
|
||||||
|
),
|
||||||
])));
|
])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,8 +577,9 @@ impl ContextProvider for RustContextProvider {
|
||||||
},
|
},
|
||||||
TaskTemplate {
|
TaskTemplate {
|
||||||
label: format!(
|
label: format!(
|
||||||
"cargo run -p {} --bin {}",
|
"cargo run -p {} --{} {}",
|
||||||
RUST_PACKAGE_TASK_VARIABLE.template_value(),
|
RUST_PACKAGE_TASK_VARIABLE.template_value(),
|
||||||
|
RUST_BIN_KIND_TASK_VARIABLE.template_value(),
|
||||||
RUST_BIN_NAME_TASK_VARIABLE.template_value(),
|
RUST_BIN_NAME_TASK_VARIABLE.template_value(),
|
||||||
),
|
),
|
||||||
command: "cargo".into(),
|
command: "cargo".into(),
|
||||||
|
@ -577,7 +587,7 @@ impl ContextProvider for RustContextProvider {
|
||||||
"run".into(),
|
"run".into(),
|
||||||
"-p".into(),
|
"-p".into(),
|
||||||
RUST_PACKAGE_TASK_VARIABLE.template_value(),
|
RUST_PACKAGE_TASK_VARIABLE.template_value(),
|
||||||
"--bin".into(),
|
format!("--{}", RUST_BIN_KIND_TASK_VARIABLE.template_value()),
|
||||||
RUST_BIN_NAME_TASK_VARIABLE.template_value(),
|
RUST_BIN_NAME_TASK_VARIABLE.template_value(),
|
||||||
],
|
],
|
||||||
cwd: Some("$ZED_DIRNAME".to_owned()),
|
cwd: Some("$ZED_DIRNAME".to_owned()),
|
||||||
|
@ -635,10 +645,42 @@ struct CargoTarget {
|
||||||
src_path: String,
|
src_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum TargetKind {
|
||||||
|
Bin,
|
||||||
|
Example,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for TargetKind {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
TargetKind::Bin => write!(f, "bin"),
|
||||||
|
TargetKind::Example => write!(f, "example"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for TargetKind {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(value: &str) -> Result<Self, ()> {
|
||||||
|
match value {
|
||||||
|
"bin" => Ok(Self::Bin),
|
||||||
|
"example" => Ok(Self::Example),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Which package and binary target are we in?
|
||||||
|
struct TargetInfo {
|
||||||
|
package_name: String,
|
||||||
|
target_name: String,
|
||||||
|
target_kind: TargetKind,
|
||||||
|
}
|
||||||
|
|
||||||
fn package_name_and_bin_name_from_abs_path(
|
fn package_name_and_bin_name_from_abs_path(
|
||||||
abs_path: &Path,
|
abs_path: &Path,
|
||||||
project_env: Option<&HashMap<String, String>>,
|
project_env: Option<&HashMap<String, String>>,
|
||||||
) -> Option<(String, String)> {
|
) -> Option<TargetInfo> {
|
||||||
let mut command = util::command::new_std_command("cargo");
|
let mut command = util::command::new_std_command("cargo");
|
||||||
if let Some(envs) = project_env {
|
if let Some(envs) = project_env {
|
||||||
command.envs(envs);
|
command.envs(envs);
|
||||||
|
@ -656,10 +698,14 @@ fn package_name_and_bin_name_from_abs_path(
|
||||||
let metadata: CargoMetadata = serde_json::from_slice(&output).log_err()?;
|
let metadata: CargoMetadata = serde_json::from_slice(&output).log_err()?;
|
||||||
|
|
||||||
retrieve_package_id_and_bin_name_from_metadata(metadata, abs_path).and_then(
|
retrieve_package_id_and_bin_name_from_metadata(metadata, abs_path).and_then(
|
||||||
|(package_id, bin_name)| {
|
|(package_id, bin_name, target_kind)| {
|
||||||
let package_name = package_name_from_pkgid(&package_id);
|
let package_name = package_name_from_pkgid(&package_id);
|
||||||
|
|
||||||
package_name.map(|package_name| (package_name.to_owned(), bin_name))
|
package_name.map(|package_name| TargetInfo {
|
||||||
|
package_name: package_name.to_owned(),
|
||||||
|
target_name: bin_name,
|
||||||
|
target_kind,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -667,13 +713,19 @@ fn package_name_and_bin_name_from_abs_path(
|
||||||
fn retrieve_package_id_and_bin_name_from_metadata(
|
fn retrieve_package_id_and_bin_name_from_metadata(
|
||||||
metadata: CargoMetadata,
|
metadata: CargoMetadata,
|
||||||
abs_path: &Path,
|
abs_path: &Path,
|
||||||
) -> Option<(String, String)> {
|
) -> Option<(String, String, TargetKind)> {
|
||||||
for package in metadata.packages {
|
for package in metadata.packages {
|
||||||
for target in package.targets {
|
for target in package.targets {
|
||||||
let is_bin = target.kind.iter().any(|kind| kind == "bin");
|
let Some(bin_kind) = target
|
||||||
|
.kind
|
||||||
|
.iter()
|
||||||
|
.find_map(|kind| TargetKind::try_from(kind.as_ref()).ok())
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let target_path = PathBuf::from(target.src_path);
|
let target_path = PathBuf::from(target.src_path);
|
||||||
if target_path == abs_path && is_bin {
|
if target_path == abs_path {
|
||||||
return Some((package.id, target.name));
|
return Some((package.id, target.name, bin_kind));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1066,7 +1118,11 @@ mod tests {
|
||||||
(
|
(
|
||||||
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"}]}]}"#,
|
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"}]}]}"#,
|
||||||
"/path/to/zed/src/main.rs",
|
"/path/to/zed/src/main.rs",
|
||||||
Some(("path+file:///path/to/zed/crates/zed#0.131.0", "zed")),
|
Some((
|
||||||
|
"path+file:///path/to/zed/crates/zed#0.131.0",
|
||||||
|
"zed",
|
||||||
|
TargetKind::Bin,
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["bin"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#,
|
r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["bin"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#,
|
||||||
|
@ -1074,6 +1130,16 @@ mod tests {
|
||||||
Some((
|
Some((
|
||||||
"path+file:///path/to/custom-package#my-custom-package@0.1.0",
|
"path+file:///path/to/custom-package#my-custom-package@0.1.0",
|
||||||
"my-custom-bin",
|
"my-custom-bin",
|
||||||
|
TargetKind::Bin,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#,
|
||||||
|
"/path/to/custom-package/src/main.rs",
|
||||||
|
Some((
|
||||||
|
"path+file:///path/to/custom-package#my-custom-package@0.1.0",
|
||||||
|
"my-custom-bin",
|
||||||
|
TargetKind::Example,
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
@ -1088,7 +1154,7 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
retrieve_package_id_and_bin_name_from_metadata(metadata, absolute_path),
|
retrieve_package_id_and_bin_name_from_metadata(metadata, absolute_path),
|
||||||
expected.map(|(pkgid, bin)| (pkgid.to_owned(), bin.to_owned()))
|
expected.map(|(pkgid, name, kind)| (pkgid.to_owned(), name.to_owned(), kind))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue