From 784f2eca88c5671847d2a34e5e8ddace1ed970de Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Thu, 19 Dec 2024 12:32:44 -0500 Subject: [PATCH] Add step back support for DAP The step back button is hidden because most dap implementations don't support it. --- assets/icons/debug_step_back.svg | 1 + crates/debugger_ui/src/debugger_panel_item.rs | 23 ++++++++++ crates/project/src/dap_store.rs | 42 ++++++++++++++++--- crates/ui/src/components/icon.rs | 1 + 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 assets/icons/debug_step_back.svg diff --git a/assets/icons/debug_step_back.svg b/assets/icons/debug_step_back.svg new file mode 100644 index 00000000000000..bc7c9b8444cda2 --- /dev/null +++ b/assets/icons/debug_step_back.svg @@ -0,0 +1 @@ + diff --git a/crates/debugger_ui/src/debugger_panel_item.rs b/crates/debugger_ui/src/debugger_panel_item.rs index 310421a54a492a..03789d152c6054 100644 --- a/crates/debugger_ui/src/debugger_panel_item.rs +++ b/crates/debugger_ui/src/debugger_panel_item.rs @@ -588,6 +588,18 @@ impl DebugPanelItem { }); } + pub fn step_back(&mut self, cx: &mut ViewContext) { + self.update_thread_state_status(ThreadStatus::Running, cx); + + let granularity = DebuggerSettings::get_global(cx).stepping_granularity; + + self.dap_store.update(cx, |store, cx| { + store + .step_back(&self.client_id, self.thread_id, granularity, cx) + .detach_and_log_err(cx); + }); + } + pub fn restart_client(&self, cx: &mut ViewContext) { self.dap_store.update(cx, |store, cx| { store @@ -807,6 +819,17 @@ impl Render for DebugPanelItem { .disabled(thread_status != ThreadStatus::Stopped) .tooltip(move |cx| Tooltip::text("Step out", cx)), ) + .when(capabilities.supports_step_back.unwrap_or(false), |this| { + this.child( + IconButton::new("debug-step-back", IconName::DebugStepBack) + .icon_size(IconSize::Small) + .on_click(cx.listener(|this, _, cx| { + this.step_back(cx); + })) + .disabled(thread_status != ThreadStatus::Stopped) + .tooltip(move |cx| Tooltip::text("Step back", cx)), + ) + }) .child( IconButton::new("debug-restart", IconName::DebugRestart) .icon_size(IconSize::Small) diff --git a/crates/project/src/dap_store.rs b/crates/project/src/dap_store.rs index e7b701101523ac..6454ebc7dd08b5 100644 --- a/crates/project/src/dap_store.rs +++ b/crates/project/src/dap_store.rs @@ -3,15 +3,15 @@ use crate::{ProjectEnvironment, ProjectItem as _, ProjectPath}; use anyhow::{anyhow, Context as _, Result}; use async_trait::async_trait; use collections::HashMap; -use dap::adapters::{DapDelegate, DapStatus, DebugAdapter, DebugAdapterBinary, DebugAdapterName}; use dap::{ + adapters::{DapDelegate, DapStatus, DebugAdapter, DebugAdapterBinary, DebugAdapterName}, client::{DebugAdapterClient, DebugAdapterClientId}, messages::{Message, Response}, requests::{ Attach, Completions, ConfigurationDone, Continue, Disconnect, Evaluate, Initialize, Launch, LoadedSources, Modules, Next, Pause, Request as _, Restart, RunInTerminal, Scopes, - SetBreakpoints, SetExpression, SetVariable, StackTrace, StartDebugging, StepIn, StepOut, - Terminate, TerminateThreads, Variables, + SetBreakpoints, SetExpression, SetVariable, StackTrace, StartDebugging, StepBack, StepIn, + StepOut, Terminate, TerminateThreads, Variables, }, AttachRequestArguments, Capabilities, CompletionItem, CompletionsArguments, ConfigurationDoneArguments, ContinueArguments, DisconnectArguments, ErrorResponse, @@ -20,8 +20,9 @@ use dap::{ ModulesArguments, NextArguments, PauseArguments, RestartArguments, RunInTerminalResponse, Scope, ScopesArguments, SetBreakpointsArguments, SetExpressionArguments, SetVariableArguments, Source, SourceBreakpoint, StackFrame, StackTraceArguments, StartDebuggingRequestArguments, - StartDebuggingRequestArgumentsRequest, StepInArguments, StepOutArguments, SteppingGranularity, - TerminateArguments, TerminateThreadsArguments, Variable, VariablesArguments, + StartDebuggingRequestArgumentsRequest, StepBackArguments, StepInArguments, StepOutArguments, + SteppingGranularity, TerminateArguments, TerminateThreadsArguments, Variable, + VariablesArguments, }; use dap_adapters::build_adapter; use fs::Fs; @@ -1077,6 +1078,37 @@ impl DapStore { }) } + pub fn step_back( + &self, + client_id: &DebugAdapterClientId, + thread_id: u64, + granularity: SteppingGranularity, + cx: &mut ModelContext, + ) -> Task> { + let Some(client) = self.client_by_id(client_id) else { + return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id))); + }; + + let capabilities = self.capabilities_by_id(client_id); + + let supports_single_thread_execution_requests = capabilities + .supports_single_thread_execution_requests + .unwrap_or_default(); + let supports_stepping_granularity = capabilities + .supports_stepping_granularity + .unwrap_or_default(); + + cx.background_executor().spawn(async move { + client + .request::(StepBackArguments { + thread_id, + granularity: supports_stepping_granularity.then(|| granularity), + single_thread: supports_single_thread_execution_requests.then(|| true), + }) + .await + }) + } + pub fn variables( &self, client_id: &DebugAdapterClientId, diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index 71bb647f5da3d8..08bee40a019973 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -168,6 +168,7 @@ pub enum IconName { DebugStepOver, DebugStepInto, DebugStepOut, + DebugStepBack, DebugRestart, Debug, DebugStop,