Set up Rust debugger code runner tasks (#27571)

## Summary 
This PR starts the process of adding debug task locators to Zed's
debugger system. A task locator is a secondary resolution phase that
allows a debug task to run a command before starting a debug session and
then uses the output of the run command to configure itself.

Locators are most applicable when debugging a compiled language but will
be helpful for any language as well.

## Architecture

At a high level, this works by adding a debug task queue to `Workspace`.
Which add's a debug configuration associated with a `TaskId` whenever a
resolved task with a debug config is added to `TaskInventory`'s queue.
Then, when the `SpawnInTerminal` task finishes running, it emits its
task_id and the result of the ran task.

When a ran task exits successfully, `Workspace` tells `Project` to start
a debug session using its stored debug config, then `DapStore` queries
the `LocatorStore` to configure the debug configuration if it has a
valid locator argument.

Release Notes:

- N/A
This commit is contained in:
Anthony Eid 2025-03-29 02:10:40 -04:00 committed by GitHub
parent 141a6c3915
commit 8add90d7cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 441 additions and 168 deletions

View file

@ -17,7 +17,7 @@ use std::{
path::{Path, PathBuf},
sync::{Arc, LazyLock},
};
use task::{TaskTemplate, TaskTemplates, TaskVariables, VariableName};
use task::{TaskTemplate, TaskTemplates, TaskType, TaskVariables, VariableName};
use util::{fs::remove_matching, maybe, ResultExt};
use crate::language_settings::language_settings;
@ -574,11 +574,16 @@ impl ContextProvider for RustContextProvider {
.variables
.get(CUSTOM_TARGET_DIR)
.cloned();
let run_task_args = if let Some(package_to_run) = package_to_run {
let run_task_args = if let Some(package_to_run) = package_to_run.clone() {
vec!["run".into(), "-p".into(), package_to_run]
} else {
vec!["run".into()]
};
let debug_task_args = if let Some(package_to_run) = package_to_run {
vec!["build".into(), "-p".into(), package_to_run]
} else {
vec!["build".into()]
};
let mut task_templates = vec![
TaskTemplate {
label: format!(
@ -620,6 +625,31 @@ impl ContextProvider for RustContextProvider {
cwd: Some("$ZED_DIRNAME".to_owned()),
..TaskTemplate::default()
},
TaskTemplate {
label: format!(
"Debug Test '{}' (package: {})",
RUST_TEST_NAME_TASK_VARIABLE.template_value(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
),
task_type: TaskType::Debug(task::DebugArgs {
adapter: "LLDB".to_owned(),
request: task::DebugArgsRequest::Launch,
locator: Some("cargo".into()),
tcp_connection: None,
initialize_args: None,
}),
command: "cargo".into(),
args: vec![
"test".into(),
"-p".into(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
RUST_TEST_NAME_TASK_VARIABLE.template_value(),
"--no-run".into(),
],
tags: vec!["rust-test".to_owned()],
cwd: Some("$ZED_DIRNAME".to_owned()),
..TaskTemplate::default()
},
TaskTemplate {
label: format!(
"Doc test '{}' (package: {})",
@ -697,6 +727,21 @@ impl ContextProvider for RustContextProvider {
cwd: Some("$ZED_DIRNAME".to_owned()),
..TaskTemplate::default()
},
TaskTemplate {
label: "Debug".into(),
cwd: Some("$ZED_DIRNAME".to_owned()),
command: "cargo".into(),
task_type: TaskType::Debug(task::DebugArgs {
request: task::DebugArgsRequest::Launch,
adapter: "LLDB".to_owned(),
initialize_args: None,
locator: Some("cargo".into()),
tcp_connection: None,
}),
args: debug_task_args,
tags: vec!["rust-main".to_owned()],
..TaskTemplate::default()
},
TaskTemplate {
label: "Clean".into(),
command: "cargo".into(),