@@ -1,5 +1,6 @@
1−use super::{Context, Editor};
1+use super::{align_view, Align, Context, Editor};
22use crate::ui::Picker;
3+use helix_core::Selection;
34use helix_dap::Client;
45use helix_lsp::block_on;
56
@@ -8,6 +9,68 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
89
910use std::collections::HashMap;
1011
12+// general utils:
13+pub fn dap_pos_to_pos(doc: &helix_core::Rope, line: usize, column: usize) -> Option<usize> {
14+ // 1-indexing to 0 indexing
15+ let line = doc.try_line_to_char(line - 1).ok()?;
16+ let pos = line + column;
17+ // TODO: this is probably utf-16 offsets
18+ Some(pos)
19+}
20+
21+pub async fn select_thread_id(editor: &mut Editor, thread_id: usize, force: bool) {
22+ let debugger = match &mut editor.debugger {
23+ Some(debugger) => debugger,
24+ None => return,
25+ };
26+
27+ if !force && debugger.thread_id.is_some() {
28+ return;
29+ }
30+
31+ debugger.thread_id = Some(thread_id);
32+
33+ // fetch stack trace
34+ // TODO: handle requesting more total frames
35+ let (frames, _) = debugger.stack_trace(thread_id).await.unwrap();
36+ debugger.stack_frames.insert(thread_id, frames);
37+ debugger.active_frame = Some(0); // TODO: check how to determine this
38+
39+ let frame = debugger.stack_frames[&thread_id].get(0).cloned();
40+ if let Some(frame) = &frame {
41+ jump_to_stack_frame(editor, frame);
42+ }
43+}
44+
45+pub fn jump_to_stack_frame(editor: &mut Editor, frame: &helix_dap::StackFrame) {
46+ let path = if let Some(helix_dap::Source {
47+ path: Some(ref path),
48+ ..
49+ }) = frame.source
50+ {
51+ path.clone()
52+ } else {
53+ return;
54+ };
55+
56+ editor
57+ .open(path, helix_view::editor::Action::Replace)
58+ .unwrap(); // TODO: there should be no unwrapping!
59+
60+ let (view, doc) = current!(editor);
61+
62+ let text_end = doc.text().len_chars().saturating_sub(1);
63+ let start = dap_pos_to_pos(doc.text(), frame.line, frame.column).unwrap_or(0);
64+ let end = frame
65+ .end_line
66+ .and_then(|end_line| dap_pos_to_pos(doc.text(), end_line, frame.end_column.unwrap_or(0)))
67+ .unwrap_or(start);
68+
69+ let selection = Selection::single(start.min(text_end), end.min(text_end));
70+ doc.set_selection(view.id, selection);
71+ align_view(doc, view, Align::Center);
72+}
73+
1174// DAP
1275pub fn dap_start_impl(
1376 editor: &mut Editor,
@@ -222,13 +285,18 @@ pub fn dap_continue(cx: &mut Context) {
222285 return;
223286 }
224287
225− let request = debugger.continue_thread(debugger.thread_id.unwrap());
226− if let Err(e) = block_on(request) {
227− cx.editor.set_error(format!("Failed to continue: {:?}", e));
228− return;
288+ if let Some(thread_id) = debugger.thread_id {
289+ let request = debugger.continue_thread(debugger.thread_id.unwrap());
290+ if let Err(e) = block_on(request) {
291+ cx.editor.set_error(format!("Failed to continue: {:?}", e));
292+ return;
293+ }
294+ debugger.is_running = true;
295+ debugger.stack_frames.remove(&thread_id);
296+ } else {
297+ cx.editor
298+ .set_error("Currently active thread is not stopped. Switch the thread.".into());
229299 }
230− debugger.is_running = true;
231− debugger.stack_pointer = None;
232300 }
233301}
234302
@@ -299,13 +367,16 @@ pub fn dap_variables(cx: &mut Context) {
299367 .set_status("Cannot access variables while target is running".to_owned());
300368 return;
301369 }
302− if debugger.stack_pointer.is_none() {
303− cx.editor
304− .set_status("Cannot find current stack pointer to access variables".to_owned());
305− return;
306− }
370+ let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) {
371+ (Some(frame), Some(thread_id)) => (frame, thread_id),
372+ _ => {
373+ cx.editor
374+ .set_status("Cannot find current stack frame to access variables".to_owned());
375+ return;
376+ }
377+ };
307378
308− let frame_id = debugger.stack_pointer.clone().unwrap().id;
379+ let frame_id = debugger.stack_frames[&thread_id][frame].id;
309380 let scopes = match block_on(debugger.scopes(frame_id)) {
310381 Ok(s) => s,
311382 Err(e) => {
@@ -366,10 +437,7 @@ pub fn dap_switch_thread(cx: &mut Context) {
366437 threads,
367438 |thread| thread.name.clone().into(),
368439 |editor, thread, _action| {
369− if let Some(debugger) = &mut editor.debugger {
370− debugger.thread_id = Some(thread.id);
371− // TODO: probably need to refetch stack frames?
372− }
440+ block_on(select_thread_id(editor, thread.id, true));
373441 },
374442 );
375443 cx.push_layer(Box::new(picker))