aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-dap/src/client.rs2
-rw-r--r--helix-term/src/application.rs52
-rw-r--r--helix-term/src/commands/dap.rs22
-rw-r--r--helix-term/src/ui/editor.rs71
4 files changed, 130 insertions, 17 deletions
diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs
index e1791cd1..e5f8feb9 100644
--- a/helix-dap/src/client.rs
+++ b/helix-dap/src/client.rs
@@ -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));
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index ce6cc76b..7a573adc 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -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)
diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs
index 61b1f438..3fb990c2 100644
--- a/helix-term/src/commands/dap.rs
+++ b/helix-term/src/commands/dap.rs
@@ -336,10 +336,24 @@ 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) {
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 85b00481..63694d0b 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -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()
+ {
+ 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() {
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() {
+ let line = doc.text().char_to_line(cursor);
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)
@@ -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,
);
}