diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index ba13b96a6..5d9916c92 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -27,8 +27,6 @@ pub struct Client { server_tx: UnboundedSender, request_counter: AtomicU64, pub caps: Option, - // - pub breakpoints: HashMap>, // thread_id -> frames pub stack_frames: HashMap>, pub thread_states: HashMap, @@ -77,7 +75,6 @@ impl Client { request_counter: AtomicU64::new(0), caps: None, // - breakpoints: HashMap::new(), stack_frames: HashMap::new(), thread_states: HashMap::new(), thread_id: None, diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index d74f91985..5fc35977d 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -320,10 +320,18 @@ impl Application { None => "Debug:".to_owned(), }; + log::info!("{}", output); self.editor.set_status(format!("{} {}", prefix, output)); } Event::Initialized => { // send existing breakpoints + for (path, breakpoints) in &self.editor.breakpoints { + // TODO: call futures in parallel, await all + debugger + .set_breakpoints(path.clone(), breakpoints.clone()) + .await + .unwrap(); + } // TODO: fetch breakpoints (in case we're attaching) if let Ok(_) = debugger.configuration_done().await { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3e740eadf..7b2078374 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1999,35 +1999,38 @@ mod cmd { bail!("Can't edit breakpoint: document has no path") } }; - if let Some(debugger) = &mut cx.editor.debugger { - if breakpoint.condition.is_some() - && !debugger - .caps - .as_ref() - .unwrap() - .supports_conditional_breakpoints - .unwrap_or_default() - { - bail!("Can't edit breakpoint: debugger does not support conditional breakpoints") - } - if breakpoint.log_message.is_some() - && !debugger - .caps - .as_ref() - .unwrap() - .supports_log_points - .unwrap_or_default() - { - bail!("Can't edit breakpoint: debugger does not support logpoints") - } - - let breakpoints = debugger.breakpoints.entry(path.clone()).or_default(); - if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) { - breakpoints.remove(pos); - breakpoints.push(breakpoint); - - let breakpoints = breakpoints.clone(); + let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default(); + if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) { + breakpoints.remove(pos); + breakpoints.push(breakpoint); + + let breakpoints = breakpoints.clone(); + + if let Some(debugger) = &mut cx.editor.debugger { + // TODO: handle capabilities correctly again, by filterin breakpoints when emitting + // if breakpoint.condition.is_some() + // && !debugger + // .caps + // .as_ref() + // .unwrap() + // .supports_conditional_breakpoints + // .unwrap_or_default() + // { + // bail!( + // "Can't edit breakpoint: debugger does not support conditional breakpoints" + // ) + // } + // if breakpoint.log_message.is_some() + // && !debugger + // .caps + // .as_ref() + // .unwrap() + // .supports_log_points + // .unwrap_or_default() + // { + // bail!("Can't edit breakpoint: debugger does not support logpoints") + // } let request = debugger.set_breakpoints(path, breakpoints); if let Err(e) = block_on(request) { bail!("Failed to set breakpoints: {:?}", e) diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index 7618fca2c..5c415ca47 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -279,12 +279,7 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) { // TODO: need to map breakpoints over edits and update them? // we shouldn't really allow editing while debug is running though - let debugger = match &mut cx.editor.debugger { - Some(debugger) => debugger, - None => return, - }; - - let breakpoints = debugger.breakpoints.entry(path.clone()).or_default(); + let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default(); if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) { breakpoints.remove(pos); } else { @@ -293,6 +288,10 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) { let breakpoints = breakpoints.clone(); + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; let request = debugger.set_breakpoints(path, breakpoints); if let Err(e) = block_on(request) { cx.editor diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 17a2df3d7..818d275f7 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -26,7 +26,7 @@ use helix_view::{ keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::borrow::Cow; +use std::{borrow::Cow, collections::HashMap, path::PathBuf}; use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind}; use tui::buffer::Buffer as Surface; @@ -76,6 +76,7 @@ impl EditorView { loader: &syntax::Loader, config: &helix_view::editor::Config, debugger: &Option, + breakpoints: &HashMap>, ) { let inner = view.inner_area(); let area = view.area; @@ -93,7 +94,15 @@ impl EditorView { Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights); Self::render_gutter( - doc, view, view.area, surface, theme, is_focused, config, debugger, + doc, + view, + view.area, + surface, + theme, + is_focused, + config, + debugger, + breakpoints, ); if is_focused { @@ -113,7 +122,7 @@ impl EditorView { } } - self.render_diagnostics(doc, view, inner, surface, theme, debugger); + self.render_diagnostics(doc, view, inner, surface, theme, breakpoints); let statusline_area = view .area @@ -417,6 +426,7 @@ impl EditorView { is_focused: bool, config: &helix_view::editor::Config, debugger: &Option, + all_breakpoints: &HashMap>, ) { let text = doc.text().slice(..); let last_line = view.last_line(doc); @@ -448,10 +458,9 @@ impl EditorView { let mut breakpoints: Option<&Vec> = None; let mut stack_frame: Option<&StackFrame> = None; - if let Some(debugger) = debugger { - if let Some(path) = doc.path() { - breakpoints = debugger.breakpoints.get(path); - + if let Some(path) = doc.path() { + breakpoints = all_breakpoints.get(path); + if let Some(debugger) = debugger { // if we have a frame, and the frame path matches document if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id) { @@ -551,7 +560,7 @@ impl EditorView { viewport: Rect, surface: &mut Surface, theme: &Theme, - debugger: &Option, + all_breakpoints: &HashMap>, ) { use helix_core::diagnostic::Severity; use tui::{ @@ -589,26 +598,23 @@ impl EditorView { lines.extend(text.lines); } - if let Some(debugger) = debugger { - if let Some(path) = doc.path() { - if let Some(breakpoints) = debugger.breakpoints.get(path) { - let line = doc.text().char_to_line(cursor); - if let Some(breakpoint) = breakpoints - .iter() - .find(|breakpoint| breakpoint.line - 1 == line) - { - if let Some(condition) = &breakpoint.condition { - lines.extend( - Text::styled(condition, info.add_modifier(Modifier::UNDERLINED)) - .lines, - ); - } - if let Some(log_message) = &breakpoint.log_message { - lines.extend( - Text::styled(log_message, info.add_modifier(Modifier::UNDERLINED)) - .lines, - ); - } + if let Some(path) = doc.path() { + if let Some(breakpoints) = all_breakpoints.get(path) { + let line = doc.text().char_to_line(cursor); + if let Some(breakpoint) = breakpoints + .iter() + .find(|breakpoint| breakpoint.line - 1 == line) + { + if let Some(condition) = &breakpoint.condition { + lines.extend( + Text::styled(condition, info.add_modifier(Modifier::UNDERLINED)).lines, + ); + } + if let Some(log_message) = &breakpoint.log_message { + lines.extend( + Text::styled(log_message, info.add_modifier(Modifier::UNDERLINED)) + .lines, + ); } } } @@ -1224,6 +1230,7 @@ impl Component for EditorView { loader, &cx.editor.config, &cx.editor.debugger, + &cx.editor.breakpoints, ); } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f87ae3180..adc40eb4f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -11,6 +11,7 @@ use futures_util::stream::select_all::SelectAll; use tokio_stream::wrappers::UnboundedReceiverStream; use std::{ + collections::HashMap, path::{Path, PathBuf}, sync::Arc, time::Duration, @@ -24,6 +25,7 @@ pub use helix_core::diagnostic::Severity; pub use helix_core::register::Registers; use helix_core::syntax::{self, DebugConfigCompletion}; use helix_core::Position; +use helix_dap as dap; use serde::Deserialize; @@ -81,8 +83,9 @@ pub struct Editor { pub theme: Theme, pub language_servers: helix_lsp::Registry, - pub debugger: Option, - pub debugger_events: SelectAll>, + pub debugger: Option, + pub debugger_events: SelectAll>, + pub breakpoints: HashMap>, pub debug_config_picker: Option>, pub debug_config_completions: Option>>, pub variables: Option>, @@ -127,6 +130,7 @@ impl Editor { language_servers, debugger: None, debugger_events: SelectAll::new(), + breakpoints: HashMap::new(), debug_config_picker: None, debug_config_completions: None, variables: None,