Reuse values from last debug panel inert state if they exist (#27211)

Anthony Eid created

This should allow the team to iterate faster when using the debug panel
to set up a session

Release Notes:

- N/A

Change summary

crates/debugger_ui/src/debugger_panel.rs | 64 +++++++++++++++++++------
crates/debugger_ui/src/session.rs        | 18 ++++++
crates/debugger_ui/src/session/inert.rs  | 46 +++++++++++++++++-
3 files changed, 106 insertions(+), 22 deletions(-)

Detailed changes

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -3,8 +3,8 @@ use anyhow::{anyhow, Result};
 use collections::HashMap;
 use command_palette_hooks::CommandPaletteFilter;
 use dap::{
-    client::SessionId, debugger_settings::DebuggerSettings, ContinuedEvent, LoadedSourceEvent,
-    ModuleEvent, OutputEvent, StoppedEvent, ThreadEvent,
+    client::SessionId, debugger_settings::DebuggerSettings, ContinuedEvent, DebugAdapterConfig,
+    LoadedSourceEvent, ModuleEvent, OutputEvent, StoppedEvent, ThreadEvent,
 };
 use futures::{channel::mpsc, SinkExt as _};
 use gpui::{
@@ -21,6 +21,7 @@ use settings::Settings;
 use std::{any::TypeId, path::PathBuf};
 use terminal_view::terminal_panel::TerminalPanel;
 use ui::prelude::*;
+use util::ResultExt;
 use workspace::{
     dock::{DockPosition, Panel, PanelEvent},
     pane, Continue, Disconnect, Pane, Pause, Restart, StepBack, StepInto, StepOut, StepOver, Stop,
@@ -51,6 +52,7 @@ pub struct DebugPanel {
     project: WeakEntity<Project>,
     workspace: WeakEntity<Workspace>,
     _subscriptions: Vec<Subscription>,
+    pub(crate) last_inert_config: Option<DebugAdapterConfig>,
 }
 
 impl DebugPanel {
@@ -63,6 +65,7 @@ impl DebugPanel {
             let project = workspace.project().clone();
             let dap_store = project.read(cx).dap_store();
             let weak_workspace = workspace.weak_handle();
+            let debug_panel = cx.weak_entity();
             let pane = cx.new(|cx| {
                 let mut pane = Pane::new(
                     workspace.weak_handle(),
@@ -81,6 +84,7 @@ impl DebugPanel {
                 pane.set_render_tab_bar_buttons(cx, {
                     let project = project.clone();
                     let weak_workspace = weak_workspace.clone();
+                    let debug_panel = debug_panel.clone();
                     move |_, _, cx| {
                         let project = project.clone();
                         let weak_workspace = weak_workspace.clone();
@@ -91,21 +95,34 @@ impl DebugPanel {
                                     .child(
                                         IconButton::new("new-debug-session", IconName::Plus)
                                             .icon_size(IconSize::Small)
-                                            .on_click(cx.listener(move |pane, _, window, cx| {
-                                                pane.add_item(
-                                                    Box::new(DebugSession::inert(
-                                                        project.clone(),
-                                                        weak_workspace.clone(),
+                                            .on_click({
+                                                let debug_panel = debug_panel.clone();
+
+                                                cx.listener(move |pane, _, window, cx| {
+                                                    let config = debug_panel
+                                                        .read_with(cx, |this: &DebugPanel, _| {
+                                                            this.last_inert_config.clone()
+                                                        })
+                                                        .log_err()
+                                                        .flatten();
+
+                                                    pane.add_item(
+                                                        Box::new(DebugSession::inert(
+                                                            project.clone(),
+                                                            weak_workspace.clone(),
+                                                            debug_panel.clone(),
+                                                            config,
+                                                            window,
+                                                            cx,
+                                                        )),
+                                                        false,
+                                                        false,
+                                                        None,
                                                         window,
                                                         cx,
-                                                    )),
-                                                    false,
-                                                    false,
-                                                    None,
-                                                    window,
-                                                    cx,
-                                                );
-                                            })),
+                                                    );
+                                                })
+                                            }),
                                     )
                                     .into_any_element(),
                             ),
@@ -116,6 +133,8 @@ impl DebugPanel {
                     Box::new(DebugSession::inert(
                         project.clone(),
                         weak_workspace.clone(),
+                        debug_panel.clone(),
+                        None,
                         window,
                         cx,
                     )),
@@ -138,6 +157,7 @@ impl DebugPanel {
                 pane,
                 size: px(300.),
                 _subscriptions,
+                last_inert_config: None,
                 project: project.downgrade(),
                 workspace: workspace.weak_handle(),
             };
@@ -280,8 +300,14 @@ impl DebugPanel {
                     // We already have an item for this session.
                     return;
                 }
-                let session_item =
-                    DebugSession::running(project, self.workspace.clone(), session, window, cx);
+                let session_item = DebugSession::running(
+                    project,
+                    self.workspace.clone(),
+                    session,
+                    cx.weak_entity(),
+                    window,
+                    cx,
+                );
 
                 self.pane.update(cx, |pane, cx| {
                     pane.add_item(Box::new(session_item), true, true, None, window, cx);
@@ -504,12 +530,16 @@ impl Panel for DebugPanel {
             let Some(project) = self.project.clone().upgrade() else {
                 return;
             };
+            let config = self.last_inert_config.clone();
+            let panel = cx.weak_entity();
             // todo: We need to revisit it when we start adding stopped items to pane (as that'll cause us to add two items).
             self.pane.update(cx, |this, cx| {
                 this.add_item(
                     Box::new(DebugSession::inert(
                         project,
                         self.workspace.clone(),
+                        panel,
+                        config,
                         window,
                         cx,
                     )),

crates/debugger_ui/src/session.rs 🔗

@@ -6,6 +6,7 @@ mod starting;
 use std::time::Duration;
 
 use dap::client::SessionId;
+use dap::DebugAdapterConfig;
 use failed::FailedState;
 use gpui::{
     percentage, Animation, AnimationExt, AnyElement, App, Entity, EventEmitter, FocusHandle,
@@ -19,11 +20,14 @@ use rpc::proto::{self, PeerId};
 use running::RunningState;
 use starting::{StartingEvent, StartingState};
 use ui::prelude::*;
+use util::ResultExt;
 use workspace::{
     item::{self, Item},
     FollowableItem, ViewId, Workspace,
 };
 
+use crate::debugger_panel::DebugPanel;
+
 pub(crate) enum DebugSessionState {
     Inert(Entity<InertState>),
     Starting(Entity<StartingState>),
@@ -44,6 +48,7 @@ pub struct DebugSession {
     remote_id: Option<workspace::ViewId>,
     mode: DebugSessionState,
     dap_store: WeakEntity<DapStore>,
+    debug_panel: WeakEntity<DebugPanel>,
     worktree_store: WeakEntity<WorktreeStore>,
     workspace: WeakEntity<Workspace>,
     _subscriptions: [Subscription; 1],
@@ -67,6 +72,8 @@ impl DebugSession {
     pub(super) fn inert(
         project: Entity<Project>,
         workspace: WeakEntity<Workspace>,
+        debug_panel: WeakEntity<DebugPanel>,
+        config: Option<DebugAdapterConfig>,
         window: &mut Window,
         cx: &mut App,
     ) -> Entity<Self> {
@@ -77,7 +84,8 @@ impl DebugSession {
             .and_then(|tree| tree.read(cx).abs_path().to_str().map(|str| str.to_string()))
             .unwrap_or_default();
 
-        let inert = cx.new(|cx| InertState::new(workspace.clone(), &default_cwd, window, cx));
+        let inert =
+            cx.new(|cx| InertState::new(workspace.clone(), &default_cwd, config, window, cx));
 
         let project = project.read(cx);
         let dap_store = project.dap_store().downgrade();
@@ -89,6 +97,7 @@ impl DebugSession {
                 mode: DebugSessionState::Inert(inert),
                 dap_store,
                 worktree_store,
+                debug_panel,
                 workspace,
                 _subscriptions,
             }
@@ -99,6 +108,7 @@ impl DebugSession {
         project: Entity<Project>,
         workspace: WeakEntity<Workspace>,
         session: Entity<Session>,
+        debug_panel: WeakEntity<DebugPanel>,
         window: &mut Window,
         cx: &mut App,
     ) -> Entity<Self> {
@@ -111,6 +121,7 @@ impl DebugSession {
             remote_id: None,
             mode: DebugSessionState::Running(mode),
             dap_store: project.read(cx).dap_store().downgrade(),
+            debug_panel,
             worktree_store: project.read(cx).worktree_store().downgrade(),
             workspace,
         })
@@ -148,6 +159,11 @@ impl DebugSession {
         let dap_store = self.dap_store.clone();
         let InertEvent::Spawned { config } = event;
         let config = config.clone();
+
+        self.debug_panel
+            .update(cx, |this, _| this.last_inert_config = Some(config.clone()))
+            .log_err();
+
         let worktree = self
             .worktree_store
             .update(cx, |this, _| this.worktrees().next())

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

@@ -32,6 +32,15 @@ impl SpawnMode {
     }
 }
 
+impl From<DebugRequestType> for SpawnMode {
+    fn from(request: DebugRequestType) -> Self {
+        match request {
+            DebugRequestType::Launch => SpawnMode::Launch,
+            DebugRequestType::Attach(_) => SpawnMode::Attach,
+        }
+    }
+}
+
 pub(crate) struct InertState {
     focus_handle: FocusHandle,
     selected_debugger: Option<SharedString>,
@@ -46,27 +55,56 @@ impl InertState {
     pub(super) fn new(
         workspace: WeakEntity<Workspace>,
         default_cwd: &str,
+        debug_config: Option<DebugAdapterConfig>,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> Self {
+        let selected_debugger = debug_config.as_ref().and_then(|config| match config.kind {
+            DebugAdapterKind::Lldb => Some("LLDB".into()),
+            DebugAdapterKind::Go(_) => Some("Delve".into()),
+            DebugAdapterKind::Php(_) => Some("PHP".into()),
+            DebugAdapterKind::Javascript(_) => Some("JavaScript".into()),
+            DebugAdapterKind::Python(_) => Some("Debugpy".into()),
+            _ => None,
+        });
+
+        let spawn_mode = debug_config
+            .as_ref()
+            .map(|config| config.request.clone().into())
+            .unwrap_or_default();
+
+        let program = debug_config
+            .as_ref()
+            .and_then(|config| config.program.to_owned());
+
         let program_editor = cx.new(|cx| {
             let mut editor = Editor::single_line(window, cx);
-            editor.set_placeholder_text("Program path", cx);
+            if let Some(program) = program {
+                editor.insert(&program, window, cx);
+            } else {
+                editor.set_placeholder_text("Program path", cx);
+            }
             editor
         });
+
+        let cwd = debug_config
+            .and_then(|config| config.cwd.map(|cwd| cwd.to_owned()))
+            .unwrap_or_else(|| PathBuf::from(default_cwd));
+
         let cwd_editor = cx.new(|cx| {
             let mut editor = Editor::single_line(window, cx);
-            editor.insert(default_cwd, window, cx);
+            editor.insert(cwd.to_str().unwrap_or_else(|| default_cwd), window, cx);
             editor.set_placeholder_text("Working directory", cx);
             editor
         });
+
         Self {
             workspace,
             cwd_editor,
             program_editor,
-            selected_debugger: None,
+            selected_debugger,
+            spawn_mode,
             focus_handle: cx.focus_handle(),
-            spawn_mode: SpawnMode::default(),
             popover_handle: Default::default(),
         }
     }