diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index 2ae824225..8dd418685 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -399,4 +399,17 @@ impl Client { self.request::(args).await } + + pub async fn set_exception_breakpoints( + &mut self, + filters: Vec, + ) -> Result>> { + let args = requests::SetExceptionBreakpointsArguments { filters }; + + let response = self + .request::(args) + .await; + + Ok(response.ok().map(|r| r.breakpoints).unwrap_or_default()) + } } diff --git a/helix-dap/src/types.rs b/helix-dap/src/types.rs index 3af299228..5430771f3 100644 --- a/helix-dap/src/types.rs +++ b/helix-dap/src/types.rs @@ -515,6 +515,29 @@ pub mod requests { type Result = EvaluateResponse; const COMMAND: &'static str = "evaluate"; } + + #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct SetExceptionBreakpointsArguments { + pub filters: Vec, + // pub filterOptions: Option>, // needs capability + // pub exceptionOptions: Option>, // needs capability + } + + #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct SetExceptionBreakpointsResponse { + pub breakpoints: Option>, + } + + #[derive(Debug)] + pub enum SetExceptionBreakpoints {} + + impl Request for SetExceptionBreakpoints { + type Arguments = SetExceptionBreakpointsArguments; + type Result = SetExceptionBreakpointsResponse; + const COMMAND: &'static str = "setExceptionBreakpoints"; + } } // Events diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index acaba6d63..f3f62d6b2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -335,6 +335,8 @@ impl Command { dap_edit_log, "Edit log message of the breakpoint on the current line", dap_switch_thread, "Switch current thread", dap_switch_stack_frame, "Switch stack frame", + dap_enable_exceptions, "Enable exception breakpoints", + dap_disable_exceptions, "Disable exception breakpoints", shell_pipe, "Pipe selections through shell command", shell_pipe_to, "Pipe selections into shell command, ignoring command output", shell_insert_output, "Insert output of shell command before each selection", diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index 3fb990c2f..65a0d33fd 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -513,6 +513,39 @@ pub fn dap_terminate(cx: &mut Context) { cx.editor.debugger = None; } +pub fn dap_enable_exceptions(cx: &mut Context) { + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; + + let filters = match &debugger.capabilities().exception_breakpoint_filters { + Some(filters) => filters.clone(), + None => return, + }; + + if let Err(e) = block_on( + debugger.set_exception_breakpoints(filters.iter().map(|f| f.filter.clone()).collect()), + ) { + cx.editor + .set_error(format!("Failed to set up exception breakpoints: {:?}", e)); + return; + } +} + +pub fn dap_disable_exceptions(cx: &mut Context) { + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; + + if let Err(e) = block_on(debugger.set_exception_breakpoints(vec![])) { + cx.editor + .set_error(format!("Failed to set up exception breakpoints: {:?}", e)); + return; + } +} + pub fn dap_edit_condition(cx: &mut Context) { if let Some((pos, mut bp)) = commands::cmd::get_breakpoint_at_current_line(cx.editor) { let callback = Box::pin(async move { diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 77bb187ce..e344457cb 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -557,6 +557,8 @@ impl Default for Keymaps { "f" => dap_switch_stack_frame, // sl, sb }, + "e" => dap_enable_exceptions, + "E" => dap_disable_exceptions, }, "w" => { "Window" "C-w" | "w" => rotate_view,