on master help sign in
Add command for editing breakpoint condition
1befbd0Dmitry Sharshakov
helix-term/src/commands.rs+10−9
@@ -317,6 +317,7 @@ impl Command {
317 dap_next, "Step to next",
317 dap_next, "Step to next",
318 dap_variables, "List variables",
318 dap_variables, "List variables",
319 dap_terminate, "End debug session",
319 dap_terminate, "End debug session",
320+ dap_edit_condition, "Edit condition of the breakpoint on the current line",
320 dap_switch_thread, "Switch current thread",
321 dap_switch_thread, "Switch current thread",
321 dap_switch_stack_frame, "Switch stack frame",
322 dap_switch_stack_frame, "Switch stack frame",
322 shell_pipe, "Pipe selections through shell command",
323 shell_pipe, "Pipe selections through shell command",
@@ -1979,10 +1980,10 @@ mod cmd {
1979 Ok(())
1980 Ok(())
1980 }
1981 }
1981
1982
1982− fn get_breakpoint_at_current_line(
1983+ pub fn get_breakpoint_at_current_line(
1983− cx: &mut compositor::Context,
1984+ editor: &mut Editor,
1984 ) -> Option<(usize, SourceBreakpoint)> {
1985 ) -> Option<(usize, SourceBreakpoint)> {
1985− let (view, doc) = current!(cx.editor);
1986+ let (view, doc) = current!(editor);
1986 let text = doc.text().slice(..);
1987 let text = doc.text().slice(..);
1987
1988
1988 let pos = doc.selection(view.id).primary().cursor(text);
1989 let pos = doc.selection(view.id).primary().cursor(text);
@@ -1992,12 +1993,9 @@ mod cmd {
1992 None => return None,
1993 None => return None,
1993 };
1994 };
1994 let vec = vec![];
1995 let vec = vec![];
1995− let breakpoints = cx.editor.breakpoints.get(&path.clone()).unwrap_or(&vec);
1996+ let breakpoints = editor.breakpoints.get(&path).unwrap_or(&vec);
1996 let i = breakpoints.iter().position(|b| b.line == line);
1997 let i = breakpoints.iter().position(|b| b.line == line);
1997− match i {
1998− Some(i) => Some((i, breakpoints.get(i).unwrap().clone())),
1998+ i.map(|i| (i, breakpoints.get(i).unwrap().clone()))
1999− None => None,
2000− }
2001 }
1999 }
2002
2000
2003 fn edit_breakpoint_impl(
2001 fn edit_breakpoint_impl(
@@ -2015,7 +2013,7 @@ mod cmd {
2015 }
2013 }
2016 };
2014 };
2017
2015
2018− if let Some((pos, mut bp)) = get_breakpoint_at_current_line(cx) {
2016+ if let Some((pos, mut bp)) = get_breakpoint_at_current_line(cx.editor) {
2019 let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
2017 let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
2020 breakpoints.remove(pos);
2018 breakpoints.remove(pos);
2021
2019
@@ -2481,6 +2479,7 @@ fn command_mode(cx: &mut Context) {
2481 .set_error(format!("no such command: '{}'", parts[0]));
2479 .set_error(format!("no such command: '{}'", parts[0]));
2482 };
2480 };
2483 },
2481 },
2482+ None,
2484 );
2483 );
2485 prompt.doc_fn = Box::new(|input: &str| {
2484 prompt.doc_fn = Box::new(|input: &str| {
2486 let part = input.split(' ').next().unwrap_or_default();
2485 let part = input.split(' ').next().unwrap_or_default();
@@ -4584,6 +4583,7 @@ fn shell_keep_pipe(cx: &mut Context) {
4584 let index = index.unwrap_or_else(|| ranges.len() - 1);
4583 let index = index.unwrap_or_else(|| ranges.len() - 1);
4585 doc.set_selection(view.id, Selection::new(ranges, index));
4584 doc.set_selection(view.id, Selection::new(ranges, index));
4586 },
4585 },
4586+ None,
4587 );
4587 );
4588
4588
4589 cx.push_layer(Box::new(prompt));
4589 cx.push_layer(Box::new(prompt));
@@ -4683,6 +4683,7 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
4683 doc.append_changes_to_history(view.id);
4683 doc.append_changes_to_history(view.id);
4684 }
4684 }
4685 },
4685 },
4686+ None,
4686 );
4687 );
4687
4688
4688 cx.push_layer(Box::new(prompt));
4689 cx.push_layer(Box::new(prompt));
helix-term/src/commands/dap.rs+72−1
@@ -1,5 +1,8 @@
1use super::{align_view, Align, Context, Editor};
1use super::{align_view, Align, Context, Editor};
2+use crate::{
3+ commands,
2−use crate::ui::{FilePicker, Picker};
4+ ui::{FilePicker, Picker, Prompt, PromptEvent},
5+};
3use helix_core::Selection;
6use helix_core::Selection;
4use helix_dap::{self as dap, Client};
7use helix_dap::{self as dap, Client};
5use helix_lsp::block_on;
8use helix_lsp::block_on;
@@ -474,6 +477,74 @@ pub fn dap_terminate(cx: &mut Context) {
474 cx.editor.debugger = None;
477 cx.editor.debugger = None;
475}
478}
476
479
480+pub fn dap_edit_condition(cx: &mut Context) {
481+ if let Some((pos, mut bp)) = commands::cmd::get_breakpoint_at_current_line(cx.editor) {
482+ let condition = bp.condition.clone();
483+ let prompt = Prompt::new(
484+ "condition: ".into(),
485+ None,
486+ |_input: &str| Vec::new(),
487+ move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
488+ if event != PromptEvent::Validate {
489+ return;
490+ }
491+
492+ let (_, doc) = current!(cx.editor);
493+ let path = match doc.path() {
494+ Some(path) => path.to_path_buf(),
495+ None => {
496+ cx.editor
497+ .set_status("Can't edit breakpoint: document has no path".to_owned());
498+ return;
499+ }
500+ };
501+
502+ let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
503+ breakpoints.remove(pos);
504+ bp.condition = match input {
505+ "" => None,
506+ input => Some(input.to_owned()),
507+ };
508+ breakpoints.push(bp.clone());
509+
510+ if let Some(debugger) = &mut cx.editor.debugger {
511+ // TODO: handle capabilities correctly again, by filterin breakpoints when emitting
512+ // if breakpoint.condition.is_some()
513+ // && !debugger
514+ // .caps
515+ // .as_ref()
516+ // .unwrap()
517+ // .supports_conditional_breakpoints
518+ // .unwrap_or_default()
519+ // {
520+ // bail!(
521+ // "Can't edit breakpoint: debugger does not support conditional breakpoints"
522+ // )
523+ // }
524+ // if breakpoint.log_message.is_some()
525+ // && !debugger
526+ // .caps
527+ // .as_ref()
528+ // .unwrap()
529+ // .supports_log_points
530+ // .unwrap_or_default()
531+ // {
532+ // bail!("Can't edit breakpoint: debugger does not support logpoints")
533+ // }
534+ let request = debugger.set_breakpoints(path, breakpoints.clone());
535+ if let Err(e) = block_on(request) {
536+ cx.editor
537+ .set_status(format!("Failed to set breakpoints: {:?}", e))
538+ }
539+ }
540+ },
541+ condition,
542+ );
543+
544+ cx.push_layer(Box::new(prompt));
545+ }
546+}
547+
477pub fn dap_switch_thread(cx: &mut Context) {
548pub fn dap_switch_thread(cx: &mut Context) {
478 thread_picker(cx, |editor, thread| {
549 thread_picker(cx, |editor, thread| {
479 block_on(select_thread_id(editor, thread.id, true));
550 block_on(select_thread_id(editor, thread.id, true));
helix-term/src/keymap.rs+1
@@ -497,6 +497,7 @@ impl Default for Keymaps {
497 "n" => dap_next,
497 "n" => dap_next,
498 "v" => dap_variables,
498 "v" => dap_variables,
499 "t" => dap_terminate,
499 "t" => dap_terminate,
500+ "C-c" => dap_edit_condition,
500 "s" => { "Switch"
501 "s" => { "Switch"
501 "t" => dap_switch_thread,
502 "t" => dap_switch_thread,
502 "f" => dap_switch_stack_frame,
503 "f" => dap_switch_stack_frame,
helix-term/src/ui/editor.rs+1
@@ -795,6 +795,7 @@ impl EditorView {
795 );
795 );
796 }
796 }
797 },
797 },
798+ None,
798 )
799 )
799 }
800 }
800
801
helix-term/src/ui/mod.rs+1
@@ -70,6 +70,7 @@ pub fn regex_prompt(
70 }
70 }
71 }
71 }
72 },
72 },
73+ None,
73 )
74 )
74}
75}
75
76
helix-term/src/ui/picker.rs+1
@@ -208,6 +208,7 @@ impl<T> Picker<T> {
208 |_editor: &mut Context, _pattern: &str, _event: PromptEvent| {
208 |_editor: &mut Context, _pattern: &str, _event: PromptEvent| {
209 //
209 //
210 },
210 },
211+ None,
211 );
212 );
212
213
213 let mut picker = Self {
214 let mut picker = Self {
helix-term/src/ui/prompt.rs+2−1
@@ -59,10 +59,11 @@ impl Prompt {
59 history_register: Option<char>,
59 history_register: Option<char>,
60 mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static,
60 mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static,
61 callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static,
61 callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static,
62+ line: Option<String>,
62 ) -> Self {
63 ) -> Self {
63 Self {
64 Self {
64 prompt,
65 prompt,
65− line: String::new(),
66+ line: line.unwrap_or_default(),
66 cursor: 0,
67 cursor: 0,
67 completion: completion_fn(""),
68 completion: completion_fn(""),
68 selection: None,
69 selection: None,