debugger: Update New Session Modal (#30018)
This PR simplifies the new session modal by flattening its three modes and updating the UI to be less noisy. The new UI also defaults to the Debug Scenario Picker, and allows users to save debug scenarios created in the UI to the active worktree's .zed/debug.json file. Release Notes: - N/A
This commit is contained in:
parent
e9a756b5fc
commit
dc01aef0cf
12 changed files with 460 additions and 527 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4199,6 +4199,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"menu",
|
"menu",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
"paths",
|
||||||
"picker",
|
"picker",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"project",
|
"project",
|
||||||
|
|
|
@ -43,6 +43,7 @@ language.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
menu.workspace = true
|
menu.workspace = true
|
||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
|
paths.workspace = true
|
||||||
picker.workspace = true
|
picker.workspace = true
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
|
|
|
@ -32,12 +32,12 @@ pub(crate) struct AttachModalDelegate {
|
||||||
|
|
||||||
impl AttachModalDelegate {
|
impl AttachModalDelegate {
|
||||||
fn new(
|
fn new(
|
||||||
workspace: Entity<Workspace>,
|
workspace: WeakEntity<Workspace>,
|
||||||
definition: DebugTaskDefinition,
|
definition: DebugTaskDefinition,
|
||||||
candidates: Arc<[Candidate]>,
|
candidates: Arc<[Candidate]>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
workspace: workspace.downgrade(),
|
workspace,
|
||||||
definition,
|
definition,
|
||||||
candidates,
|
candidates,
|
||||||
selected_index: 0,
|
selected_index: 0,
|
||||||
|
@ -55,7 +55,7 @@ pub struct AttachModal {
|
||||||
impl AttachModal {
|
impl AttachModal {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
definition: DebugTaskDefinition,
|
definition: DebugTaskDefinition,
|
||||||
workspace: Entity<Workspace>,
|
workspace: WeakEntity<Workspace>,
|
||||||
modal: bool,
|
modal: bool,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
|
@ -82,7 +82,7 @@ impl AttachModal {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn with_processes(
|
pub(super) fn with_processes(
|
||||||
workspace: Entity<Workspace>,
|
workspace: WeakEntity<Workspace>,
|
||||||
definition: DebugTaskDefinition,
|
definition: DebugTaskDefinition,
|
||||||
processes: Arc<[Candidate]>,
|
processes: Arc<[Candidate]>,
|
||||||
modal: bool,
|
modal: bool,
|
||||||
|
|
|
@ -5,15 +5,15 @@ use crate::{
|
||||||
FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables, Pause, Restart, StepBack,
|
FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables, Pause, Restart, StepBack,
|
||||||
StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, persistence,
|
StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, persistence,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::{Result, anyhow};
|
||||||
use command_palette_hooks::CommandPaletteFilter;
|
use command_palette_hooks::CommandPaletteFilter;
|
||||||
|
use dap::StartDebuggingRequestArguments;
|
||||||
use dap::adapters::DebugAdapterName;
|
use dap::adapters::DebugAdapterName;
|
||||||
use dap::debugger_settings::DebugPanelDockPosition;
|
use dap::debugger_settings::DebugPanelDockPosition;
|
||||||
use dap::{
|
use dap::{
|
||||||
ContinuedEvent, LoadedSourceEvent, ModuleEvent, OutputEvent, StoppedEvent, ThreadEvent,
|
ContinuedEvent, LoadedSourceEvent, ModuleEvent, OutputEvent, StoppedEvent, ThreadEvent,
|
||||||
client::SessionId, debugger_settings::DebuggerSettings,
|
client::SessionId, debugger_settings::DebuggerSettings,
|
||||||
};
|
};
|
||||||
use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Action, App, AsyncWindowContext, Context, DismissEvent, Entity, EntityId, EventEmitter,
|
Action, App, AsyncWindowContext, Context, DismissEvent, Entity, EntityId, EventEmitter,
|
||||||
FocusHandle, Focusable, MouseButton, MouseDownEvent, Point, Subscription, Task, WeakEntity,
|
FocusHandle, Focusable, MouseButton, MouseDownEvent, Point, Subscription, Task, WeakEntity,
|
||||||
|
@ -54,12 +54,11 @@ pub enum DebugPanelEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
actions!(debug_panel, [ToggleFocus]);
|
actions!(debug_panel, [ToggleFocus]);
|
||||||
|
|
||||||
pub struct DebugPanel {
|
pub struct DebugPanel {
|
||||||
size: Pixels,
|
size: Pixels,
|
||||||
sessions: Vec<Entity<DebugSession>>,
|
sessions: Vec<Entity<DebugSession>>,
|
||||||
active_session: Option<Entity<DebugSession>>,
|
active_session: Option<Entity<DebugSession>>,
|
||||||
/// This represents the last debug definition that was created in the new session modal
|
|
||||||
pub(crate) past_debug_definition: Option<DebugTaskDefinition>,
|
|
||||||
project: Entity<Project>,
|
project: Entity<Project>,
|
||||||
workspace: WeakEntity<Workspace>,
|
workspace: WeakEntity<Workspace>,
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
|
@ -80,7 +79,6 @@ impl DebugPanel {
|
||||||
size: px(300.),
|
size: px(300.),
|
||||||
sessions: vec![],
|
sessions: vec![],
|
||||||
active_session: None,
|
active_session: None,
|
||||||
past_debug_definition: None,
|
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
project,
|
project,
|
||||||
workspace: workspace.weak_handle(),
|
workspace: workspace.weak_handle(),
|
||||||
|
@ -992,6 +990,69 @@ impl DebugPanel {
|
||||||
self.active_session = Some(session_item);
|
self.active_session = Some(session_item);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn save_scenario(
|
||||||
|
&self,
|
||||||
|
scenario: &DebugScenario,
|
||||||
|
worktree_id: WorktreeId,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> Task<Result<()>> {
|
||||||
|
self.workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
let Some(mut path) = workspace.absolute_path_of_worktree(worktree_id, cx) else {
|
||||||
|
return Task::ready(Err(anyhow!("Couldn't get worktree path")));
|
||||||
|
};
|
||||||
|
|
||||||
|
let serialized_scenario = serde_json::to_value(scenario);
|
||||||
|
|
||||||
|
path.push(paths::local_debug_file_relative_path());
|
||||||
|
|
||||||
|
cx.spawn_in(window, async move |workspace, cx| {
|
||||||
|
let serialized_scenario = serialized_scenario?;
|
||||||
|
let path = path.as_path();
|
||||||
|
let fs =
|
||||||
|
workspace.update(cx, |workspace, _| workspace.app_state().fs.clone())?;
|
||||||
|
|
||||||
|
if !fs.is_file(path).await {
|
||||||
|
let content =
|
||||||
|
serde_json::to_string_pretty(&serde_json::Value::Array(vec![
|
||||||
|
serialized_scenario,
|
||||||
|
]))?;
|
||||||
|
|
||||||
|
fs.create_file(path, Default::default()).await?;
|
||||||
|
fs.save(path, &content.into(), Default::default()).await?;
|
||||||
|
} else {
|
||||||
|
let content = fs.load(path).await?;
|
||||||
|
let mut values = serde_json::from_str::<Vec<serde_json::Value>>(&content)?;
|
||||||
|
values.push(serialized_scenario);
|
||||||
|
fs.save(
|
||||||
|
path,
|
||||||
|
&serde_json::to_string_pretty(&values).map(Into::into)?,
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace.update_in(cx, |workspace, window, cx| {
|
||||||
|
if let Some(project_path) = workspace
|
||||||
|
.project()
|
||||||
|
.read(cx)
|
||||||
|
.project_path_for_absolute_path(&path, cx)
|
||||||
|
{
|
||||||
|
workspace.open_path(project_path, None, true, window, cx)
|
||||||
|
} else {
|
||||||
|
Task::ready(Err(anyhow!(
|
||||||
|
"Couldn't get project path for .zed/debug.json in active worktree"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
})?.await?;
|
||||||
|
|
||||||
|
anyhow::Ok(())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|err| Task::ready(Err(err)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<PanelEvent> for DebugPanel {}
|
impl EventEmitter<PanelEvent> for DebugPanel {}
|
||||||
|
|
|
@ -147,36 +147,7 @@ pub fn init(cx: &mut App) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.register_action(|workspace: &mut Workspace, _: &Start, window, cx| {
|
.register_action(|workspace: &mut Workspace, _: &Start, window, cx| {
|
||||||
if let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) {
|
NewSessionModal::show(workspace, window, cx);
|
||||||
let weak_panel = debug_panel.downgrade();
|
|
||||||
let weak_workspace = cx.weak_entity();
|
|
||||||
let task_store = workspace.project().read(cx).task_store().clone();
|
|
||||||
|
|
||||||
cx.spawn_in(window, async move |this, cx| {
|
|
||||||
let task_contexts = this
|
|
||||||
.update_in(cx, |workspace, window, cx| {
|
|
||||||
tasks_ui::task_contexts(workspace, window, cx)
|
|
||||||
})?
|
|
||||||
.await;
|
|
||||||
|
|
||||||
this.update_in(cx, |workspace, window, cx| {
|
|
||||||
workspace.toggle_modal(window, cx, |window, cx| {
|
|
||||||
NewSessionModal::new(
|
|
||||||
debug_panel.read(cx).past_debug_definition.clone(),
|
|
||||||
weak_panel,
|
|
||||||
weak_workspace,
|
|
||||||
Some(task_store),
|
|
||||||
task_contexts,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
})?;
|
|
||||||
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
|
||||||
.detach()
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -864,7 +864,7 @@ impl RunningState {
|
||||||
|
|
||||||
dap::DebugRequest::Launch(new_launch_request)
|
dap::DebugRequest::Launch(new_launch_request)
|
||||||
}
|
}
|
||||||
request @ dap::DebugRequest::Attach(_) => request,
|
request @ dap::DebugRequest::Attach(_) => request, // todo(debugger): We should check that process_id is valid and if not show the modal
|
||||||
};
|
};
|
||||||
Ok(DebugTaskDefinition {
|
Ok(DebugTaskDefinition {
|
||||||
label,
|
label,
|
||||||
|
|
|
@ -103,7 +103,7 @@ async fn test_show_attach_modal_and_select_process(
|
||||||
});
|
});
|
||||||
let attach_modal = workspace
|
let attach_modal = workspace
|
||||||
.update(cx, |workspace, window, cx| {
|
.update(cx, |workspace, window, cx| {
|
||||||
let workspace_handle = cx.entity();
|
let workspace_handle = cx.weak_entity();
|
||||||
workspace.toggle_modal(window, cx, |window, cx| {
|
workspace.toggle_modal(window, cx, |window, cx| {
|
||||||
AttachModal::with_processes(
|
AttachModal::with_processes(
|
||||||
workspace_handle,
|
workspace_handle,
|
||||||
|
|
|
@ -141,7 +141,7 @@ impl JsonLspAdapter {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fileMatch": [
|
"fileMatch": [
|
||||||
schema_file_match(paths::debug_tasks_file()),
|
schema_file_match(paths::debug_scenarios_file()),
|
||||||
paths::local_debug_file_relative_path()
|
paths::local_debug_file_relative_path()
|
||||||
],
|
],
|
||||||
"schema": debug_schema,
|
"schema": debug_schema,
|
||||||
|
|
|
@ -216,9 +216,9 @@ pub fn tasks_file() -> &'static PathBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the `debug.json` file.
|
/// Returns the path to the `debug.json` file.
|
||||||
pub fn debug_tasks_file() -> &'static PathBuf {
|
pub fn debug_scenarios_file() -> &'static PathBuf {
|
||||||
static DEBUG_TASKS_FILE: OnceLock<PathBuf> = OnceLock::new();
|
static DEBUG_SCENARIOS_FILE: OnceLock<PathBuf> = OnceLock::new();
|
||||||
DEBUG_TASKS_FILE.get_or_init(|| config_dir().join("debug.json"))
|
DEBUG_SCENARIOS_FILE.get_or_init(|| config_dir().join("debug.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the extensions directory.
|
/// Returns the path to the extensions directory.
|
||||||
|
|
|
@ -193,22 +193,22 @@ pub struct DebugScenario {
|
||||||
/// Name of the debug task
|
/// Name of the debug task
|
||||||
pub label: SharedString,
|
pub label: SharedString,
|
||||||
/// A task to run prior to spawning the debuggee.
|
/// A task to run prior to spawning the debuggee.
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub build: Option<BuildTaskDefinition>,
|
pub build: Option<BuildTaskDefinition>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub request: Option<DebugRequest>,
|
pub request: Option<DebugRequest>,
|
||||||
/// Additional initialization arguments to be sent on DAP initialization
|
/// Additional initialization arguments to be sent on DAP initialization
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub initialize_args: Option<serde_json::Value>,
|
pub initialize_args: Option<serde_json::Value>,
|
||||||
/// Optional TCP connection information
|
/// Optional TCP connection information
|
||||||
///
|
///
|
||||||
/// If provided, this will be used to connect to the debug adapter instead of
|
/// If provided, this will be used to connect to the debug adapter instead of
|
||||||
/// spawning a new process. This is useful for connecting to a debug adapter
|
/// spawning a new process. This is useful for connecting to a debug adapter
|
||||||
/// that is already running or is started by another process.
|
/// that is already running or is started by another process.
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub tcp_connection: Option<TcpArgumentsTemplate>,
|
pub tcp_connection: Option<TcpArgumentsTemplate>,
|
||||||
/// Whether to tell the debug adapter to stop on entry
|
/// Whether to tell the debug adapter to stop on entry
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub stop_on_entry: Option<bool>,
|
pub stop_on_entry: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -701,7 +701,7 @@ fn register_actions(
|
||||||
})
|
})
|
||||||
.register_action(move |_: &mut Workspace, _: &OpenDebugTasks, window, cx| {
|
.register_action(move |_: &mut Workspace, _: &OpenDebugTasks, window, cx| {
|
||||||
open_settings_file(
|
open_settings_file(
|
||||||
paths::debug_tasks_file(),
|
paths::debug_scenarios_file(),
|
||||||
|| settings::initial_debug_tasks_content().as_ref().into(),
|
|| settings::initial_debug_tasks_content().as_ref().into(),
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue