dap: Allow setting breakpoints before starting the adapter

pull/574/head
Blaž Hrastnik 3 years ago
parent 289303a30d
commit b997d2cdeb

@ -27,8 +27,6 @@ pub struct Client {
server_tx: UnboundedSender<Request>, server_tx: UnboundedSender<Request>,
request_counter: AtomicU64, request_counter: AtomicU64,
pub caps: Option<DebuggerCapabilities>, pub caps: Option<DebuggerCapabilities>,
//
pub breakpoints: HashMap<PathBuf, Vec<SourceBreakpoint>>,
// thread_id -> frames // thread_id -> frames
pub stack_frames: HashMap<usize, Vec<StackFrame>>, pub stack_frames: HashMap<usize, Vec<StackFrame>>,
pub thread_states: HashMap<usize, String>, pub thread_states: HashMap<usize, String>,
@ -77,7 +75,6 @@ impl Client {
request_counter: AtomicU64::new(0), request_counter: AtomicU64::new(0),
caps: None, caps: None,
// //
breakpoints: HashMap::new(),
stack_frames: HashMap::new(), stack_frames: HashMap::new(),
thread_states: HashMap::new(), thread_states: HashMap::new(),
thread_id: None, thread_id: None,

@ -320,10 +320,18 @@ impl Application {
None => "Debug:".to_owned(), None => "Debug:".to_owned(),
}; };
log::info!("{}", output);
self.editor.set_status(format!("{} {}", prefix, output)); self.editor.set_status(format!("{} {}", prefix, output));
} }
Event::Initialized => { Event::Initialized => {
// send existing breakpoints // 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) // TODO: fetch breakpoints (in case we're attaching)
if let Ok(_) = debugger.configuration_done().await { if let Ok(_) = debugger.configuration_done().await {

@ -1999,35 +1999,38 @@ mod cmd {
bail!("Can't edit breakpoint: document has no path") 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); let request = debugger.set_breakpoints(path, breakpoints);
if let Err(e) = block_on(request) { if let Err(e) = block_on(request) {
bail!("Failed to set breakpoints: {:?}", e) bail!("Failed to set breakpoints: {:?}", e)

@ -279,12 +279,7 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) {
// TODO: need to map breakpoints over edits and update them? // TODO: need to map breakpoints over edits and update them?
// we shouldn't really allow editing while debug is running though // we shouldn't really allow editing while debug is running though
let debugger = match &mut cx.editor.debugger { let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
Some(debugger) => debugger,
None => return,
};
let breakpoints = debugger.breakpoints.entry(path.clone()).or_default();
if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) { if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) {
breakpoints.remove(pos); breakpoints.remove(pos);
} else { } else {
@ -293,6 +288,10 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) {
let breakpoints = breakpoints.clone(); let breakpoints = breakpoints.clone();
let debugger = match &mut cx.editor.debugger {
Some(debugger) => debugger,
None => return,
};
let request = debugger.set_breakpoints(path, breakpoints); let request = debugger.set_breakpoints(path, breakpoints);
if let Err(e) = block_on(request) { if let Err(e) = block_on(request) {
cx.editor cx.editor

@ -26,7 +26,7 @@ use helix_view::{
keyboard::{KeyCode, KeyModifiers}, keyboard::{KeyCode, KeyModifiers},
Document, Editor, Theme, View, Document, Editor, Theme, View,
}; };
use std::borrow::Cow; use std::{borrow::Cow, collections::HashMap, path::PathBuf};
use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind}; use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind};
use tui::buffer::Buffer as Surface; use tui::buffer::Buffer as Surface;
@ -76,6 +76,7 @@ impl EditorView {
loader: &syntax::Loader, loader: &syntax::Loader,
config: &helix_view::editor::Config, config: &helix_view::editor::Config,
debugger: &Option<helix_dap::Client>, debugger: &Option<helix_dap::Client>,
breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
) { ) {
let inner = view.inner_area(); let inner = view.inner_area();
let area = view.area; let area = view.area;
@ -93,7 +94,15 @@ impl EditorView {
Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights); Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights);
Self::render_gutter( 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 { 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 let statusline_area = view
.area .area
@ -417,6 +426,7 @@ impl EditorView {
is_focused: bool, is_focused: bool,
config: &helix_view::editor::Config, config: &helix_view::editor::Config,
debugger: &Option<helix_dap::Client>, debugger: &Option<helix_dap::Client>,
all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
) { ) {
let text = doc.text().slice(..); let text = doc.text().slice(..);
let last_line = view.last_line(doc); let last_line = view.last_line(doc);
@ -448,10 +458,9 @@ impl EditorView {
let mut breakpoints: Option<&Vec<SourceBreakpoint>> = None; let mut breakpoints: Option<&Vec<SourceBreakpoint>> = None;
let mut stack_frame: Option<&StackFrame> = None; let mut stack_frame: Option<&StackFrame> = None;
if let Some(debugger) = debugger { if let Some(path) = doc.path() {
if let Some(path) = doc.path() { breakpoints = all_breakpoints.get(path);
breakpoints = debugger.breakpoints.get(path); if let Some(debugger) = debugger {
// if we have a frame, and the frame path matches document // if we have a frame, and the frame path matches document
if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id) if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id)
{ {
@ -551,7 +560,7 @@ impl EditorView {
viewport: Rect, viewport: Rect,
surface: &mut Surface, surface: &mut Surface,
theme: &Theme, theme: &Theme,
debugger: &Option<helix_dap::Client>, all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
) { ) {
use helix_core::diagnostic::Severity; use helix_core::diagnostic::Severity;
use tui::{ use tui::{
@ -589,26 +598,23 @@ impl EditorView {
lines.extend(text.lines); lines.extend(text.lines);
} }
if let Some(debugger) = debugger { if let Some(path) = doc.path() {
if let Some(path) = doc.path() { if let Some(breakpoints) = all_breakpoints.get(path) {
if let Some(breakpoints) = debugger.breakpoints.get(path) { let line = doc.text().char_to_line(cursor);
let line = doc.text().char_to_line(cursor); if let Some(breakpoint) = breakpoints
if let Some(breakpoint) = breakpoints .iter()
.iter() .find(|breakpoint| breakpoint.line - 1 == line)
.find(|breakpoint| breakpoint.line - 1 == line) {
{ if let Some(condition) = &breakpoint.condition {
if let Some(condition) = &breakpoint.condition { lines.extend(
lines.extend( Text::styled(condition, info.add_modifier(Modifier::UNDERLINED)).lines,
Text::styled(condition, info.add_modifier(Modifier::UNDERLINED)) );
.lines, }
); if let Some(log_message) = &breakpoint.log_message {
} lines.extend(
if let Some(log_message) = &breakpoint.log_message { Text::styled(log_message, info.add_modifier(Modifier::UNDERLINED))
lines.extend( .lines,
Text::styled(log_message, info.add_modifier(Modifier::UNDERLINED)) );
.lines,
);
}
} }
} }
} }
@ -1224,6 +1230,7 @@ impl Component for EditorView {
loader, loader,
&cx.editor.config, &cx.editor.config,
&cx.editor.debugger, &cx.editor.debugger,
&cx.editor.breakpoints,
); );
} }

@ -11,6 +11,7 @@ use futures_util::stream::select_all::SelectAll;
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
use std::{ use std::{
collections::HashMap,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
time::Duration, time::Duration,
@ -24,6 +25,7 @@ pub use helix_core::diagnostic::Severity;
pub use helix_core::register::Registers; pub use helix_core::register::Registers;
use helix_core::syntax::{self, DebugConfigCompletion}; use helix_core::syntax::{self, DebugConfigCompletion};
use helix_core::Position; use helix_core::Position;
use helix_dap as dap;
use serde::Deserialize; use serde::Deserialize;
@ -81,8 +83,9 @@ pub struct Editor {
pub theme: Theme, pub theme: Theme,
pub language_servers: helix_lsp::Registry, pub language_servers: helix_lsp::Registry,
pub debugger: Option<helix_dap::Client>, pub debugger: Option<dap::Client>,
pub debugger_events: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>, pub debugger_events: SelectAll<UnboundedReceiverStream<dap::Payload>>,
pub breakpoints: HashMap<PathBuf, Vec<dap::SourceBreakpoint>>,
pub debug_config_picker: Option<Vec<String>>, pub debug_config_picker: Option<Vec<String>>,
pub debug_config_completions: Option<Vec<Vec<DebugConfigCompletion>>>, pub debug_config_completions: Option<Vec<Vec<DebugConfigCompletion>>>,
pub variables: Option<Vec<String>>, pub variables: Option<Vec<String>>,
@ -127,6 +130,7 @@ impl Editor {
language_servers, language_servers,
debugger: None, debugger: None,
debugger_events: SelectAll::new(), debugger_events: SelectAll::new(),
breakpoints: HashMap::new(),
debug_config_picker: None, debug_config_picker: None,
debug_config_completions: None, debug_config_completions: None,
variables: None, variables: None,

Loading…
Cancel
Save