Add command for editing breakpoint condition

This commit is contained in:
Dmitry Sharshakov 2021-09-04 22:57:58 +03:00
parent e36fc57fff
commit 1befbd076c
7 changed files with 88 additions and 11 deletions

View File

@ -317,6 +317,7 @@ pub fn doc(&self) -> &'static str {
dap_next, "Step to next", dap_next, "Step to next",
dap_variables, "List variables", dap_variables, "List variables",
dap_terminate, "End debug session", dap_terminate, "End debug session",
dap_edit_condition, "Edit condition of the breakpoint on the current line",
dap_switch_thread, "Switch current thread", dap_switch_thread, "Switch current thread",
dap_switch_stack_frame, "Switch stack frame", dap_switch_stack_frame, "Switch stack frame",
shell_pipe, "Pipe selections through shell command", shell_pipe, "Pipe selections through shell command",
@ -1979,10 +1980,10 @@ fn debug_eval(
Ok(()) Ok(())
} }
fn get_breakpoint_at_current_line( pub fn get_breakpoint_at_current_line(
cx: &mut compositor::Context, editor: &mut Editor,
) -> Option<(usize, SourceBreakpoint)> { ) -> Option<(usize, SourceBreakpoint)> {
let (view, doc) = current!(cx.editor); let (view, doc) = current!(editor);
let text = doc.text().slice(..); let text = doc.text().slice(..);
let pos = doc.selection(view.id).primary().cursor(text); let pos = doc.selection(view.id).primary().cursor(text);
@ -1992,12 +1993,9 @@ fn get_breakpoint_at_current_line(
None => return None, None => return None,
}; };
let vec = vec![]; let vec = vec![];
let breakpoints = cx.editor.breakpoints.get(&path.clone()).unwrap_or(&vec); let breakpoints = editor.breakpoints.get(&path).unwrap_or(&vec);
let i = breakpoints.iter().position(|b| b.line == line); let i = breakpoints.iter().position(|b| b.line == line);
match i { i.map(|i| (i, breakpoints.get(i).unwrap().clone()))
Some(i) => Some((i, breakpoints.get(i).unwrap().clone())),
None => None,
}
} }
fn edit_breakpoint_impl( fn edit_breakpoint_impl(
@ -2015,7 +2013,7 @@ fn edit_breakpoint_impl(
} }
}; };
if let Some((pos, mut bp)) = get_breakpoint_at_current_line(cx) { if let Some((pos, mut bp)) = get_breakpoint_at_current_line(cx.editor) {
let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default(); let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
breakpoints.remove(pos); breakpoints.remove(pos);
@ -2481,6 +2479,7 @@ fn command_mode(cx: &mut Context) {
.set_error(format!("no such command: '{}'", parts[0])); .set_error(format!("no such command: '{}'", parts[0]));
}; };
}, },
None,
); );
prompt.doc_fn = Box::new(|input: &str| { prompt.doc_fn = Box::new(|input: &str| {
let part = input.split(' ').next().unwrap_or_default(); let part = input.split(' ').next().unwrap_or_default();
@ -4584,6 +4583,7 @@ fn shell_keep_pipe(cx: &mut Context) {
let index = index.unwrap_or_else(|| ranges.len() - 1); let index = index.unwrap_or_else(|| ranges.len() - 1);
doc.set_selection(view.id, Selection::new(ranges, index)); doc.set_selection(view.id, Selection::new(ranges, index));
}, },
None,
); );
cx.push_layer(Box::new(prompt)); cx.push_layer(Box::new(prompt));
@ -4683,6 +4683,7 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
doc.append_changes_to_history(view.id); doc.append_changes_to_history(view.id);
} }
}, },
None,
); );
cx.push_layer(Box::new(prompt)); cx.push_layer(Box::new(prompt));

View File

@ -1,5 +1,8 @@
use super::{align_view, Align, Context, Editor}; use super::{align_view, Align, Context, Editor};
use crate::ui::{FilePicker, Picker}; use crate::{
commands,
ui::{FilePicker, Picker, Prompt, PromptEvent},
};
use helix_core::Selection; use helix_core::Selection;
use helix_dap::{self as dap, Client}; use helix_dap::{self as dap, Client};
use helix_lsp::block_on; use helix_lsp::block_on;
@ -474,6 +477,74 @@ pub fn dap_terminate(cx: &mut Context) {
cx.editor.debugger = None; cx.editor.debugger = None;
} }
pub fn dap_edit_condition(cx: &mut Context) {
if let Some((pos, mut bp)) = commands::cmd::get_breakpoint_at_current_line(cx.editor) {
let condition = bp.condition.clone();
let prompt = Prompt::new(
"condition: ".into(),
None,
|_input: &str| Vec::new(),
move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
if event != PromptEvent::Validate {
return;
}
let (_, doc) = current!(cx.editor);
let path = match doc.path() {
Some(path) => path.to_path_buf(),
None => {
cx.editor
.set_status("Can't edit breakpoint: document has no path".to_owned());
return;
}
};
let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
breakpoints.remove(pos);
bp.condition = match input {
"" => None,
input => Some(input.to_owned()),
};
breakpoints.push(bp.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.clone());
if let Err(e) = block_on(request) {
cx.editor
.set_status(format!("Failed to set breakpoints: {:?}", e))
}
}
},
condition,
);
cx.push_layer(Box::new(prompt));
}
}
pub fn dap_switch_thread(cx: &mut Context) { pub fn dap_switch_thread(cx: &mut Context) {
thread_picker(cx, |editor, thread| { thread_picker(cx, |editor, thread| {
block_on(select_thread_id(editor, thread.id, true)); block_on(select_thread_id(editor, thread.id, true));

View File

@ -497,6 +497,7 @@ fn default() -> Keymaps {
"n" => dap_next, "n" => dap_next,
"v" => dap_variables, "v" => dap_variables,
"t" => dap_terminate, "t" => dap_terminate,
"C-c" => dap_edit_condition,
"s" => { "Switch" "s" => { "Switch"
"t" => dap_switch_thread, "t" => dap_switch_thread,
"f" => dap_switch_stack_frame, "f" => dap_switch_stack_frame,

View File

@ -795,6 +795,7 @@ fn debug_parameter_prompt(
); );
} }
}, },
None,
) )
} }

View File

@ -70,6 +70,7 @@ pub fn regex_prompt(
} }
} }
}, },
None,
) )
} }

View File

@ -208,6 +208,7 @@ pub fn new(
|_editor: &mut Context, _pattern: &str, _event: PromptEvent| { |_editor: &mut Context, _pattern: &str, _event: PromptEvent| {
// //
}, },
None,
); );
let mut picker = Self { let mut picker = Self {

View File

@ -59,10 +59,11 @@ pub fn new(
history_register: Option<char>, history_register: Option<char>,
mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static, mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static,
callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static, callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static,
line: Option<String>,
) -> Self { ) -> Self {
Self { Self {
prompt, prompt,
line: String::new(), line: line.unwrap_or_default(),
cursor: 0, cursor: 0,
completion: completion_fn(""), completion: completion_fn(""),
selection: None, selection: None,