on master help sign in
Work towards a breakpoint UI
commit94a1951d40d26f4f535bdb5aab5668c84fdd95ae authorBlaž Hrastnik <blaz@mxxn.io> dateThu 19 Aug 2021, 11:24 (5 years ago) parent8759dc7
7 files changed+69−15
helix-dap/src/client.rs+5 helix-term/src/application.rs+1−5 helix-term/src/commands.rs+36−6 helix-term/src/keymap.rs+3 helix-term/src/ui/editor.rs+19−1 helix-view/src/document.rs−2 helix-view/src/editor.rs+5−1
helix-dap/src/client.rs+5
@@ -33,6 +33,9 @@ pub struct Client {
3333 request_counter: AtomicU64,
3434 capabilities: Option<DebuggerCapabilities>,
3535 awaited_events: Arc<Mutex<HashMap<String, Sender<Event>>>>,
36+
37+ //
38+ pub breakpoints: HashMap<PathBuf, Vec<SourceBreakpoint>>,
3639}
3740
3841impl Client {
@@ -51,6 +54,8 @@ impl Client {
5154 request_counter: AtomicU64::new(0),
5255 capabilities: None,
5356 awaited_events: Arc::new(Mutex::new(HashMap::default())),
57+ //
58+ breakpoints: HashMap::new(),
5459 };
5560
5661 tokio::spawn(Self::recv(Arc::clone(&client.awaited_events), server_rx));
helix-term/src/application.rs+1−5
@@ -245,11 +245,7 @@ impl Application {
245245 }
246246 }
247247
248− pub async fn handle_debugger_message(
249− &mut self,
250− call: (),
251− server_id: usize,
252− ) {
248+ pub async fn handle_debugger_message(&mut self, call: ()) {
253249
254250 //
255251 }
helix-term/src/commands.rs+36−6
@@ -302,6 +302,7 @@ impl Command {
302302 surround_delete, "Surround delete",
303303 select_textobject_around, "Select around object",
304304 select_textobject_inner, "Select inside object",
305+ toggle_breakpoint, "Toggle breakpoint",
305306 suspend, "Suspend"
306307 );
307308}
@@ -1913,25 +1914,21 @@ mod cmd {
19131914 // look up config for filetype
19141915 // if multiple available, open picker
19151916
1916− log::error!("1");
1917−
19181917 let client = Client::tcp_process("dlv", vec!["dap"], "-l 127.0.0.1:{}", 0);
19191918 let mut client = block_on(client)?;
1920− log::error!("2");
19211919
19221920 let request = client.initialize("go".to_owned());
19231921 let _ = block_on(request)?;
1924− log::error!("3");
19251922
19261923 let mut args = HashMap::new();
19271924 args.insert("mode", "debug");
1928− args.insert("program", "main");
1925+ args.insert("program", "main.go");
19291926
19301927 let request = client.launch(to_value(args)?);
19311928 let _ = block_on(request)?;
19321929
19331930 log::error!("4");
1934− doc.debugger = Some(client);
1931+ cx.editor.debugger = Some(client);
19351932 Ok(())
19361933 }
19371934
@@ -4282,3 +4279,36 @@ fn suspend(_cx: &mut Context) {
42824279 #[cfg(not(windows))]
42834280 signal_hook::low_level::raise(signal_hook::consts::signal::SIGTSTP).unwrap();
42844281}
4282+
4283+// DAP
4284+fn toggle_breakpoint(cx: &mut Context) {
4285+ let (view, doc) = current!(cx.editor);
4286+ let text = doc.text().slice(..);
4287+ let pos = doc.selection(view.id).primary().cursor(text);
4288+
4289+ let breakpoint = helix_dap::SourceBreakpoint {
4290+ line: text.char_to_line(pos),
4291+ ..Default::default()
4292+ };
4293+
4294+ let path = match doc.path() {
4295+ Some(path) => path.to_path_buf(),
4296+ None => {
4297+ cx.editor
4298+ .set_error("Can't set breakpoint: document has no path".to_string());
4299+ return;
4300+ }
4301+ };
4302+
4303+ // TODO: need to map breakpoints over edits and update them?
4304+ // we shouldn't really allow editing while debug is running though
4305+
4306+ if let Some(debugger) = &mut cx.editor.debugger {
4307+ let breakpoints = debugger.breakpoints.entry(path).or_default();
4308+ if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) {
4309+ breakpoints.remove(pos);
4310+ } else {
4311+ breakpoints.push(breakpoint);
4312+ }
4313+ }
4314+}
helix-term/src/keymap.rs+3
@@ -485,6 +485,9 @@ impl Default for Keymaps {
485485 "s" => symbol_picker,
486486 "a" => code_action,
487487 "'" => last_picker,
488+ "d" => { "Debug"
489+ "b" => toggle_breakpoint,
490+ },
488491 "w" => { "Window"
489492 "C-w" | "w" => rotate_view,
490493 "C-h" | "h" => hsplit,
helix-term/src/ui/editor.rs+19−1
@@ -71,6 +71,7 @@ impl EditorView {
7171 is_focused: bool,
7272 loader: &syntax::Loader,
7373 config: &helix_view::editor::Config,
74+ debugger: Option<&helix_dap::Client>,
7475 ) {
7576 let inner = view.inner_area();
7677 let area = view.area;
@@ -87,7 +88,9 @@ impl EditorView {
8788 };
8889
8990 Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights);
90− Self::render_gutter(doc, view, view.area, surface, theme, is_focused, config);
91+ Self::render_gutter(
92+ doc, view, view.area, surface, theme, is_focused, config, debugger,
93+ );
9194
9295 if is_focused {
9396 Self::render_focused_view_elements(view, doc, inner, theme, surface);
@@ -409,6 +412,7 @@ impl EditorView {
409412 theme: &Theme,
410413 is_focused: bool,
411414 config: &helix_view::editor::Config,
415+ debugger: Option<&helix_dap::Client>,
412416 ) {
413417 let text = doc.text().slice(..);
414418 let last_line = view.last_line(doc);
@@ -438,6 +442,10 @@ impl EditorView {
438442 .map(|range| range.cursor_line(text))
439443 .collect();
440444
445+ let breakpoints = doc
446+ .path()
447+ .and_then(|path| debugger.and_then(|debugger| debugger.breakpoints.get(path)));
448+
441449 for (i, line) in (view.offset.row..(last_line + 1)).enumerate() {
442450 use helix_core::diagnostic::Severity;
443451 if let Some(diagnostic) = doc.diagnostics().iter().find(|d| d.line == line) {
@@ -457,6 +465,14 @@ impl EditorView {
457465
458466 let selected = cursors.contains(&line);
459467
468+ if let Some(breakpoint) = breakpoints.and_then(|breakpoints| {
469+ breakpoints
470+ .iter()
471+ .find(|breakpoint| breakpoint.line == line)
472+ }) {
473+ surface.set_stringn(viewport.x, viewport.y + i as u16, "▲", 1, warning);
474+ }
475+
460476 let text = if line == last_line && !draw_last {
461477 " ~".into()
462478 } else {
@@ -1007,6 +1023,7 @@ impl Component for EditorView {
10071023 for (view, is_focused) in cx.editor.tree.views() {
10081024 let doc = cx.editor.document(view.doc).unwrap();
10091025 let loader = &cx.editor.syn_loader;
1026+ let debugger = cx.editor.debugger.as_ref();
10101027 self.render_view(
10111028 doc,
10121029 view,
@@ -1016,6 +1033,7 @@ impl Component for EditorView {
10161033 is_focused,
10171034 loader,
10181035 &cx.editor.config,
1036+ debugger,
10191037 );
10201038 }
10211039
helix-view/src/document.rs−2
@@ -100,7 +100,6 @@ pub struct Document {
100100
101101 diagnostics: Vec<Diagnostic>,
102102 language_server: Option<Arc<helix_lsp::Client>>,
103− pub debugger: Option<helix_dap::Client>,
104103}
105104
106105use std::fmt;
@@ -426,7 +425,6 @@ impl Document {
426425 history: Cell::new(History::default()),
427426 last_saved_revision: 0,
428427 language_server: None,
429− debugger: None,
430428 line_ending: DEFAULT_LINE_ENDING,
431429 }
432430 }
helix-view/src/editor.rs+5−1
@@ -73,7 +73,10 @@ pub struct Editor {
7373 pub registers: Registers,
7474 pub theme: Theme,
7575 pub language_servers: helix_lsp::Registry,
76− pub debuggers: SelectAll<UnboundedReceiverStream<(usize, helix_dap::Payload)>>,
76+
77+ pub debugger: Option<helix_dap::Client>,
78+ pub debuggers: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>,
79+
7780 pub clipboard_provider: Box<dyn ClipboardProvider>,
7881
7982 pub syn_loader: Arc<syntax::Loader>,
@@ -111,6 +114,7 @@ impl Editor {
111114 selected_register: RegisterSelection::default(),
112115 theme: themes.default(),
113116 language_servers,
117+ debugger: None,
114118 debuggers: SelectAll::new(),
115119 syn_loader: config_loader,
116120 theme_loader: themes,