debugger: Allow users to include PickProcessId in debug tasks and resolve Pid (#42913)

Closes #33286

This PR adds support for Zed's `$ZED_PICK_PID` command in debug
configurations, which allows users to select a process to attach to at
debug time. When this variable is present in a debug configuration, Zed
automatically opens a process picker modal.

Follow up for this will be integrating this variable in the task system
instead of just the debug configuration system.

Release Notes:

- Added `$ZED_PICK_PID` variable for debug configurations, allowing
users to select which process to attach the debugger to at runtime

---------

Co-authored-by: Remco Smits <djsmits12@gmail.com>
This commit is contained in:
Anthony Eid
2025-11-20 10:12:59 -05:00
committed by GitHub
co-authored by Remco Smits
parent e033829ef2
commit 56401fc99c
6 changed files with 413 additions and 90 deletions
+24 -1
View File
@@ -173,6 +173,9 @@ pub enum VariableName {
SelectedText,
/// The symbol selected by the symbol tagging system, specifically the @run capture in a runnables.scm
RunnableSymbol,
/// Open a Picker to select a process ID to use in place
/// Can only be used to debug configurations
PickProcessId,
/// Custom variable, provided by the plugin or other external source.
/// Will be printed with `CUSTOM_` prefix to avoid potential conflicts with other variables.
Custom(Cow<'static, str>),
@@ -240,6 +243,7 @@ impl std::fmt::Display for VariableName {
Self::Column => write!(f, "{ZED_VARIABLE_NAME_PREFIX}COLUMN"),
Self::SelectedText => write!(f, "{ZED_VARIABLE_NAME_PREFIX}SELECTED_TEXT"),
Self::RunnableSymbol => write!(f, "{ZED_VARIABLE_NAME_PREFIX}RUNNABLE_SYMBOL"),
Self::PickProcessId => write!(f, "{ZED_VARIABLE_NAME_PREFIX}PICK_PID"),
Self::Custom(s) => write!(
f,
"{ZED_VARIABLE_NAME_PREFIX}{ZED_CUSTOM_VARIABLE_NAME_PREFIX}{s}"
@@ -346,15 +350,28 @@ pub fn shell_to_proto(shell: Shell) -> proto::Shell {
}
type VsCodeEnvVariable = String;
type VsCodeCommand = String;
type ZedEnvVariable = String;
struct EnvVariableReplacer {
variables: HashMap<VsCodeEnvVariable, ZedEnvVariable>,
commands: HashMap<VsCodeCommand, ZedEnvVariable>,
}
impl EnvVariableReplacer {
fn new(variables: HashMap<VsCodeEnvVariable, ZedEnvVariable>) -> Self {
Self { variables }
Self {
variables,
commands: HashMap::default(),
}
}
fn with_commands(
mut self,
commands: impl IntoIterator<Item = (VsCodeCommand, ZedEnvVariable)>,
) -> Self {
self.commands = commands.into_iter().collect();
self
}
fn replace_value(&self, input: serde_json::Value) -> serde_json::Value {
@@ -380,7 +397,13 @@ impl EnvVariableReplacer {
if left == "env" && !right.is_empty() {
let variable_name = &right[1..];
return Some(format!("${{{variable_name}}}"));
} else if left == "command" && !right.is_empty() {
let command_name = &right[1..];
if let Some(replacement_command) = self.commands.get(command_name) {
return Some(format!("${{{replacement_command}}}"));
}
}
let (variable_name, default) = (left, right);
let append_previous_default = |ret: &mut String| {
if !default.is_empty() {
+41 -2
View File
@@ -68,7 +68,11 @@ impl TryFrom<VsCodeDebugTaskFile> for DebugTaskFile {
VariableName::RelativeFile.to_string(),
),
("file".to_owned(), VariableName::File.to_string()),
]));
]))
.with_commands([(
"pickMyProcess".to_owned(),
VariableName::PickProcessId.to_string(),
)]);
let templates = file
.configurations
.into_iter()
@@ -96,7 +100,7 @@ fn task_type_to_adapter_name(task_type: &str) -> String {
mod tests {
use serde_json::json;
use crate::{DebugScenario, DebugTaskFile};
use crate::{DebugScenario, DebugTaskFile, VariableName};
use super::VsCodeDebugTaskFile;
@@ -152,4 +156,39 @@ mod tests {
}])
);
}
#[test]
fn test_command_pickmyprocess_replacement() {
let raw = r#"
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Process",
"request": "attach",
"type": "cppdbg",
"processId": "${command:pickMyProcess}"
}
]
}
"#;
let parsed: VsCodeDebugTaskFile =
serde_json_lenient::from_str(raw).expect("deserializing launch.json");
let zed = DebugTaskFile::try_from(parsed).expect("converting to Zed debug templates");
let expected_placeholder = format!("${{{}}}", VariableName::PickProcessId);
pretty_assertions::assert_eq!(
zed,
DebugTaskFile(vec![DebugScenario {
label: "Attach to Process".into(),
adapter: "CodeLLDB".into(),
config: json!({
"request": "attach",
"processId": expected_placeholder,
}),
tcp_connection: None,
build: None
}])
);
}
}