debugger: Debug sessions rerun build tasks by default when restarting (#33724)

Anthony Eid and Cole Miller created

We reworked the debug modal spawning to use the task context from past
debug sessions when spawning a debug scenario based on task inventory
history.

We changed restart session keybinding to rerun session too.

Closes #31369

Release Notes:

- Restarting a debug session now reruns build tasks that are associated
with the session

---------

Co-authored-by: Cole Miller <cole@zed.dev>

Change summary

assets/keymaps/default-linux.json                 |  4 
assets/keymaps/default-macos.json                 |  4 
crates/debugger_ui/src/debugger_panel.rs          | 76 ++++++++++------
crates/debugger_ui/src/debugger_ui.rs             | 30 ++++--
crates/debugger_ui/src/new_process_modal.rs       | 60 +++++++++---
crates/debugger_ui/src/session/running.rs         | 36 +++++++
crates/debugger_ui/src/tests.rs                   |  1 
crates/debugger_ui/src/tests/new_process_modal.rs |  9 +
crates/editor/src/editor.rs                       |  9 +
crates/project/src/project.rs                     |  3 
crates/project/src/task_inventory.rs              | 50 ++++++++--
crates/workspace/src/tasks.rs                     | 12 ++
crates/workspace/src/workspace.rs                 |  1 
13 files changed, 213 insertions(+), 82 deletions(-)

Detailed changes

assets/keymaps/default-linux.json 🔗

@@ -34,7 +34,7 @@
       "ctrl-q": "zed::Quit",
       "f4": "debugger::Start",
       "shift-f5": "debugger::Stop",
-      "ctrl-shift-f5": "debugger::Restart",
+      "ctrl-shift-f5": "debugger::RerunSession",
       "f6": "debugger::Pause",
       "f7": "debugger::StepOver",
       "ctrl-f11": "debugger::StepInto",
@@ -598,7 +598,7 @@
       // "foo-bar": ["task::Spawn", { "task_name": "MyTask", "reveal_target": "dock" }]
       // or by tag:
       // "foo-bar": ["task::Spawn", { "task_tag": "MyTag" }],
-      "f5": "debugger::RerunLastSession"
+      "f5": "debugger::Rerun"
     }
   },
   {

assets/keymaps/default-macos.json 🔗

@@ -5,7 +5,7 @@
     "bindings": {
       "f4": "debugger::Start",
       "shift-f5": "debugger::Stop",
-      "shift-cmd-f5": "debugger::Restart",
+      "shift-cmd-f5": "debugger::RerunSession",
       "f6": "debugger::Pause",
       "f7": "debugger::StepOver",
       "f11": "debugger::StepInto",
@@ -652,7 +652,7 @@
       "cmd-k shift-up": "workspace::SwapPaneUp",
       "cmd-k shift-down": "workspace::SwapPaneDown",
       "cmd-shift-x": "zed::Extensions",
-      "f5": "debugger::RerunLastSession"
+      "f5": "debugger::Rerun"
     }
   },
   {

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -5,7 +5,7 @@ use crate::session::running::breakpoint_list::BreakpointList;
 use crate::{
     ClearAllBreakpoints, Continue, CopyDebugAdapterArguments, Detach, FocusBreakpointList,
     FocusConsole, FocusFrames, FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables,
-    NewProcessModal, NewProcessMode, Pause, Restart, StepInto, StepOut, StepOver, Stop,
+    NewProcessModal, NewProcessMode, Pause, RerunSession, StepInto, StepOut, StepOver, Stop,
     ToggleExpandItem, ToggleSessionPicker, ToggleThreadPicker, persistence, spawn_task_or_modal,
 };
 use anyhow::{Context as _, Result, anyhow};
@@ -25,7 +25,7 @@ use gpui::{
 use itertools::Itertools as _;
 use language::Buffer;
 use project::debugger::session::{Session, SessionStateEvent};
-use project::{Fs, ProjectPath, WorktreeId};
+use project::{DebugScenarioContext, Fs, ProjectPath, WorktreeId};
 use project::{Project, debugger::session::ThreadStatus};
 use rpc::proto::{self};
 use settings::Settings;
@@ -197,6 +197,7 @@ impl DebugPanel {
                 .and_then(|buffer| buffer.read(cx).file())
                 .map(|f| f.worktree_id(cx))
         });
+
         let Some(worktree) = worktree
             .and_then(|id| self.project.read(cx).worktree_for_id(id, cx))
             .or_else(|| self.project.read(cx).visible_worktrees(cx).next())
@@ -204,6 +205,7 @@ impl DebugPanel {
             log::debug!("Could not find a worktree to spawn the debug session in");
             return;
         };
+
         self.debug_scenario_scheduled_last = true;
         if let Some(inventory) = self
             .project
@@ -214,7 +216,15 @@ impl DebugPanel {
             .cloned()
         {
             inventory.update(cx, |inventory, _| {
-                inventory.scenario_scheduled(scenario.clone());
+                inventory.scenario_scheduled(
+                    scenario.clone(),
+                    // todo(debugger): Task context is cloned three times
+                    // once in Session,inventory, and in resolve scenario
+                    // we should wrap it in an RC instead to save some memory
+                    task_context.clone(),
+                    worktree_id,
+                    active_buffer.as_ref().map(|buffer| buffer.downgrade()),
+                );
             })
         }
         let task = cx.spawn_in(window, {
@@ -225,6 +235,16 @@ impl DebugPanel {
                 let definition = debug_session
                     .update_in(cx, |debug_session, window, cx| {
                         debug_session.running_state().update(cx, |running, cx| {
+                            if scenario.build.is_some() {
+                                running.scenario = Some(scenario.clone());
+                                running.scenario_context = Some(DebugScenarioContext {
+                                    active_buffer: active_buffer
+                                        .as_ref()
+                                        .map(|entity| entity.downgrade()),
+                                    task_context: task_context.clone(),
+                                    worktree_id: worktree_id,
+                                });
+                            };
                             running.resolve_scenario(
                                 scenario,
                                 task_context,
@@ -273,7 +293,8 @@ impl DebugPanel {
             return;
         };
         let workspace = self.workspace.clone();
-        let Some(scenario) = task_inventory.read(cx).last_scheduled_scenario().cloned() else {
+        let Some((scenario, context)) = task_inventory.read(cx).last_scheduled_scenario().cloned()
+        else {
             window.defer(cx, move |window, cx| {
                 workspace
                     .update(cx, |workspace, cx| {
@@ -284,28 +305,22 @@ impl DebugPanel {
             return;
         };
 
-        cx.spawn_in(window, async move |this, cx| {
-            let task_contexts = workspace
-                .update_in(cx, |workspace, window, cx| {
-                    tasks_ui::task_contexts(workspace, window, cx)
-                })?
-                .await;
+        let DebugScenarioContext {
+            task_context,
+            worktree_id,
+            active_buffer,
+        } = context;
 
-            let task_context = task_contexts.active_context().cloned().unwrap_or_default();
-            let worktree_id = task_contexts.worktree();
+        let active_buffer = active_buffer.and_then(|buffer| buffer.upgrade());
 
-            this.update_in(cx, |this, window, cx| {
-                this.start_session(
-                    scenario.clone(),
-                    task_context,
-                    None,
-                    worktree_id,
-                    window,
-                    cx,
-                );
-            })
-        })
-        .detach();
+        self.start_session(
+            scenario,
+            task_context,
+            active_buffer,
+            worktree_id,
+            window,
+            cx,
+        );
     }
 
     pub(crate) async fn register_session(
@@ -758,16 +773,16 @@ impl DebugPanel {
                                             .icon_size(IconSize::XSmall)
                                             .on_click(window.listener_for(
                                                 &running_state,
-                                                |this, _, _window, cx| {
-                                                    this.restart_session(cx);
+                                                |this, _, window, cx| {
+                                                    this.rerun_session(window, cx);
                                                 },
                                             ))
                                             .tooltip({
                                                 let focus_handle = focus_handle.clone();
                                                 move |window, cx| {
                                                     Tooltip::for_action_in(
-                                                        "Restart",
-                                                        &Restart,
+                                                        "Rerun Session",
+                                                        &RerunSession,
                                                         &focus_handle,
                                                         window,
                                                         cx,
@@ -1600,12 +1615,13 @@ impl workspace::DebuggerProvider for DebuggerProvider {
         definition: DebugScenario,
         context: TaskContext,
         buffer: Option<Entity<Buffer>>,
+        worktree_id: Option<WorktreeId>,
         window: &mut Window,
         cx: &mut App,
     ) {
         self.0.update(cx, |_, cx| {
-            cx.defer_in(window, |this, window, cx| {
-                this.start_session(definition, context, buffer, None, window, cx);
+            cx.defer_in(window, move |this, window, cx| {
+                this.start_session(definition, context, buffer, worktree_id, window, cx);
             })
         })
     }

crates/debugger_ui/src/debugger_ui.rs 🔗

@@ -37,6 +37,7 @@ actions!(
         Detach,
         Pause,
         Restart,
+        RerunSession,
         StepInto,
         StepOver,
         StepOut,
@@ -54,7 +55,8 @@ actions!(
         ShowStackTrace,
         ToggleThreadPicker,
         ToggleSessionPicker,
-        RerunLastSession,
+        #[action(deprecated_aliases = ["debugger::RerunLastSession"])]
+        Rerun,
         ToggleExpandItem,
     ]
 );
@@ -74,17 +76,15 @@ pub fn init(cx: &mut App) {
             .register_action(|workspace: &mut Workspace, _: &Start, window, cx| {
                 NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx);
             })
-            .register_action(
-                |workspace: &mut Workspace, _: &RerunLastSession, window, cx| {
-                    let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
-                        return;
-                    };
+            .register_action(|workspace: &mut Workspace, _: &Rerun, window, cx| {
+                let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
+                    return;
+                };
 
-                    debug_panel.update(cx, |debug_panel, cx| {
-                        debug_panel.rerun_last_session(workspace, window, cx);
-                    })
-                },
-            )
+                debug_panel.update(cx, |debug_panel, cx| {
+                    debug_panel.rerun_last_session(workspace, window, cx);
+                })
+            })
             .register_action(
                 |workspace: &mut Workspace, _: &ShutdownDebugAdapters, _window, cx| {
                     workspace.project().update(cx, |project, cx| {
@@ -210,6 +210,14 @@ pub fn init(cx: &mut App) {
                             .ok();
                     }
                 })
+                .on_action({
+                    let active_item = active_item.clone();
+                    move |_: &RerunSession, window, cx| {
+                        active_item
+                            .update(cx, |item, cx| item.rerun_session(window, cx))
+                            .ok();
+                    }
+                })
                 .on_action({
                     let active_item = active_item.clone();
                     move |_: &Stop, _, cx| {

crates/debugger_ui/src/new_process_modal.rs 🔗

@@ -23,7 +23,9 @@ use gpui::{
 };
 use itertools::Itertools as _;
 use picker::{Picker, PickerDelegate, highlighted_match_with_paths::HighlightedMatch};
-use project::{ProjectPath, TaskContexts, TaskSourceKind, task_store::TaskStore};
+use project::{
+    DebugScenarioContext, ProjectPath, TaskContexts, TaskSourceKind, task_store::TaskStore,
+};
 use settings::{Settings, initial_local_debug_tasks_content};
 use task::{DebugScenario, RevealTarget, ZedDebugConfig};
 use theme::ThemeSettings;
@@ -92,6 +94,7 @@ impl NewProcessModal {
 
         cx.spawn_in(window, async move |workspace, cx| {
             let task_contexts = workspace.update_in(cx, |workspace, window, cx| {
+                // todo(debugger): get the buffer here (if the active item is an editor) and store it so we can pass it to start_session later
                 tasks_ui::task_contexts(workspace, window, cx)
             })?;
             workspace.update_in(cx, |workspace, window, cx| {
@@ -1110,7 +1113,11 @@ pub(super) struct TaskMode {
 
 pub(super) struct DebugDelegate {
     task_store: Entity<TaskStore>,
-    candidates: Vec<(Option<TaskSourceKind>, DebugScenario)>,
+    candidates: Vec<(
+        Option<TaskSourceKind>,
+        DebugScenario,
+        Option<DebugScenarioContext>,
+    )>,
     selected_index: usize,
     matches: Vec<StringMatch>,
     prompt: String,
@@ -1208,7 +1215,11 @@ impl DebugDelegate {
 
                 this.delegate.candidates = recent
                     .into_iter()
-                    .map(|scenario| Self::get_scenario_kind(&languages, &dap_registry, scenario))
+                    .map(|(scenario, context)| {
+                        let (kind, scenario) =
+                            Self::get_scenario_kind(&languages, &dap_registry, scenario);
+                        (kind, scenario, Some(context))
+                    })
                     .chain(
                         scenarios
                             .into_iter()
@@ -1223,7 +1234,7 @@ impl DebugDelegate {
                             .map(|(kind, scenario)| {
                                 let (language, scenario) =
                                     Self::get_scenario_kind(&languages, &dap_registry, scenario);
-                                (language.or(Some(kind)), scenario)
+                                (language.or(Some(kind)), scenario, None)
                             }),
                     )
                     .collect();
@@ -1269,7 +1280,7 @@ impl PickerDelegate for DebugDelegate {
             let candidates: Vec<_> = candidates
                 .into_iter()
                 .enumerate()
-                .map(|(index, (_, candidate))| {
+                .map(|(index, (_, candidate, _))| {
                     StringMatchCandidate::new(index, candidate.label.as_ref())
                 })
                 .collect();
@@ -1434,25 +1445,40 @@ impl PickerDelegate for DebugDelegate {
             .get(self.selected_index())
             .and_then(|match_candidate| self.candidates.get(match_candidate.candidate_id).cloned());
 
-        let Some((_, debug_scenario)) = debug_scenario else {
+        let Some((_, debug_scenario, context)) = debug_scenario else {
             return;
         };
 
-        let (task_context, worktree_id) = self
-            .task_contexts
-            .as_ref()
-            .and_then(|task_contexts| {
-                Some((
-                    task_contexts.active_context().cloned()?,
-                    task_contexts.worktree(),
-                ))
-            })
-            .unwrap_or_default();
+        let context = context.unwrap_or_else(|| {
+            self.task_contexts
+                .as_ref()
+                .and_then(|task_contexts| {
+                    Some(DebugScenarioContext {
+                        task_context: task_contexts.active_context().cloned()?,
+                        active_buffer: None,
+                        worktree_id: task_contexts.worktree(),
+                    })
+                })
+                .unwrap_or_default()
+        });
+        let DebugScenarioContext {
+            task_context,
+            active_buffer,
+            worktree_id,
+        } = context;
+        let active_buffer = active_buffer.and_then(|buffer| buffer.upgrade());
 
         send_telemetry(&debug_scenario, TelemetrySpawnLocation::ScenarioList, cx);
         self.debug_panel
             .update(cx, |panel, cx| {
-                panel.start_session(debug_scenario, task_context, None, worktree_id, window, cx);
+                panel.start_session(
+                    debug_scenario,
+                    task_context,
+                    active_buffer,
+                    worktree_id,
+                    window,
+                    cx,
+                );
             })
             .ok();
 

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

@@ -33,7 +33,7 @@ use language::Buffer;
 use loaded_source_list::LoadedSourceList;
 use module_list::ModuleList;
 use project::{
-    Project, WorktreeId,
+    DebugScenarioContext, Project, WorktreeId,
     debugger::session::{Session, SessionEvent, ThreadId, ThreadStatus},
     terminals::TerminalKind,
 };
@@ -79,6 +79,8 @@ pub struct RunningState {
     pane_close_subscriptions: HashMap<EntityId, Subscription>,
     dock_axis: Axis,
     _schedule_serialize: Option<Task<()>>,
+    pub(crate) scenario: Option<DebugScenario>,
+    pub(crate) scenario_context: Option<DebugScenarioContext>,
 }
 
 impl RunningState {
@@ -831,6 +833,8 @@ impl RunningState {
             debug_terminal,
             dock_axis,
             _schedule_serialize: None,
+            scenario: None,
+            scenario_context: None,
         }
     }
 
@@ -1039,7 +1043,7 @@ impl RunningState {
                 let scenario = dap_registry
                     .adapter(&adapter)
                     .with_context(|| anyhow!("{}: is not a valid adapter name", &adapter))?.config_from_zed_format(zed_config)
-.await?;
+                    .await?;
                 config = scenario.config;
                 util::merge_non_null_json_value_into(extra_config, &mut config);
 
@@ -1525,6 +1529,34 @@ impl RunningState {
         });
     }
 
+    pub fn rerun_session(&mut self, window: &mut Window, cx: &mut Context<Self>) {
+        if let Some((scenario, context)) = self.scenario.take().zip(self.scenario_context.take())
+            && scenario.build.is_some()
+        {
+            let DebugScenarioContext {
+                task_context,
+                active_buffer,
+                worktree_id,
+            } = context;
+            let active_buffer = active_buffer.and_then(|buffer| buffer.upgrade());
+
+            self.workspace
+                .update(cx, |workspace, cx| {
+                    workspace.start_debug_session(
+                        scenario,
+                        task_context,
+                        active_buffer,
+                        worktree_id,
+                        window,
+                        cx,
+                    )
+                })
+                .ok();
+        } else {
+            self.restart_session(cx);
+        }
+    }
+
     pub fn restart_session(&self, cx: &mut Context<Self>) {
         self.session().update(cx, |state, cx| {
             state.restart(None, cx);

crates/debugger_ui/src/tests.rs 🔗

@@ -115,6 +115,7 @@ pub fn start_debug_session_with<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
             config.to_scenario(),
             TaskContext::default(),
             None,
+            None,
             window,
             cx,
         )

crates/debugger_ui/src/tests/new_process_modal.rs 🔗

@@ -141,7 +141,14 @@ async fn test_debug_session_substitutes_variables_and_relativizes_paths(
 
         workspace
             .update(cx, |workspace, window, cx| {
-                workspace.start_debug_session(scenario, task_context.clone(), None, window, cx)
+                workspace.start_debug_session(
+                    scenario,
+                    task_context.clone(),
+                    None,
+                    None,
+                    window,
+                    cx,
+                )
             })
             .unwrap();
 

crates/editor/src/editor.rs 🔗

@@ -6186,7 +6186,14 @@ impl Editor {
 
                 workspace.update(cx, |workspace, cx| {
                     dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
-                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
+                    workspace.start_debug_session(
+                        scenario,
+                        context,
+                        Some(buffer),
+                        None,
+                        window,
+                        cx,
+                    );
                 });
                 Some(Task::ready(Ok(())))
             }

crates/project/src/project.rs 🔗

@@ -131,7 +131,8 @@ pub use language::Location;
 #[cfg(any(test, feature = "test-support"))]
 pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
 pub use task_inventory::{
-    BasicContextProvider, ContextProviderWithTasks, Inventory, TaskContexts, TaskSourceKind,
+    BasicContextProvider, ContextProviderWithTasks, DebugScenarioContext, Inventory, TaskContexts,
+    TaskSourceKind,
 };
 
 pub use buffer_store::ProjectTransaction;

crates/project/src/task_inventory.rs 🔗

@@ -12,7 +12,7 @@ use anyhow::Result;
 use collections::{HashMap, HashSet, VecDeque};
 use dap::DapRegistry;
 use fs::Fs;
-use gpui::{App, AppContext as _, Context, Entity, SharedString, Task};
+use gpui::{App, AppContext as _, Context, Entity, SharedString, Task, WeakEntity};
 use itertools::Itertools;
 use language::{
     Buffer, ContextLocation, ContextProvider, File, Language, LanguageToolchainStore, Location,
@@ -31,11 +31,18 @@ use worktree::WorktreeId;
 
 use crate::{task_store::TaskSettingsLocation, worktree_store::WorktreeStore};
 
+#[derive(Clone, Debug, Default)]
+pub struct DebugScenarioContext {
+    pub task_context: TaskContext,
+    pub worktree_id: Option<WorktreeId>,
+    pub active_buffer: Option<WeakEntity<Buffer>>,
+}
+
 /// Inventory tracks available tasks for a given project.
 pub struct Inventory {
     fs: Arc<dyn Fs>,
     last_scheduled_tasks: VecDeque<(TaskSourceKind, ResolvedTask)>,
-    last_scheduled_scenarios: VecDeque<DebugScenario>,
+    last_scheduled_scenarios: VecDeque<(DebugScenario, DebugScenarioContext)>,
     templates_from_settings: InventoryFor<TaskTemplate>,
     scenarios_from_settings: InventoryFor<DebugScenario>,
 }
@@ -245,16 +252,29 @@ impl Inventory {
         })
     }
 
-    pub fn scenario_scheduled(&mut self, scenario: DebugScenario) {
+    pub fn scenario_scheduled(
+        &mut self,
+        scenario: DebugScenario,
+        task_context: TaskContext,
+        worktree_id: Option<WorktreeId>,
+        active_buffer: Option<WeakEntity<Buffer>>,
+    ) {
         self.last_scheduled_scenarios
-            .retain(|s| s.label != scenario.label);
-        self.last_scheduled_scenarios.push_back(scenario);
+            .retain(|(s, _)| s.label != scenario.label);
+        self.last_scheduled_scenarios.push_back((
+            scenario,
+            DebugScenarioContext {
+                task_context,
+                worktree_id,
+                active_buffer,
+            },
+        ));
         if self.last_scheduled_scenarios.len() > 5_000 {
             self.last_scheduled_scenarios.pop_front();
         }
     }
 
-    pub fn last_scheduled_scenario(&self) -> Option<&DebugScenario> {
+    pub fn last_scheduled_scenario(&self) -> Option<&(DebugScenario, DebugScenarioContext)> {
         self.last_scheduled_scenarios.back()
     }
 
@@ -265,7 +285,10 @@ impl Inventory {
         current_resolved_tasks: Vec<(TaskSourceKind, task::ResolvedTask)>,
         add_current_language_tasks: bool,
         cx: &mut App,
-    ) -> Task<(Vec<DebugScenario>, Vec<(TaskSourceKind, DebugScenario)>)> {
+    ) -> Task<(
+        Vec<(DebugScenario, DebugScenarioContext)>,
+        Vec<(TaskSourceKind, DebugScenario)>,
+    )> {
         let mut scenarios = Vec::new();
 
         if let Some(worktree_id) = task_contexts
@@ -765,7 +788,7 @@ impl Inventory {
                 }
             }
         }
-        self.last_scheduled_scenarios.retain_mut(|scenario| {
+        self.last_scheduled_scenarios.retain_mut(|(scenario, _)| {
             if !previously_existing_scenarios.contains(&scenario.label) {
                 return true;
             }
@@ -1304,7 +1327,7 @@ mod tests {
             .clone();
 
         inventory.update(cx, |this, _| {
-            this.scenario_scheduled(scenario.clone());
+            this.scenario_scheduled(scenario.clone(), TaskContext::default(), None, None);
         });
 
         assert_eq!(
@@ -1316,7 +1339,8 @@ mod tests {
                 .0
                 .first()
                 .unwrap()
-                .clone(),
+                .clone()
+                .0,
             scenario
         );
 
@@ -1346,6 +1370,7 @@ mod tests {
                 .0
                 .first()
                 .unwrap()
+                .0
                 .adapter,
             "Delve",
         );
@@ -1367,15 +1392,14 @@ mod tests {
             .unwrap();
         });
 
-        assert_eq!(
+        assert!(
             inventory
                 .update(cx, |this, cx| {
                     this.list_debug_scenarios(&TaskContexts::default(), vec![], vec![], false, cx)
                 })
                 .await
                 .0
-                .first(),
-            None
+                .is_empty(),
         );
     }
 

crates/workspace/src/tasks.rs 🔗

@@ -3,7 +3,7 @@ use std::process::ExitStatus;
 use anyhow::Result;
 use gpui::{AppContext, Context, Entity, Task};
 use language::Buffer;
-use project::TaskSourceKind;
+use project::{TaskSourceKind, WorktreeId};
 use remote::ConnectionState;
 use task::{DebugScenario, ResolvedTask, SpawnInTerminal, TaskContext, TaskTemplate};
 use ui::Window;
@@ -95,11 +95,19 @@ impl Workspace {
         scenario: DebugScenario,
         task_context: TaskContext,
         active_buffer: Option<Entity<Buffer>>,
+        worktree_id: Option<WorktreeId>,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
         if let Some(provider) = self.debugger_provider.as_mut() {
-            provider.start_session(scenario, task_context, active_buffer, window, cx)
+            provider.start_session(
+                scenario,
+                task_context,
+                active_buffer,
+                worktree_id,
+                window,
+                cx,
+            )
         }
     }
 

crates/workspace/src/workspace.rs 🔗

@@ -146,6 +146,7 @@ pub trait DebuggerProvider {
         definition: DebugScenario,
         task_context: TaskContext,
         active_buffer: Option<Entity<Buffer>>,
+        worktree_id: Option<WorktreeId>,
         window: &mut Window,
         cx: &mut App,
     );