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:
co-authored by
Remco Smits
parent
e033829ef2
commit
56401fc99c
@@ -5,16 +5,23 @@ pub(crate) mod memory_view;
|
||||
pub(crate) mod module_list;
|
||||
pub mod stack_frame_list;
|
||||
pub mod variable_list;
|
||||
use std::{any::Any, ops::ControlFlow, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
any::Any,
|
||||
ops::ControlFlow,
|
||||
path::PathBuf,
|
||||
sync::{Arc, LazyLock},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ToggleExpandItem,
|
||||
attach_modal::{AttachModal, ModalIntent},
|
||||
new_process_modal::resolve_path,
|
||||
persistence::{self, DebuggerPaneItem, SerializedLayout},
|
||||
session::running::memory_view::MemoryView,
|
||||
};
|
||||
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use anyhow::{Context as _, Result, anyhow, bail};
|
||||
use breakpoint_list::BreakpointList;
|
||||
use collections::{HashMap, IndexMap};
|
||||
use console::Console;
|
||||
@@ -56,6 +63,9 @@ use workspace::{
|
||||
Workspace, item::TabContentParams, move_item, pane::Event,
|
||||
};
|
||||
|
||||
static PROCESS_ID_PLACEHOLDER: LazyLock<String> =
|
||||
LazyLock::new(|| task::VariableName::PickProcessId.template_value());
|
||||
|
||||
pub struct RunningState {
|
||||
session: Entity<Session>,
|
||||
thread_id: Option<ThreadId>,
|
||||
@@ -653,6 +663,40 @@ impl RunningState {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_substring(config: &serde_json::Value, substring: &str) -> bool {
|
||||
match config {
|
||||
serde_json::Value::Object(obj) => obj
|
||||
.values()
|
||||
.any(|value| Self::contains_substring(value, substring)),
|
||||
serde_json::Value::Array(array) => array
|
||||
.iter()
|
||||
.any(|value| Self::contains_substring(value, substring)),
|
||||
serde_json::Value::String(s) => s.contains(substring),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn substitute_process_id_in_config(config: &mut serde_json::Value, process_id: i32) {
|
||||
match config {
|
||||
serde_json::Value::Object(obj) => {
|
||||
obj.values_mut().for_each(|value| {
|
||||
Self::substitute_process_id_in_config(value, process_id);
|
||||
});
|
||||
}
|
||||
serde_json::Value::Array(array) => {
|
||||
array.iter_mut().for_each(|value| {
|
||||
Self::substitute_process_id_in_config(value, process_id);
|
||||
});
|
||||
}
|
||||
serde_json::Value::String(s) => {
|
||||
if s.contains(PROCESS_ID_PLACEHOLDER.as_str()) {
|
||||
*s = s.replace(PROCESS_ID_PLACEHOLDER.as_str(), &process_id.to_string());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn relativize_paths(
|
||||
key: Option<&str>,
|
||||
config: &mut serde_json::Value,
|
||||
@@ -955,6 +999,31 @@ impl RunningState {
|
||||
Self::relativize_paths(None, &mut config, &task_context);
|
||||
Self::substitute_variables_in_config(&mut config, &task_context);
|
||||
|
||||
if Self::contains_substring(&config, PROCESS_ID_PLACEHOLDER.as_str()) || label.as_ref().contains(PROCESS_ID_PLACEHOLDER.as_str()) {
|
||||
let (tx, rx) = futures::channel::oneshot::channel::<Option<i32>>();
|
||||
|
||||
let weak_workspace_clone = weak_workspace.clone();
|
||||
weak_workspace.update_in(cx, |workspace, window, cx| {
|
||||
let project = workspace.project().clone();
|
||||
workspace.toggle_modal(window, cx, |window, cx| {
|
||||
AttachModal::new(
|
||||
ModalIntent::ResolveProcessId(Some(tx)),
|
||||
weak_workspace_clone,
|
||||
project,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
}).ok();
|
||||
|
||||
let Some(process_id) = rx.await.ok().flatten() else {
|
||||
bail!("No process selected with config that contains {}", PROCESS_ID_PLACEHOLDER.as_str())
|
||||
};
|
||||
|
||||
Self::substitute_process_id_in_config(&mut config, process_id);
|
||||
}
|
||||
|
||||
let request_type = match dap_registry
|
||||
.adapter(&adapter)
|
||||
.with_context(|| format!("{}: is not a valid adapter name", &adapter)) {
|
||||
|
||||
Reference in New Issue
Block a user