dap: Allow setting breakpoints before starting the adapter
This commit is contained in:
parent
289303a30d
commit
b997d2cdeb
6 changed files with 83 additions and 65 deletions
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue