debugger: Use JS adapter's suggested names for child sessions (#32474)

Cole Miller created

Also introduces an extension point for other adapters to do this if it
turns out they also send this information.

Release Notes:

- N/A (JS locator is still gated)

Change summary

crates/dap/src/adapters.rs               |  4 ++++
crates/dap_adapters/src/javascript.rs    |  5 +++++
crates/debugger_ui/src/debugger_panel.rs | 26 +++++++++++++++++++++-----
3 files changed, 30 insertions(+), 5 deletions(-)

Detailed changes

crates/dap/src/adapters.rs 🔗

@@ -369,6 +369,10 @@ pub trait DebugAdapter: 'static + Send + Sync {
     }
 
     async fn dap_schema(&self) -> serde_json::Value;
+
+    fn label_for_child_session(&self, _args: &StartDebuggingRequestArguments) -> Option<String> {
+        None
+    }
 }
 
 #[cfg(any(test, feature = "test-support"))]

crates/dap_adapters/src/javascript.rs 🔗

@@ -431,4 +431,9 @@ impl DebugAdapter for JsDebugAdapter {
         self.get_installed_binary(delegate, &config, user_installed_path, cx)
             .await
     }
+
+    fn label_for_child_session(&self, args: &StartDebuggingRequestArguments) -> Option<String> {
+        let label = args.configuration.get("name")?.as_str()?;
+        Some(label.to_owned())
+    }
 }

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -10,13 +10,13 @@ use crate::{
 };
 use anyhow::Result;
 use command_palette_hooks::CommandPaletteFilter;
-use dap::StartDebuggingRequestArguments;
 use dap::adapters::DebugAdapterName;
 use dap::debugger_settings::DebugPanelDockPosition;
 use dap::{
     ContinuedEvent, LoadedSourceEvent, ModuleEvent, OutputEvent, StoppedEvent, ThreadEvent,
     client::SessionId, debugger_settings::DebuggerSettings,
 };
+use dap::{DapRegistry, StartDebuggingRequestArguments};
 use gpui::{
     Action, App, AsyncWindowContext, Context, DismissEvent, Entity, EntityId, EventEmitter,
     FocusHandle, Focusable, MouseButton, MouseDownEvent, Point, Subscription, Task, WeakEntity,
@@ -445,10 +445,7 @@ impl DebugPanel {
         };
 
         let dap_store_handle = self.project.read(cx).dap_store().clone();
-        let mut label = parent_session.read(cx).label().clone();
-        if !label.ends_with("(child)") {
-            label = format!("{label} (child)").into();
-        }
+        let label = self.label_for_child_session(&parent_session, request, cx);
         let adapter = parent_session.read(cx).adapter().clone();
         let mut binary = parent_session.read(cx).binary().clone();
         binary.request_args = request.clone();
@@ -1039,6 +1036,25 @@ impl DebugPanel {
             cx.emit(PanelEvent::ZoomIn);
         }
     }
+
+    fn label_for_child_session(
+        &self,
+        parent_session: &Entity<Session>,
+        request: &StartDebuggingRequestArguments,
+        cx: &mut Context<'_, Self>,
+    ) -> SharedString {
+        let adapter = parent_session.read(cx).adapter();
+        if let Some(adapter) = DapRegistry::global(cx).adapter(&adapter) {
+            if let Some(label) = adapter.label_for_child_session(request) {
+                return label.into();
+            }
+        }
+        let mut label = parent_session.read(cx).label().clone();
+        if !label.ends_with("(child)") {
+            label = format!("{label} (child)").into();
+        }
+        label
+    }
 }
 
 async fn register_session_inner(