Get breakpoint reports from debugger

This commit is contained in:
Dmitry Sharshakov 2021-09-06 08:47:54 +03:00
parent c9cd06e904
commit 507a1f8dd6
4 changed files with 130 additions and 17 deletions

View file

@ -33,6 +33,7 @@ pub struct Client {
pub thread_id: Option<isize>, pub thread_id: Option<isize>,
/// Currently active frame for the current thread. /// Currently active frame for the current thread.
pub active_frame: Option<usize>, pub active_frame: Option<usize>,
pub breakpoints: Vec<Breakpoint>,
} }
impl Client { impl Client {
@ -80,6 +81,7 @@ impl Client {
thread_states: HashMap::new(), thread_states: HashMap::new(),
thread_id: None, thread_id: None,
active_frame: None, active_frame: None,
breakpoints: vec![],
}; };
tokio::spawn(Self::recv(server_rx, client_rx)); tokio::spawn(Self::recv(server_rx, client_rx));

View file

@ -7,7 +7,7 @@ use crate::{
args::Args, commands::fetch_stack_trace, compositor::Compositor, config::Config, job::Jobs, ui, args::Args, commands::fetch_stack_trace, compositor::Compositor, config::Config, job::Jobs, ui,
}; };
use log::error; use log::{error, warn};
use std::{ use std::{
io::{stdout, Write}, io::{stdout, Write},
sync::Arc, sync::Arc,
@ -320,6 +320,53 @@ impl Application {
Event::Thread(_) => { Event::Thread(_) => {
// TODO: update thread_states, make threads request // TODO: update thread_states, make threads request
} }
Event::Breakpoint(events::Breakpoint { reason, breakpoint }) => match &reason[..] {
"new" => {
debugger.breakpoints.push(breakpoint);
}
"changed" => {
match debugger
.breakpoints
.iter()
.position(|b| b.id == breakpoint.id)
{
Some(i) => {
let item = debugger.breakpoints.get_mut(i).unwrap();
item.verified = breakpoint.verified;
item.message = breakpoint.message.or_else(|| item.message.clone());
item.source = breakpoint.source.or_else(|| item.source.clone());
item.line = breakpoint.line.or(item.line);
item.column = breakpoint.column.or(item.column);
item.end_line = breakpoint.end_line.or(item.end_line);
item.end_column = breakpoint.end_column.or(item.end_column);
item.instruction_reference = breakpoint
.instruction_reference
.or_else(|| item.instruction_reference.clone());
item.offset = breakpoint.offset.or(item.offset);
}
None => {
warn!("Changed breakpoint with id {:?} not found", breakpoint.id);
}
}
}
"removed" => {
match debugger
.breakpoints
.iter()
.position(|b| b.id == breakpoint.id)
{
Some(i) => {
debugger.breakpoints.remove(i);
}
None => {
warn!("Removed breakpoint with id {:?} not found", breakpoint.id);
}
}
}
reason => {
warn!("Unknown breakpoint event: {}", reason);
}
},
Event::Output(events::Output { Event::Output(events::Output {
category, output, .. category, output, ..
}) => { }) => {
@ -340,9 +387,10 @@ impl Application {
// send existing breakpoints // send existing breakpoints
for (path, breakpoints) in &self.editor.breakpoints { for (path, breakpoints) in &self.editor.breakpoints {
// TODO: call futures in parallel, await all // TODO: call futures in parallel, await all
debugger debugger.breakpoints = debugger
.set_breakpoints(path.clone(), breakpoints.clone()) .set_breakpoints(path.clone(), breakpoints.clone())
.await .await
.unwrap()
.unwrap(); .unwrap();
} }
// TODO: fetch breakpoints (in case we're attaching) // TODO: fetch breakpoints (in case we're attaching)

View file

@ -336,10 +336,24 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) {
None => return, None => return,
}; };
let request = debugger.set_breakpoints(path, breakpoints); let request = debugger.set_breakpoints(path, breakpoints);
if let Err(e) = block_on(request) { match block_on(request) {
cx.editor Ok(Some(breakpoints)) => {
.set_error(format!("Failed to set breakpoints: {:?}", e)); let old_breakpoints = debugger.breakpoints.clone();
} debugger.breakpoints = breakpoints.clone();
for bp in breakpoints {
if !old_breakpoints.iter().any(|b| b.message == bp.message) {
if let Some(msg) = &bp.message {
cx.editor.set_status(format!("Breakpoint set: {}", msg));
break;
}
}
}
}
Err(e) => cx
.editor
.set_error(format!("Failed to set breakpoints: {:?}", e)),
_ => {}
};
} }
pub fn dap_continue(cx: &mut Context) { pub fn dap_continue(cx: &mut Context) {

View file

@ -16,11 +16,11 @@ use helix_core::{
unicode::width::UnicodeWidthStr, unicode::width::UnicodeWidthStr,
LineEnding, Position, Range, Selection, LineEnding, Position, Range, Selection,
}; };
use helix_dap::{SourceBreakpoint, StackFrame}; use helix_dap::{Breakpoint, SourceBreakpoint, StackFrame};
use helix_view::{ use helix_view::{
document::Mode, document::Mode,
editor::LineNumber, editor::LineNumber,
graphics::{CursorKind, Modifier, Rect, Style}, graphics::{Color, CursorKind, Modifier, Rect, Style},
info::Info, info::Info,
input::KeyEvent, input::KeyEvent,
keyboard::{KeyCode, KeyModifiers}, keyboard::{KeyCode, KeyModifiers},
@ -76,7 +76,8 @@ 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>>, all_breakpoints: &HashMap<PathBuf, Vec<SourceBreakpoint>>,
dbg_breakpoints: &Option<Vec<Breakpoint>>,
) { ) {
let inner = view.inner_area(); let inner = view.inner_area();
let area = view.area; let area = view.area;
@ -102,7 +103,8 @@ impl EditorView {
is_focused, is_focused,
config, config,
debugger, debugger,
breakpoints, all_breakpoints,
dbg_breakpoints,
); );
if is_focused { if is_focused {
@ -122,7 +124,7 @@ impl EditorView {
} }
} }
self.render_diagnostics(doc, view, inner, surface, theme, breakpoints); self.render_diagnostics(doc, view, inner, surface, theme, all_breakpoints);
let statusline_area = view let statusline_area = view
.area .area
@ -426,7 +428,8 @@ 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>>, all_breakpoints: &HashMap<PathBuf, Vec<SourceBreakpoint>>,
dbg_breakpoints: &Option<Vec<Breakpoint>>,
) { ) {
let text = doc.text().slice(..); let text = doc.text().slice(..);
let last_line = view.last_line(doc); let last_line = view.last_line(doc);
@ -500,10 +503,35 @@ impl EditorView {
let selected = cursors.contains(&line); let selected = cursors.contains(&line);
if let Some(bps) = breakpoints.as_ref() { if let Some(user) = breakpoints.as_ref() {
if let Some(breakpoint) = bps.iter().find(|breakpoint| breakpoint.line - 1 == line) let debugger_breakpoint = if let Some(debugger) = dbg_breakpoints.as_ref() {
debugger.iter().find(|breakpoint| {
if breakpoint.source.is_some()
&& doc.path().is_some()
&& breakpoint.source.as_ref().unwrap().path == doc.path().cloned()
{
match (breakpoint.line, breakpoint.end_line) {
#[allow(clippy::int_plus_one)]
(Some(l), Some(el)) => l - 1 <= line && line <= el - 1,
(Some(l), None) => l - 1 == line,
_ => false,
}
} else {
false
}
})
} else {
None
};
if let Some(breakpoint) = user.iter().find(|breakpoint| breakpoint.line - 1 == line)
{ {
let style = let unverified = match dbg_breakpoints {
Some(_) => debugger_breakpoint.map(|b| !b.verified).unwrap_or(true),
// We cannot mark breakpoint as unverified unless we have a debugger
None => false,
};
let mut style =
if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { if breakpoint.condition.is_some() && breakpoint.log_message.is_some() {
error.add_modifier(Modifier::UNDERLINED) error.add_modifier(Modifier::UNDERLINED)
} else if breakpoint.condition.is_some() { } else if breakpoint.condition.is_some() {
@ -513,7 +541,26 @@ impl EditorView {
} else { } else {
warning warning
}; };
if unverified {
// Faded colors
style = if let Some(Color::Rgb(r, g, b)) = style.fg {
style.fg(Color::Rgb(
((r as f32) * 0.4).floor() as u8,
((g as f32) * 0.4).floor() as u8,
((b as f32) * 0.4).floor() as u8,
))
} else {
style.fg(Color::Gray)
}
};
surface.set_stringn(viewport.x, viewport.y + i as u16, "", 1, style); surface.set_stringn(viewport.x, viewport.y + i as u16, "", 1, style);
} else if let Some(breakpoint) = debugger_breakpoint {
let style = if breakpoint.verified {
info
} else {
info.fg(Color::Gray)
};
surface.set_stringn(viewport.x, viewport.y + i as u16, "", 1, style);
} }
} }
@ -563,7 +610,7 @@ impl EditorView {
viewport: Rect, viewport: Rect,
surface: &mut Surface, surface: &mut Surface,
theme: &Theme, theme: &Theme,
all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>, all_breakpoints: &HashMap<PathBuf, Vec<SourceBreakpoint>>,
) { ) {
use helix_core::diagnostic::Severity; use helix_core::diagnostic::Severity;
use tui::{ use tui::{
@ -602,8 +649,8 @@ impl EditorView {
} }
if let Some(path) = doc.path() { if let Some(path) = doc.path() {
let line = doc.text().char_to_line(cursor);
if let Some(breakpoints) = all_breakpoints.get(path) { if let Some(breakpoints) = all_breakpoints.get(path) {
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)
@ -1272,6 +1319,7 @@ impl Component for EditorView {
for (view, is_focused) in cx.editor.tree.views() { for (view, is_focused) in cx.editor.tree.views() {
let doc = cx.editor.document(view.doc).unwrap(); let doc = cx.editor.document(view.doc).unwrap();
let loader = &cx.editor.syn_loader; let loader = &cx.editor.syn_loader;
let dbg_breakpoints = cx.editor.debugger.as_ref().map(|d| d.breakpoints.clone());
self.render_view( self.render_view(
doc, doc,
view, view,
@ -1283,6 +1331,7 @@ impl Component for EditorView {
&cx.editor.config, &cx.editor.config,
&cx.editor.debugger, &cx.editor.debugger,
&cx.editor.breakpoints, &cx.editor.breakpoints,
&dbg_breakpoints,
); );
} }