Get breakpoint reports from debugger
This commit is contained in:
parent
c9cd06e904
commit
507a1f8dd6
4 changed files with 130 additions and 17 deletions
|
@ -33,6 +33,7 @@ pub struct Client {
|
|||
pub thread_id: Option<isize>,
|
||||
/// Currently active frame for the current thread.
|
||||
pub active_frame: Option<usize>,
|
||||
pub breakpoints: Vec<Breakpoint>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -80,6 +81,7 @@ impl Client {
|
|||
thread_states: HashMap::new(),
|
||||
thread_id: None,
|
||||
active_frame: None,
|
||||
breakpoints: vec![],
|
||||
};
|
||||
|
||||
tokio::spawn(Self::recv(server_rx, client_rx));
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
args::Args, commands::fetch_stack_trace, compositor::Compositor, config::Config, job::Jobs, ui,
|
||||
};
|
||||
|
||||
use log::error;
|
||||
use log::{error, warn};
|
||||
use std::{
|
||||
io::{stdout, Write},
|
||||
sync::Arc,
|
||||
|
@ -320,6 +320,53 @@ impl Application {
|
|||
Event::Thread(_) => {
|
||||
// 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 {
|
||||
category, output, ..
|
||||
}) => {
|
||||
|
@ -340,9 +387,10 @@ impl Application {
|
|||
// send existing breakpoints
|
||||
for (path, breakpoints) in &self.editor.breakpoints {
|
||||
// TODO: call futures in parallel, await all
|
||||
debugger
|
||||
debugger.breakpoints = debugger
|
||||
.set_breakpoints(path.clone(), breakpoints.clone())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
}
|
||||
// TODO: fetch breakpoints (in case we're attaching)
|
||||
|
|
|
@ -336,11 +336,25 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) {
|
|||
None => return,
|
||||
};
|
||||
let request = debugger.set_breakpoints(path, breakpoints);
|
||||
if let Err(e) = block_on(request) {
|
||||
cx.editor
|
||||
.set_error(format!("Failed to set breakpoints: {:?}", e));
|
||||
match block_on(request) {
|
||||
Ok(Some(breakpoints)) => {
|
||||
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) {
|
||||
let debugger = match &mut cx.editor.debugger {
|
||||
|
|
|
@ -16,11 +16,11 @@ use helix_core::{
|
|||
unicode::width::UnicodeWidthStr,
|
||||
LineEnding, Position, Range, Selection,
|
||||
};
|
||||
use helix_dap::{SourceBreakpoint, StackFrame};
|
||||
use helix_dap::{Breakpoint, SourceBreakpoint, StackFrame};
|
||||
use helix_view::{
|
||||
document::Mode,
|
||||
editor::LineNumber,
|
||||
graphics::{CursorKind, Modifier, Rect, Style},
|
||||
graphics::{Color, CursorKind, Modifier, Rect, Style},
|
||||
info::Info,
|
||||
input::KeyEvent,
|
||||
keyboard::{KeyCode, KeyModifiers},
|
||||
|
@ -76,7 +76,8 @@ impl EditorView {
|
|||
loader: &syntax::Loader,
|
||||
config: &helix_view::editor::Config,
|
||||
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 area = view.area;
|
||||
|
@ -102,7 +103,8 @@ impl EditorView {
|
|||
is_focused,
|
||||
config,
|
||||
debugger,
|
||||
breakpoints,
|
||||
all_breakpoints,
|
||||
dbg_breakpoints,
|
||||
);
|
||||
|
||||
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
|
||||
.area
|
||||
|
@ -426,7 +428,8 @@ impl EditorView {
|
|||
is_focused: bool,
|
||||
config: &helix_view::editor::Config,
|
||||
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 last_line = view.last_line(doc);
|
||||
|
@ -500,10 +503,35 @@ impl EditorView {
|
|||
|
||||
let selected = cursors.contains(&line);
|
||||
|
||||
if let Some(bps) = breakpoints.as_ref() {
|
||||
if let Some(breakpoint) = bps.iter().find(|breakpoint| breakpoint.line - 1 == line)
|
||||
if let Some(user) = breakpoints.as_ref() {
|
||||
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()
|
||||
{
|
||||
let style =
|
||||
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 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() {
|
||||
error.add_modifier(Modifier::UNDERLINED)
|
||||
} else if breakpoint.condition.is_some() {
|
||||
|
@ -513,7 +541,26 @@ impl EditorView {
|
|||
} else {
|
||||
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);
|
||||
} 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,
|
||||
surface: &mut Surface,
|
||||
theme: &Theme,
|
||||
all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
|
||||
all_breakpoints: &HashMap<PathBuf, Vec<SourceBreakpoint>>,
|
||||
) {
|
||||
use helix_core::diagnostic::Severity;
|
||||
use tui::{
|
||||
|
@ -602,8 +649,8 @@ impl EditorView {
|
|||
}
|
||||
|
||||
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(breakpoints) = all_breakpoints.get(path) {
|
||||
if let Some(breakpoint) = breakpoints
|
||||
.iter()
|
||||
.find(|breakpoint| breakpoint.line - 1 == line)
|
||||
|
@ -1272,6 +1319,7 @@ impl Component for EditorView {
|
|||
for (view, is_focused) in cx.editor.tree.views() {
|
||||
let doc = cx.editor.document(view.doc).unwrap();
|
||||
let loader = &cx.editor.syn_loader;
|
||||
let dbg_breakpoints = cx.editor.debugger.as_ref().map(|d| d.breakpoints.clone());
|
||||
self.render_view(
|
||||
doc,
|
||||
view,
|
||||
|
@ -1283,6 +1331,7 @@ impl Component for EditorView {
|
|||
&cx.editor.config,
|
||||
&cx.editor.debugger,
|
||||
&cx.editor.breakpoints,
|
||||
&dbg_breakpoints,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue