diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index 889ca89fd..b0e43154d 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -31,7 +31,7 @@ pub struct Client { pub breakpoints: HashMap>, // TODO: multiple threads support pub stack_pointer: Option, - pub stopped_thread: Option, + pub thread_id: Option, pub is_running: bool, } @@ -77,7 +77,7 @@ impl Client { // breakpoints: HashMap::new(), stack_pointer: None, - stopped_thread: None, + thread_id: None, is_running: false, }; diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index e4d48f3d6..25ed8a0aa 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1,4 +1,4 @@ -use helix_core::{merge_toml_values, syntax, Range, Selection}; +use helix_core::{merge_toml_values, syntax, Selection}; use helix_dap::Payload; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; use helix_view::{theme, Editor}; @@ -280,19 +280,13 @@ impl Application { .. }) => { debugger.is_running = false; - let main = debugger.threads().await.ok().and_then(|threads| { - // Workaround for debugging Go tests. Main thread has * in beginning of its name - let mut main = threads.iter().find(|t| t.name.starts_with('*')).cloned(); - if main.is_none() { - main = threads.get(0).cloned(); - } - main - }); - if let Some(main) = main { - let (bt, _) = debugger.stack_trace(main.id).await.unwrap(); + // whichever thread stops is made "current". + debugger.thread_id = thread_id; + + if let Some(thread_id) = thread_id { + let (bt, _) = debugger.stack_trace(thread_id).await.unwrap(); debugger.stack_pointer = bt.get(0).cloned(); - debugger.stopped_thread = Some(main.id); } let scope = match thread_id { @@ -379,7 +373,6 @@ impl Application { .set_status("Debugged application started".to_owned()); } Event::Continued(_) => { - debugger.stopped_thread = None; debugger.stack_pointer = None; debugger.is_running = true; } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 03a71fd3e..ffaaac55e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -316,6 +316,7 @@ impl Command { dap_next, "Step to next", dap_variables, "List variables", dap_terminate, "End debug session", + dap_switch_thread, "Switch current thread", suspend, "Suspend" ); } diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index 9509ada1f..66127360b 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -1,4 +1,5 @@ use super::{Context, Editor}; +use crate::ui::Picker; use helix_dap::Client; use helix_lsp::block_on; @@ -221,7 +222,7 @@ pub fn dap_continue(cx: &mut Context) { return; } - let request = debugger.continue_thread(debugger.stopped_thread.unwrap()); + let request = debugger.continue_thread(debugger.thread_id.unwrap()); if let Err(e) = block_on(request) { cx.editor.set_error(format!("Failed to continue: {:?}", e)); return; @@ -254,7 +255,7 @@ pub fn dap_step_in(cx: &mut Context) { return; } - let request = debugger.step_in(debugger.stopped_thread.unwrap()); + let request = debugger.step_in(debugger.thread_id.unwrap()); if let Err(e) = block_on(request) { cx.editor.set_error(format!("Failed to step: {:?}", e)); } @@ -269,7 +270,7 @@ pub fn dap_step_out(cx: &mut Context) { return; } - let request = debugger.step_out(debugger.stopped_thread.unwrap()); + let request = debugger.step_out(debugger.thread_id.unwrap()); if let Err(e) = block_on(request) { cx.editor.set_error(format!("Failed to step: {:?}", e)); } @@ -284,7 +285,7 @@ pub fn dap_next(cx: &mut Context) { return; } - let request = debugger.next(debugger.stopped_thread.unwrap()); + let request = debugger.next(debugger.thread_id.unwrap()); if let Err(e) = block_on(request) { cx.editor.set_error(format!("Failed to step: {:?}", e)); } @@ -347,3 +348,30 @@ pub fn dap_terminate(cx: &mut Context) { cx.editor.debugger = None; } } + +pub fn dap_switch_thread(cx: &mut Context) { + if let Some(debugger) = &mut cx.editor.debugger { + let request = debugger.threads(); + let threads = match block_on(request) { + Ok(threads) => threads, + Err(e) => { + cx.editor + .set_error(format!("Failed to retrieve threads: {:?}", e)); + return; + } + }; + + let picker = Picker::new( + true, + threads, + |thread| thread.name.clone().into(), + |editor, thread, _action| { + if let Some(debugger) = &mut editor.debugger { + debugger.thread_id = Some(thread.id); + // TODO: probably need to refetch stack frames? + } + }, + ); + cx.push_layer(Box::new(picker)) + } +} diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 48ce923ef..5a26529ff 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -486,16 +486,21 @@ impl Default for Keymaps { "a" => code_action, "'" => last_picker, "d" => { "Debug" - "s" => dap_launch, + "l" => dap_launch, "b" => dap_toggle_breakpoint, "r" => dap_run, "c" => dap_continue, "h" => dap_pause, - "j" => dap_step_in, - "k" => dap_step_out, - "l" => dap_next, + "i" => dap_step_in, + "o" => dap_step_out, + "n" => dap_next, "v" => dap_variables, "t" => dap_terminate, + "s" => { "Switch" + "t" => dap_switch_thread, + // f = stack frame + // sl, sb + }, }, "w" => { "Window" "C-w" | "w" => rotate_view,