From 4370628e309a4c6b84dd6a3be13ea2230c4f635e Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 13 Jun 2025 19:17:51 +0200 Subject: [PATCH] debugger: Focus child sessions if parent has never stopped (#32693) Closes #ISSUE Release Notes: - When debugging JavaScript, Zed will now preselect child sessions by default. --- crates/debugger_ui/src/debugger_panel.rs | 6 +++++- .../debugger_ui/src/tests/debugger_panel.rs | 12 ++++++----- crates/project/src/debugger/session.rs | 20 +++++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index 62536204bfab0836049977a9f7de488e216f9b57..baa1042ace94764f93d594d86cdec2f9ec70825e 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -404,7 +404,11 @@ impl DebugPanel { }); (session, task) })?; - Self::register_session(this, session, false, cx).await?; + // Focus child sessions if the parent has never emitted a stopped event; + // this improves our JavaScript experience, as it always spawns a "main" session that then spawns subsessions. + let parent_ever_stopped = + parent_session.update(cx, |this, _| this.has_ever_stopped())?; + Self::register_session(this, session, !parent_ever_stopped, cx).await?; task.await }) .detach_and_log_err(cx); diff --git a/crates/debugger_ui/src/tests/debugger_panel.rs b/crates/debugger_ui/src/tests/debugger_panel.rs index 8fa11603788de704b2de2bdb22d58e87583c9f87..a8b6c7ecc2eae626fee9efc53a7153ef5b602dac 100644 --- a/crates/debugger_ui/src/tests/debugger_panel.rs +++ b/crates/debugger_ui/src/tests/debugger_panel.rs @@ -444,18 +444,20 @@ async fn test_handle_start_debugging_request( .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::(cx).unwrap(); - // Active session does not change on spawn. + // Active session changes on spawn, as the parent has never stopped. let active_session = debug_panel .read(cx) .active_session() .unwrap() .read(cx) .session(cx); - - assert_eq!(active_session, sessions[0].read(cx).session(cx)); - assert!(active_session.read(cx).parent_session().is_none()); - let current_sessions = debug_panel.read(cx).sessions(); + assert_eq!(active_session, current_sessions[1].read(cx).session(cx)); + assert_eq!( + active_session.read(cx).parent_session(), + Some(¤t_sessions[0].read(cx).session(cx)) + ); + assert_eq!(current_sessions.len(), 2); assert_eq!(current_sessions[0], sessions[0]); diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 917aae513b489ed2639ad04511ed7648a48ef84a..f9982fe5a29c66221096efcaeaabbe77ad8d8865 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -137,6 +137,7 @@ pub struct RunningMode { worktree: WeakEntity, executor: BackgroundExecutor, is_started: bool, + has_ever_stopped: bool, } fn client_source(abs_path: &Path) -> dap::Source { @@ -188,6 +189,7 @@ impl RunningMode { binary, executor: cx.background_executor().clone(), is_started: false, + has_ever_stopped: false, }) } @@ -508,6 +510,20 @@ impl Mode { ))), } } + + /// Did this debug session stop at least once? + pub(crate) fn has_ever_stopped(&self) -> bool { + match self { + Mode::Building => false, + Mode::Running(running_mode) => running_mode.has_ever_stopped, + } + } + + fn stopped(&mut self) { + if let Mode::Running(running) = self { + running.has_ever_stopped = true; + } + } } #[derive(Default)] @@ -1237,6 +1253,7 @@ impl Session { } fn handle_stopped_event(&mut self, event: StoppedEvent, cx: &mut Context) { + self.mode.stopped(); // todo(debugger): Find a clean way to get around the clone let breakpoint_store = self.breakpoint_store.clone(); if let Some((local, path)) = self.as_running_mut().and_then(|local| { @@ -1831,6 +1848,9 @@ impl Session { } } + pub fn has_ever_stopped(&self) -> bool { + self.mode.has_ever_stopped() + } pub fn step_over( &mut self, thread_id: ThreadId,