debugger: Unify landing state for new session modal (#30046)

Closes #ISSUE

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2025-05-07 00:27:50 +02:00 committed by GitHub
parent cec1d2584b
commit bbffe1ec2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 58 additions and 101 deletions

View file

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 474 B

Before After
Before After

View file

@ -1,11 +1,10 @@
use crate::persistence::DebuggerPaneItem; use crate::persistence::DebuggerPaneItem;
use crate::session::DebugSession;
use crate::{ use crate::{
ClearAllBreakpoints, Continue, CreateDebuggingSession, Disconnect, FocusBreakpointList, ClearAllBreakpoints, Continue, Detach, FocusBreakpointList, FocusConsole, FocusFrames,
FocusConsole, FocusFrames, FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables, FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables, Pause, Restart, StepBack,
Pause, Restart, StepBack, StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, persistence,
persistence,
}; };
use crate::{new_session_modal::NewSessionModal, session::DebugSession};
use anyhow::Result; use anyhow::Result;
use command_palette_hooks::CommandPaletteFilter; use command_palette_hooks::CommandPaletteFilter;
use dap::adapters::DebugAdapterName; use dap::adapters::DebugAdapterName;
@ -110,7 +109,7 @@ impl DebugPanel {
let filter = CommandPaletteFilter::global_mut(cx); let filter = CommandPaletteFilter::global_mut(cx);
let debugger_action_types = [ let debugger_action_types = [
TypeId::of::<Disconnect>(), TypeId::of::<Detach>(),
TypeId::of::<Stop>(), TypeId::of::<Stop>(),
TypeId::of::<ToggleIgnoreBreakpoints>(), TypeId::of::<ToggleIgnoreBreakpoints>(),
]; ];
@ -609,52 +608,19 @@ impl DebugPanel {
let focus_handle = self.focus_handle.clone(); let focus_handle = self.focus_handle.clone();
let is_side = self.position(window, cx).axis() == gpui::Axis::Horizontal; let is_side = self.position(window, cx).axis() == gpui::Axis::Horizontal;
let div = if is_side { v_flex() } else { h_flex() }; let div = if is_side { v_flex() } else { h_flex() };
let weak_panel = cx.weak_entity();
let new_session_button = || { let new_session_button = || {
IconButton::new("debug-new-session", IconName::Plus) IconButton::new("debug-new-session", IconName::Plus)
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.on_click({ .on_click({
let workspace = self.workspace.clone(); move |_, window, cx| window.dispatch_action(crate::Start.boxed_clone(), cx)
let weak_panel = weak_panel.clone();
let past_debug_definition = self.past_debug_definition.clone();
move |_, window, cx| {
let weak_panel = weak_panel.clone();
let past_debug_definition = past_debug_definition.clone();
let workspace = workspace.clone();
window
.spawn(cx, async move |cx| {
let task_contexts = workspace
.update_in(cx, |workspace, window, cx| {
tasks_ui::task_contexts(workspace, window, cx)
})?
.await;
workspace.update_in(cx, |this, window, cx| {
this.toggle_modal(window, cx, |window, cx| {
NewSessionModal::new(
past_debug_definition,
weak_panel,
workspace.clone(),
None,
task_contexts,
window,
cx,
)
});
})?;
Result::<_, anyhow::Error>::Ok(())
})
.detach();
}
}) })
.tooltip({ .tooltip({
let focus_handle = focus_handle.clone(); let focus_handle = focus_handle.clone();
move |window, cx| { move |window, cx| {
Tooltip::for_action_in( Tooltip::for_action_in(
"New Debug Session", "Start Debug Session",
&CreateDebuggingSession, &crate::Start,
&focus_handle, &focus_handle,
window, window,
cx, cx,
@ -920,6 +886,28 @@ impl DebugPanel {
} }
}), }),
) )
.child(
IconButton::new("debug-disconnect", IconName::DebugDetach)
.icon_size(IconSize::XSmall)
.on_click(window.listener_for(
&running_session,
|this, _, _, cx| {
this.detach_client(cx);
},
))
.tooltip({
let focus_handle = focus_handle.clone();
move |window, cx| {
Tooltip::for_action_in(
"Detach",
&Detach,
&focus_handle,
window,
cx,
)
}
}),
)
}, },
), ),
) )
@ -1270,10 +1258,7 @@ impl Render for DebugPanel {
Button::new("spawn-new-session-empty-state", "New Session") Button::new("spawn-new-session-empty-state", "New Session")
.size(ButtonSize::Large) .size(ButtonSize::Large)
.on_click(|_, window, cx| { .on_click(|_, window, cx| {
window.dispatch_action( window.dispatch_action(crate::Start.boxed_clone(), cx);
CreateDebuggingSession.boxed_clone(),
cx,
);
}), }),
), ),
), ),

View file

@ -24,7 +24,7 @@ actions!(
[ [
Start, Start,
Continue, Continue,
Disconnect, Detach,
Pause, Pause,
Restart, Restart,
StepInto, StepInto,
@ -34,7 +34,6 @@ actions!(
Stop, Stop,
ToggleIgnoreBreakpoints, ToggleIgnoreBreakpoints,
ClearAllBreakpoints, ClearAllBreakpoints,
CreateDebuggingSession,
FocusConsole, FocusConsole,
FocusVariables, FocusVariables,
FocusBreakpointList, FocusBreakpointList,
@ -147,38 +146,6 @@ pub fn init(cx: &mut App) {
}) })
}, },
) )
.register_action(
|workspace: &mut Workspace, _: &CreateDebuggingSession, window, cx| {
if let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) {
let weak_panel = debug_panel.downgrade();
let weak_workspace = cx.weak_entity();
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,
None,
task_contexts,
window,
cx,
)
});
})?;
Result::<_, anyhow::Error>::Ok(())
})
.detach();
}
},
)
.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) { if let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) {
let weak_panel = debug_panel.downgrade(); let weak_panel = debug_panel.downgrade();

View file

@ -629,9 +629,7 @@ impl Render for NewSessionModal {
), ),
) )
.justify_between() .justify_between()
.when(!matches!(self.mode, NewSessionMode::Scenario(_)), |this| { .children(self.adapter_drop_down_menu(window, cx))
this.children(self.adapter_drop_down_menu(window, cx))
})
.border_color(cx.theme().colors().border_variant) .border_color(cx.theme().colors().border_variant)
.border_b_1(), .border_b_1(),
) )
@ -644,7 +642,15 @@ impl Render for NewSessionModal {
.border_color(cx.theme().colors().border_variant) .border_color(cx.theme().colors().border_variant)
.border_t_1() .border_t_1()
.w_full() .w_full()
.child(self.debug_config_drop_down_menu(window, cx)) .child(
matches!(self.mode, NewSessionMode::Scenario(_))
.not()
.then(|| {
self.debug_config_drop_down_menu(window, cx)
.into_any_element()
})
.unwrap_or_else(|| v_flex().w_full().into_any_element()),
)
.child( .child(
h_flex() h_flex()
.justify_end() .justify_end()

View file

@ -103,14 +103,14 @@ impl DebugSession {
pub(crate) fn label_element(&self, cx: &App) -> AnyElement { pub(crate) fn label_element(&self, cx: &App) -> AnyElement {
let label = self.label(cx); let label = self.label(cx);
let icon = { let is_terminated = self
if self
.running_state .running_state
.read(cx) .read(cx)
.session() .session()
.read(cx) .read(cx)
.is_terminated() .is_terminated();
{ let icon = {
if is_terminated {
Some(Indicator::dot().color(Color::Error)) Some(Indicator::dot().color(Color::Error))
} else { } else {
match self match self
@ -131,7 +131,7 @@ impl DebugSession {
.gap_2() .gap_2()
.when_some(icon, |this, indicator| this.child(indicator)) .when_some(icon, |this, indicator| this.child(indicator))
.justify_between() .justify_between()
.child(Label::new(label)) .child(Label::new(label).when(is_terminated, |this| this.strikethrough()))
.into_any_element() .into_any_element()
} }
} }

View file

@ -44,9 +44,10 @@ use task::{
use terminal_view::TerminalView; use terminal_view::TerminalView;
use ui::{ use ui::{
ActiveTheme, AnyElement, App, ButtonCommon as _, Clickable as _, Context, ContextMenu, ActiveTheme, AnyElement, App, ButtonCommon as _, Clickable as _, Context, ContextMenu,
DropdownMenu, FluentBuilder, IconButton, IconName, IconSize, InteractiveElement, IntoElement, Disableable, DropdownMenu, FluentBuilder, IconButton, IconName, IconSize, InteractiveElement,
Label, LabelCommon as _, ParentElement, Render, SharedString, StatefulInteractiveElement, IntoElement, Label, LabelCommon as _, ParentElement, Render, SharedString,
Styled, Tab, Tooltip, VisibleOnHover, VisualContext, Window, div, h_flex, v_flex, StatefulInteractiveElement, Styled, Tab, Tooltip, VisibleOnHover, VisualContext, Window, div,
h_flex, v_flex,
}; };
use util::ResultExt; use util::ResultExt;
use variable_list::VariableList; use variable_list::VariableList;
@ -1420,11 +1421,7 @@ impl RunningState {
}); });
} }
#[expect( pub fn detach_client(&self, cx: &mut Context<Self>) {
unused,
reason = "Support for disconnecting a client is not wired through yet"
)]
pub fn disconnect_client(&self, cx: &mut Context<Self>) {
self.session().update(cx, |state, cx| { self.session().update(cx, |state, cx| {
state.disconnect_client(cx); state.disconnect_client(cx);
}); });
@ -1442,6 +1439,7 @@ impl RunningState {
cx: &mut Context<'_, RunningState>, cx: &mut Context<'_, RunningState>,
) -> DropdownMenu { ) -> DropdownMenu {
let state = cx.entity(); let state = cx.entity();
let session_terminated = self.session.read(cx).is_terminated();
let threads = self.session.update(cx, |this, cx| this.threads(cx)); let threads = self.session.update(cx, |this, cx| this.threads(cx));
let selected_thread_name = threads let selected_thread_name = threads
.iter() .iter()
@ -1464,6 +1462,7 @@ impl RunningState {
this this
}), }),
) )
.disabled(session_terminated)
} }
fn default_pane_layout( fn default_pane_layout(

View file

@ -81,7 +81,7 @@ pub enum IconName {
DebugContinue, DebugContinue,
DebugDisabledBreakpoint, DebugDisabledBreakpoint,
DebugDisabledLogBreakpoint, DebugDisabledLogBreakpoint,
DebugDisconnect, DebugDetach,
DebugIgnoreBreakpoints, DebugIgnoreBreakpoints,
DebugLogBreakpoint, DebugLogBreakpoint,
DebugPause, DebugPause,