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

Piotr Osiewicz created

Closes #ISSUE

Release Notes:

- N/A

Change summary

assets/icons/debug_detach.svg               |  0 
crates/debugger_ui/src/debugger_panel.rs    | 77 +++++++++-------------
crates/debugger_ui/src/debugger_ui.rs       | 35 ----------
crates/debugger_ui/src/new_session_modal.rs | 14 ++-
crates/debugger_ui/src/session.rs           | 16 ++--
crates/debugger_ui/src/session/running.rs   | 15 ++--
crates/icons/src/icons.rs                   |  2 
7 files changed, 58 insertions(+), 101 deletions(-)

Detailed changes

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -1,11 +1,10 @@
 use crate::persistence::DebuggerPaneItem;
+use crate::session::DebugSession;
 use crate::{
-    ClearAllBreakpoints, Continue, CreateDebuggingSession, Disconnect, FocusBreakpointList,
-    FocusConsole, FocusFrames, FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables,
-    Pause, Restart, StepBack, StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints,
-    persistence,
+    ClearAllBreakpoints, Continue, Detach, FocusBreakpointList, FocusConsole, FocusFrames,
+    FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables, Pause, Restart, StepBack,
+    StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, persistence,
 };
-use crate::{new_session_modal::NewSessionModal, session::DebugSession};
 use anyhow::Result;
 use command_palette_hooks::CommandPaletteFilter;
 use dap::adapters::DebugAdapterName;
@@ -110,7 +109,7 @@ impl DebugPanel {
 
         let filter = CommandPaletteFilter::global_mut(cx);
         let debugger_action_types = [
-            TypeId::of::<Disconnect>(),
+            TypeId::of::<Detach>(),
             TypeId::of::<Stop>(),
             TypeId::of::<ToggleIgnoreBreakpoints>(),
         ];
@@ -609,52 +608,19 @@ impl DebugPanel {
         let focus_handle = self.focus_handle.clone();
         let is_side = self.position(window, cx).axis() == gpui::Axis::Horizontal;
         let div = if is_side { v_flex() } else { h_flex() };
-        let weak_panel = cx.weak_entity();
 
         let new_session_button = || {
             IconButton::new("debug-new-session", IconName::Plus)
                 .icon_size(IconSize::Small)
                 .on_click({
-                    let workspace = self.workspace.clone();
-                    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();
-                    }
+                    move |_, window, cx| window.dispatch_action(crate::Start.boxed_clone(), cx)
                 })
                 .tooltip({
                     let focus_handle = focus_handle.clone();
                     move |window, cx| {
                         Tooltip::for_action_in(
-                            "New Debug Session",
-                            &CreateDebuggingSession,
+                            "Start Debug Session",
+                            &crate::Start,
                             &focus_handle,
                             window,
                             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")
                                         .size(ButtonSize::Large)
                                         .on_click(|_, window, cx| {
-                                            window.dispatch_action(
-                                                CreateDebuggingSession.boxed_clone(),
-                                                cx,
-                                            );
+                                            window.dispatch_action(crate::Start.boxed_clone(), cx);
                                         }),
                                 ),
                             ),

crates/debugger_ui/src/debugger_ui.rs 🔗

@@ -24,7 +24,7 @@ actions!(
     [
         Start,
         Continue,
-        Disconnect,
+        Detach,
         Pause,
         Restart,
         StepInto,
@@ -34,7 +34,6 @@ actions!(
         Stop,
         ToggleIgnoreBreakpoints,
         ClearAllBreakpoints,
-        CreateDebuggingSession,
         FocusConsole,
         FocusVariables,
         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| {
                     if let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) {
                         let weak_panel = debug_panel.downgrade();

crates/debugger_ui/src/new_session_modal.rs 🔗

@@ -629,9 +629,7 @@ impl Render for NewSessionModal {
                             ),
                     )
                     .justify_between()
-                    .when(!matches!(self.mode, NewSessionMode::Scenario(_)), |this| {
-                        this.children(self.adapter_drop_down_menu(window, cx))
-                    })
+                    .children(self.adapter_drop_down_menu(window, cx))
                     .border_color(cx.theme().colors().border_variant)
                     .border_b_1(),
             )
@@ -644,7 +642,15 @@ impl Render for NewSessionModal {
                     .border_color(cx.theme().colors().border_variant)
                     .border_t_1()
                     .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(
                         h_flex()
                             .justify_end()

crates/debugger_ui/src/session.rs 🔗

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

crates/debugger_ui/src/session/running.rs 🔗

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

crates/icons/src/icons.rs 🔗

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