dap: Allow setting breakpoints before starting the adapter

This commit is contained in:
Blaž Hrastnik 2021-09-03 13:02:09 +09:00
parent 289303a30d
commit b997d2cdeb
6 changed files with 83 additions and 65 deletions

View file

@ -27,8 +27,6 @@ pub struct Client {
server_tx: UnboundedSender<Request>,
request_counter: AtomicU64,
pub caps: Option<DebuggerCapabilities>,
//
pub breakpoints: HashMap<PathBuf, Vec<SourceBreakpoint>>,
// thread_id -> frames
pub stack_frames: HashMap<usize, Vec<StackFrame>>,
pub thread_states: HashMap<usize, String>,
@ -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,

View file

@ -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 {

View file

@ -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 = 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();
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)

View file

@ -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

View file

@ -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<helix_dap::Client>,
breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
) {
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<helix_dap::Client>,
all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
) {
let text = doc.text().slice(..);
let last_line = view.last_line(doc);
@ -448,10 +458,9 @@ impl EditorView {
let mut breakpoints: Option<&Vec<SourceBreakpoint>> = 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<helix_dap::Client>,
all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
) {
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,
);
}

View file

@ -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<helix_dap::Client>,
pub debugger_events: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>,
pub debugger: Option<dap::Client>,
pub debugger_events: SelectAll<UnboundedReceiverStream<dap::Payload>>,
pub breakpoints: HashMap<PathBuf, Vec<dap::SourceBreakpoint>>,
pub debug_config_picker: Option<Vec<String>>,
pub debug_config_completions: Option<Vec<Vec<DebugConfigCompletion>>>,
pub variables: Option<Vec<String>>,
@ -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,