on master help sign in
New way of starting debug sessions
8df6739Dmitry Sharshakov
helix-term/src/commands.rs+37−1
@@ -304,6 +304,7 @@ impl Command {
304 surround_delete, "Surround delete",
304 surround_delete, "Surround delete",
305 select_textobject_around, "Select around object",
305 select_textobject_around, "Select around object",
306 select_textobject_inner, "Select inside object",
306 select_textobject_inner, "Select inside object",
307+ dap_launch, "Launch debug target",
307 dap_toggle_breakpoint, "Toggle breakpoint",
308 dap_toggle_breakpoint, "Toggle breakpoint",
308 dap_run, "Begin program execution",
309 dap_run, "Begin program execution",
309 dap_continue, "Continue program execution",
310 dap_continue, "Continue program execution",
@@ -4491,7 +4492,7 @@ fn suspend(_cx: &mut Context) {
4491}
4492}
4492
4493
4493// DAP
4494// DAP
4494−fn dap_start_impl(
4495+pub fn dap_start_impl(
4495 editor: &mut Editor,
4496 editor: &mut Editor,
4496 name: Option<&str>,
4497 name: Option<&str>,
4497 socket: Option<std::net::SocketAddr>,
4498 socket: Option<std::net::SocketAddr>,
@@ -4596,6 +4597,41 @@ fn dap_start_impl(
4596 editor.debugger_events.push(stream);
4597 editor.debugger_events.push(stream);
4597}
4598}
4598
4599
4600+fn dap_launch(cx: &mut Context) {
4601+ if cx.editor.debugger.is_some() {
4602+ cx.editor
4603+ .set_error("Can't start debug: debugger is running".to_string());
4604+ return;
4605+ }
4606+
4607+ let (_, doc) = current!(cx.editor);
4608+ let path = match doc.path() {
4609+ Some(path) => path.to_path_buf(),
4610+ None => {
4611+ cx.editor
4612+ .set_error("Can't start debug: document has no path".to_string());
4613+ return;
4614+ }
4615+ };
4616+
4617+ let config = cx
4618+ .editor
4619+ .syn_loader
4620+ .language_config_for_file_name(&path)
4621+ .and_then(|x| x.debugger.clone());
4622+ let config = match config {
4623+ Some(c) => c,
4624+ None => {
4625+ cx.editor.set_error(
4626+ "Can't start debug: no debug adapter available for language".to_string(),
4627+ );
4628+ return;
4629+ }
4630+ };
4631+
4632+ cx.editor.debug_config_picker = Some(config.templates.iter().map(|t| t.name.clone()).collect());
4633+}
4634+
4599fn dap_toggle_breakpoint(cx: &mut Context) {
4635fn dap_toggle_breakpoint(cx: &mut Context) {
4600 use helix_lsp::block_on;
4636 use helix_lsp::block_on;
4601
4637
helix-term/src/keymap.rs+1
@@ -486,6 +486,7 @@ impl Default for Keymaps {
486 "a" => code_action,
486 "a" => code_action,
487 "'" => last_picker,
487 "'" => last_picker,
488 "d" => { "Debug"
488 "d" => { "Debug"
489+ "s" => dap_launch,
489 "b" => dap_toggle_breakpoint,
490 "b" => dap_toggle_breakpoint,
490 "r" => dap_run,
491 "r" => dap_run,
491 "c" => dap_continue,
492 "c" => dap_continue,
helix-term/src/ui/editor.rs+62
@@ -30,6 +30,8 @@ use std::borrow::Cow;
30use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind};
30use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind};
31use tui::buffer::Buffer as Surface;
31use tui::buffer::Buffer as Surface;
32
32
33+use super::{Prompt, PromptEvent};
34+
33pub struct EditorView {
35pub struct EditorView {
34 keymaps: Keymaps,
36 keymaps: Keymaps,
35 on_next_key: Option<Box<dyn FnOnce(&mut commands::Context, KeyEvent)>>,
37 on_next_key: Option<Box<dyn FnOnce(&mut commands::Context, KeyEvent)>>,
@@ -712,6 +714,45 @@ impl EditorView {
712 ) -> Option<KeymapResult> {
714 ) -> Option<KeymapResult> {
713 self.autoinfo = None;
715 self.autoinfo = None;
714
716
717+ if let Some(picker) = cxt.editor.debug_config_picker.clone() {
718+ match event {
719+ KeyEvent {
720+ code: KeyCode::Esc, ..
721+ } => {}
722+ KeyEvent {
723+ code: KeyCode::Char(char),
724+ ..
725+ } => {
726+ let name = match picker.iter().find(|t| t.starts_with(char)) {
727+ Some(n) => n.clone(),
728+ None => return None,
729+ };
730+ let prompt = Prompt::new(
731+ "arg:".to_owned(),
732+ None,
733+ |_input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate
734+ move |cx: &mut crate::compositor::Context,
735+ input: &str,
736+ event: PromptEvent| {
737+ if event != PromptEvent::Validate {
738+ return;
739+ }
740+ commands::dap_start_impl(
741+ cx.editor,
742+ Some(&name),
743+ None,
744+ Some(vec![input]),
745+ );
746+ },
747+ );
748+ cxt.push_layer(Box::new(prompt));
749+ }
750+ _ => return None,
751+ }
752+ cxt.editor.debug_config_picker = None;
753+ return None;
754+ }
755+
715 if cxt.editor.variables.is_some() {
756 if cxt.editor.variables.is_some() {
716 match event {
757 match event {
717 KeyEvent {
758 KeyEvent {
@@ -735,6 +776,7 @@ impl EditorView {
735 }
776 }
736 return None;
777 return None;
737 }
778 }
779+
738 match self.keymaps.get_mut(&mode).unwrap().get(event) {
780 match self.keymaps.get_mut(&mode).unwrap().get(event) {
739 KeymapResult::Matched(command) => command.execute(cxt),
781 KeymapResult::Matched(command) => command.execute(cxt),
740 KeymapResult::Pending(node) => self.autoinfo = Some(node.into()),
782 KeymapResult::Pending(node) => self.autoinfo = Some(node.into()),
@@ -1137,6 +1179,26 @@ impl Component for EditorView {
1137 info.render(area, surface, cx);
1179 info.render(area, surface, cx);
1138 }
1180 }
1139
1181
1182+ if let Some(ref configs) = cx.editor.debug_config_picker {
1183+ let mut text = String::new();
1184+ let mut height = 0;
1185+ let mut max_len = 20;
1186+
1187+ for line in configs {
1188+ max_len = max_len.max(line.len() as u16 + 2);
1189+ height += 1;
1190+ text.push_str(&format!("{} {}\n", line.chars().next().unwrap(), line));
1191+ }
1192+
1193+ let mut info = Info {
1194+ height: 20.min(height + 1),
1195+ width: 70.min(max_len),
1196+ title: "Debug targets".to_owned(),
1197+ text: text + "Exit Esc",
1198+ };
1199+ info.render(area, surface, cx);
1200+ }
1201+
1140 if let Some(ref mut info) = self.autoinfo {
1202 if let Some(ref mut info) = self.autoinfo {
1141 info.render(area, surface, cx);
1203 info.render(area, surface, cx);
1142 }
1204 }
helix-view/src/editor.rs+2
@@ -76,6 +76,7 @@ pub struct Editor {
76
76
77 pub debugger: Option<helix_dap::Client>,
77 pub debugger: Option<helix_dap::Client>,
78 pub debugger_events: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>,
78 pub debugger_events: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>,
79+ pub debug_config_picker: Option<Vec<String>>,
79 pub variables: Option<Vec<String>>,
80 pub variables: Option<Vec<String>>,
80 pub variables_page: usize,
81 pub variables_page: usize,
81
82
@@ -118,6 +119,7 @@ impl Editor {
118 language_servers,
119 language_servers,
119 debugger: None,
120 debugger: None,
120 debugger_events: SelectAll::new(),
121 debugger_events: SelectAll::new(),
122+ debug_config_picker: None,
121 variables: None,
123 variables: None,
122 variables_page: 0,
124 variables_page: 0,
123 syn_loader: config_loader,
125 syn_loader: config_loader,