debugger: Show child sessions as indented and ensure they're next to the parent session (#32939)

Piotr Osiewicz created

Closes #ISSUE

Release Notes:

- debugger: Tweaked how child sessions are shown in the session list.

Change summary

crates/debugger_ui/src/debugger_panel.rs | 14 +++++++++++---
crates/debugger_ui/src/dropdown_menus.rs | 26 +++++++++++++++++++-------
crates/debugger_ui/src/session.rs        |  3 ++-
3 files changed, 32 insertions(+), 11 deletions(-)

Detailed changes

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -1142,7 +1142,9 @@ async fn register_session_inner(
         let debug_session = DebugSession::running(
             this.project.clone(),
             this.workspace.clone(),
-            parent_session.map(|p| p.read(cx).running_state().read(cx).debug_terminal.clone()),
+            parent_session
+                .as_ref()
+                .map(|p| p.read(cx).running_state().read(cx).debug_terminal.clone()),
             session,
             serialized_layout,
             this.position(window, cx).axis(),
@@ -1157,8 +1159,14 @@ async fn register_session_inner(
             |_, _, cx| cx.notify(),
         )
         .detach();
-
-        this.sessions.push(debug_session.clone());
+        let insert_position = this
+            .sessions
+            .iter()
+            .position(|session| Some(session) == parent_session.as_ref())
+            .map(|position| position + 1)
+            .unwrap_or(this.sessions.len());
+        // Maintain topological sort order of sessions
+        this.sessions.insert(insert_position, debug_session.clone());
 
         debug_session
     })?;

crates/debugger_ui/src/dropdown_menus.rs 🔗

@@ -1,5 +1,6 @@
 use std::time::Duration;
 
+use collections::HashMap;
 use gpui::{Animation, AnimationExt as _, Entity, Transformation, percentage};
 use project::debugger::session::{ThreadId, ThreadStatus};
 use ui::{ContextMenu, DropdownMenu, DropdownStyle, Indicator, prelude::*};
@@ -72,10 +73,21 @@ impl DebugPanel {
                     trigger,
                     ContextMenu::build(window, cx, move |mut this, _, cx| {
                         let context_menu = cx.weak_entity();
+                        let mut session_depths = HashMap::default();
                         for session in sessions.into_iter() {
                             let weak_session = session.downgrade();
                             let weak_session_id = weak_session.entity_id();
-
+                            let session_id = session.read(cx).session_id(cx);
+                            let parent_depth = session
+                                .read(cx)
+                                .session(cx)
+                                .read(cx)
+                                .parent_id(cx)
+                                .and_then(|parent_id| session_depths.get(&parent_id).cloned());
+                            let self_depth =
+                                *session_depths.entry(session_id).or_insert_with(|| {
+                                    parent_depth.map(|depth| depth + 1).unwrap_or(0usize)
+                                });
                             this = this.custom_entry(
                                 {
                                     let weak = weak.clone();
@@ -84,16 +96,16 @@ impl DebugPanel {
                                         weak_session
                                             .read_with(cx, |session, cx| {
                                                 let context_menu = context_menu.clone();
-                                                let id: SharedString = format!(
-                                                    "debug-session-{}",
-                                                    session.session_id(cx).0
-                                                )
-                                                .into();
+
+                                                let id: SharedString =
+                                                    format!("debug-session-{}", session_id.0)
+                                                        .into();
+
                                                 h_flex()
                                                     .w_full()
                                                     .group(id.clone())
                                                     .justify_between()
-                                                    .child(session.label_element(cx))
+                                                    .child(session.label_element(self_depth, cx))
                                                     .child(
                                                         IconButton::new(
                                                             "close-debug-session",

crates/debugger_ui/src/session.rs 🔗

@@ -125,7 +125,7 @@ impl DebugSession {
         &self.running_state
     }
 
-    pub(crate) fn label_element(&self, cx: &App) -> AnyElement {
+    pub(crate) fn label_element(&self, depth: usize, cx: &App) -> AnyElement {
         let label = self.label(cx);
 
         let is_terminated = self
@@ -153,6 +153,7 @@ impl DebugSession {
         };
 
         h_flex()
+            .ml(depth * px(16.0))
             .gap_2()
             .when_some(icon, |this, indicator| this.child(indicator))
             .justify_between()