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

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>
This commit is contained in:
Anthony Eid 2025-07-01 15:43:58 -04:00 committed by GitHub
parent 6b06685723
commit 0e2e5b8b0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 213 additions and 82 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -33,7 +33,7 @@ use language::Buffer;
use loaded_source_list::LoadedSourceList; use loaded_source_list::LoadedSourceList;
use module_list::ModuleList; use module_list::ModuleList;
use project::{ use project::{
Project, WorktreeId, DebugScenarioContext, Project, WorktreeId,
debugger::session::{Session, SessionEvent, ThreadId, ThreadStatus}, debugger::session::{Session, SessionEvent, ThreadId, ThreadStatus},
terminals::TerminalKind, terminals::TerminalKind,
}; };
@ -79,6 +79,8 @@ pub struct RunningState {
pane_close_subscriptions: HashMap<EntityId, Subscription>, pane_close_subscriptions: HashMap<EntityId, Subscription>,
dock_axis: Axis, dock_axis: Axis,
_schedule_serialize: Option<Task<()>>, _schedule_serialize: Option<Task<()>>,
pub(crate) scenario: Option<DebugScenario>,
pub(crate) scenario_context: Option<DebugScenarioContext>,
} }
impl RunningState { impl RunningState {
@ -831,6 +833,8 @@ impl RunningState {
debug_terminal, debug_terminal,
dock_axis, dock_axis,
_schedule_serialize: None, _schedule_serialize: None,
scenario: None,
scenario_context: None,
} }
} }
@ -1039,7 +1043,7 @@ impl RunningState {
let scenario = dap_registry let scenario = dap_registry
.adapter(&adapter) .adapter(&adapter)
.with_context(|| anyhow!("{}: is not a valid adapter name", &adapter))?.config_from_zed_format(zed_config) .with_context(|| anyhow!("{}: is not a valid adapter name", &adapter))?.config_from_zed_format(zed_config)
.await?; .await?;
config = scenario.config; config = scenario.config;
util::merge_non_null_json_value_into(extra_config, &mut 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>) { pub fn restart_session(&self, cx: &mut Context<Self>) {
self.session().update(cx, |state, cx| { self.session().update(cx, |state, cx| {
state.restart(None, cx); state.restart(None, cx);

View file

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

View file

@ -141,7 +141,14 @@ async fn test_debug_session_substitutes_variables_and_relativizes_paths(
workspace workspace
.update(cx, |workspace, window, cx| { .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(); .unwrap();

View file

@ -6186,7 +6186,14 @@ impl Editor {
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, 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(()))) Some(Task::ready(Ok(())))
} }

View file

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

View file

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

View file

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

View file

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