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:
parent
6b06685723
commit
0e2e5b8b0d
13 changed files with 213 additions and 82 deletions
|
@ -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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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| {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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(())))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue