From 6458edecfd5fda486c9b9a1d0d802aa23bcd90ac Mon Sep 17 00:00:00 2001 From: Dmitry Sharshakov Date: Sat, 21 Aug 2021 14:15:29 +0300 Subject: [PATCH] Add stack pointer display when stopped --- helix-dap/src/client.rs | 3 +++ helix-term/src/commands.rs | 30 ++++++++++++++++++++-- helix-term/src/ui/editor.rs | 51 +++++++++++++++++++++++++++---------- helix-view/src/editor.rs | 3 ++- 4 files changed, 70 insertions(+), 17 deletions(-) diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index e7e714b6f..7f648e987 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -36,6 +36,8 @@ pub struct Client { // pub breakpoints: HashMap>, + // TODO: multiple threads support + pub stack_pointer: Option, } impl Client { @@ -56,6 +58,7 @@ impl Client { awaited_events: Arc::new(Mutex::new(HashMap::default())), // breakpoints: HashMap::new(), + stack_pointer: None, }; tokio::spawn(Self::recv(Arc::clone(&client.awaited_events), server_rx)); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0b222a2ab..b463da2ae 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -24,6 +24,7 @@ use helix_lsp::{ }; use insert::*; use movement::Movement; +use tokio::sync::{mpsc::Receiver, Mutex}; use crate::{ compositor::{self, Component, Compositor}, @@ -32,8 +33,8 @@ use crate::{ use crate::job::{self, Job, Jobs}; use futures_util::FutureExt; -use std::num::NonZeroUsize; use std::{collections::HashMap, fmt, future::Future}; +use std::{num::NonZeroUsize, sync::Arc}; use std::{ borrow::Cow, @@ -4267,11 +4268,34 @@ fn dap_start(cx: &mut Context) { let request = debugger.launch(to_value(args).unwrap()); let _ = block_on(request).unwrap(); - // TODO: either await "initialized" or buffer commands until event is received + let stopped = block_on(debugger.listen_for_event("stopped".to_owned())); + let debugger = Arc::new(Mutex::new(debugger)); + tokio::spawn(dap_listen_stopped(stopped, Arc::clone(&debugger))); + // TODO: either await "initialized" or buffer commands until event is received cx.editor.debugger = Some(debugger); } +async fn dap_listen_stopped( + mut stopped: Receiver, + debugger: Arc>, +) { + loop { + stopped.recv().await; + + let mut dbg = debugger.lock().await; + let main = dbg + .threads() + .await + .ok() + .and_then(|threads| threads.get(0).and_then(|x| Some(x.clone()))); + if let Some(main) = main { + let (a, _) = dbg.stack_trace(main.id).await.unwrap(); + dbg.stack_pointer = a.get(0).and_then(|x| Some(x.clone())); + } + } +} + fn dap_toggle_breakpoint(cx: &mut Context) { use helix_lsp::block_on; @@ -4297,6 +4321,7 @@ fn dap_toggle_breakpoint(cx: &mut Context) { // we shouldn't really allow editing while debug is running though if let Some(debugger) = &mut cx.editor.debugger { + let mut debugger = block_on(debugger.lock()); let breakpoints = debugger.breakpoints.entry(path.clone()).or_default(); if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) { breakpoints.remove(pos); @@ -4315,6 +4340,7 @@ fn dap_run(cx: &mut Context) { use helix_lsp::block_on; if let Some(debugger) = &mut cx.editor.debugger { + let mut debugger = block_on(debugger.lock()); let request = debugger.configuration_done(); let _ = block_on(request).unwrap(); } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 20f6fdc78..d48fc0615 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -15,6 +15,7 @@ use helix_core::{ unicode::width::UnicodeWidthStr, LineEnding, Position, Range, Selection, }; +use helix_dap::{SourceBreakpoint, StackFrame}; use helix_view::{ document::Mode, editor::LineNumber, @@ -24,7 +25,8 @@ use helix_view::{ keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::borrow::Cow; +use std::{borrow::Cow, sync::Arc}; +use tokio::sync::Mutex; use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind}; use tui::buffer::Buffer as Surface; @@ -71,7 +73,7 @@ impl EditorView { is_focused: bool, loader: &syntax::Loader, config: &helix_view::editor::Config, - debugger: Option<&helix_dap::Client>, + debugger: Option>>, ) { let inner = view.inner_area(); let area = view.area; @@ -412,8 +414,9 @@ impl EditorView { theme: &Theme, is_focused: bool, config: &helix_view::editor::Config, - debugger: Option<&helix_dap::Client>, + debugger: Option>>, ) { + use helix_lsp::block_on; let text = doc.text().slice(..); let last_line = view.last_line(doc); @@ -442,9 +445,15 @@ impl EditorView { .map(|range| range.cursor_line(text)) .collect(); - let breakpoints = doc - .path() - .and_then(|path| debugger.and_then(|debugger| debugger.breakpoints.get(path))); + let mut breakpoints: Option> = None; + let mut stack_pointer: Option = None; + if let Some(debugger) = debugger { + if let Some(path) = doc.path() { + let dbg = block_on(debugger.lock()); + breakpoints = dbg.breakpoints.get(path).and_then(|bps| Some(bps.clone())); + stack_pointer = dbg.stack_pointer.clone() + } + } for (i, line) in (view.offset.row..(last_line + 1)).enumerate() { use helix_core::diagnostic::Severity; @@ -465,12 +474,23 @@ impl EditorView { let selected = cursors.contains(&line); - if let Some(_breakpoint) = breakpoints.and_then(|breakpoints| { - breakpoints - .iter() - .find(|breakpoint| breakpoint.line == line) - }) { - surface.set_stringn(viewport.x, viewport.y + i as u16, "▲", 1, warning); + if let Some(bps) = breakpoints.as_ref() { + if let Some(_) = bps.iter().find(|breakpoint| breakpoint.line == line) { + surface.set_stringn(viewport.x, viewport.y + i as u16, "▲", 1, warning); + } + } + + if let Some(sp) = stack_pointer.as_ref() { + if let Some(src) = sp.source.as_ref() { + if doc + .path() + .and_then(|path| Some(src.path == Some(path.clone()))) + .unwrap_or(false) + && sp.line == line + { + surface.set_stringn(viewport.x, viewport.y + i as u16, "⇒", 1, warning); + } + } } let text = if line == last_line && !draw_last { @@ -1023,7 +1043,10 @@ impl Component for EditorView { for (view, is_focused) in cx.editor.tree.views() { let doc = cx.editor.document(view.doc).unwrap(); let loader = &cx.editor.syn_loader; - let debugger = cx.editor.debugger.as_ref(); + let mut dbg: Option>> = None; + if let Some(debugger) = &cx.editor.debugger { + dbg = Some(Arc::clone(&debugger)); + } self.render_view( doc, view, @@ -1033,7 +1056,7 @@ impl Component for EditorView { is_focused, loader, &cx.editor.config, - debugger, + dbg, ); } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1fae59be3..2309379af 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -8,6 +8,7 @@ use crate::{ use futures_util::future; use futures_util::stream::select_all::SelectAll; +use tokio::sync::Mutex; use tokio_stream::wrappers::UnboundedReceiverStream; use std::{ @@ -74,7 +75,7 @@ pub struct Editor { pub theme: Theme, pub language_servers: helix_lsp::Registry, - pub debugger: Option, + pub debugger: Option>>, pub debuggers: SelectAll>, pub clipboard_provider: Box,