From 5b920c53f0b2cb1d6f48ffa46659c65f7fb6fde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 3 Sep 2021 11:10:30 +0900 Subject: [PATCH] Refactor resume_application state handling --- helix-term/src/application.rs | 28 +-- helix-term/src/commands/dap.rs | 323 ++++++++++++++++++--------------- 2 files changed, 187 insertions(+), 164 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index e64389ed..24ebbf60 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -256,7 +256,7 @@ impl Application { } pub async fn handle_debugger_message(&mut self, payload: helix_dap::Payload) { - use crate::commands::dap::select_thread_id; + use crate::commands::dap::{resume_application, select_thread_id}; use helix_dap::{events, Event}; let mut debugger = match self.editor.debugger.as_mut() { Some(debugger) => debugger, @@ -276,22 +276,7 @@ impl Application { debugger.is_running = false; // whichever thread stops is made "current" (if no previously selected thread). - if thread_id.is_none() || all_threads_stopped.unwrap_or_default() { - 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.map(|t| t.id) - }); - if let Some(id) = main { - select_thread_id(&mut self.editor, id, true).await; - } - } else { - select_thread_id(&mut self.editor, thread_id.unwrap(), true).await; - } + select_thread_id(&mut self.editor, thread_id.unwrap(), false).await; let scope = match thread_id { Some(id) => format!("Thread {}", id), @@ -330,10 +315,11 @@ impl Application { self.editor .set_status("Debugged application started".to_owned()); } - Event::Continued(_) => { - debugger.is_running = true; - debugger.active_frame = None; - debugger.thread_id = None; + Event::Continued(events::Continued { thread_id, .. }) => { + // TODO: remove thread from thread-states + if debugger.thread_id == Some(thread_id) { + resume_application(debugger) + } } ev => { log::warn!("Unhandled event {:?}", ev); diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index a1558dde..7efc2c74 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -18,6 +18,12 @@ pub fn dap_pos_to_pos(doc: &helix_core::Rope, line: usize, column: usize) -> Opt Some(pos) } +pub fn resume_application(debugger: &mut Client) { + debugger.is_running = true; // TODO: set state running for debugger.thread_id + debugger.active_frame = None; + debugger.thread_id = None; +} + pub async fn select_thread_id(editor: &mut Editor, thread_id: usize, force: bool) { let debugger = match &mut editor.debugger { Some(debugger) => debugger, @@ -243,203 +249,234 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) { // TODO: need to map breakpoints over edits and update them? // we shouldn't really allow editing while debug is running though - if let Some(debugger) = &mut cx.editor.debugger { - let breakpoints = debugger.breakpoints.entry(path.clone()).or_default(); - if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) { - breakpoints.remove(pos); - } else { - breakpoints.push(breakpoint); - } + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; + + let breakpoints = debugger.breakpoints.entry(path.clone()).or_default(); + if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) { + breakpoints.remove(pos); + } else { + breakpoints.push(breakpoint); + } - let breakpoints = breakpoints.clone(); + let breakpoints = breakpoints.clone(); - let request = debugger.set_breakpoints(path, breakpoints); - if let Err(e) = block_on(request) { - cx.editor - .set_error(format!("Failed to set breakpoints: {:?}", e)); - } + let request = debugger.set_breakpoints(path, breakpoints); + if let Err(e) = block_on(request) { + cx.editor + .set_error(format!("Failed to set breakpoints: {:?}", e)); } } pub fn dap_run(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - if debugger.is_running { - cx.editor - .set_status("Debuggee is already running".to_owned()); - return; - } - let request = debugger.configuration_done(); - if let Err(e) = block_on(request) { - cx.editor.set_error(format!("Failed to run: {:?}", e)); - return; - } - debugger.is_running = true; + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; + + if debugger.is_running { + cx.editor + .set_status("Debuggee is already running".to_owned()); + return; } + let request = debugger.configuration_done(); + if let Err(e) = block_on(request) { + cx.editor.set_error(format!("Failed to run: {:?}", e)); + return; + } + debugger.is_running = true; } pub fn dap_continue(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - if debugger.is_running { - cx.editor - .set_status("Debuggee is already running".to_owned()); - return; - } + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; - if let Some(thread_id) = debugger.thread_id { - 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; - } - debugger.is_running = true; - debugger.stack_frames.remove(&thread_id); - } else { - cx.editor - .set_error("Currently active thread is not stopped. Switch the thread.".into()); + if let Some(thread_id) = debugger.thread_id { + let request = debugger.continue_thread(thread_id); + if let Err(e) = block_on(request) { + cx.editor.set_error(format!("Failed to continue: {:?}", e)); + return; } + resume_application(debugger); + debugger.stack_frames.remove(&thread_id); + } else { + cx.editor + .set_error("Currently active thread is not stopped. Switch the thread.".into()); } } pub fn dap_pause(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - if !debugger.is_running { - cx.editor.set_status("Debuggee is not running".to_owned()); - return; - } + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; - // FIXME: correct number here - let request = debugger.pause(0); - if let Err(e) = block_on(request) { - cx.editor.set_error(format!("Failed to pause: {:?}", e)); - } + if !debugger.is_running { + cx.editor.set_status("Debuggee is not running".to_owned()); + return; + } + + // FIXME: correct number here + let request = debugger.pause(0); + if let Err(e) = block_on(request) { + cx.editor.set_error(format!("Failed to pause: {:?}", e)); } } pub fn dap_step_in(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - if debugger.is_running { - cx.editor - .set_status("Debuggee is already running".to_owned()); - return; - } + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; - let request = debugger.step_in(debugger.thread_id.unwrap()); + if let Some(thread_id) = debugger.thread_id { + let request = debugger.step_in(thread_id); if let Err(e) = block_on(request) { - cx.editor.set_error(format!("Failed to step: {:?}", e)); + cx.editor.set_error(format!("Failed to continue: {:?}", e)); + return; } + resume_application(debugger); + debugger.stack_frames.remove(&thread_id); + } else { + cx.editor + .set_error("Currently active thread is not stopped. Switch the thread.".into()); } } pub fn dap_step_out(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - if debugger.is_running { - cx.editor - .set_status("Debuggee is already running".to_owned()); - return; - } + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; - let request = debugger.step_out(debugger.thread_id.unwrap()); + if let Some(thread_id) = debugger.thread_id { + let request = debugger.step_out(thread_id); if let Err(e) = block_on(request) { - cx.editor.set_error(format!("Failed to step: {:?}", e)); + cx.editor.set_error(format!("Failed to continue: {:?}", e)); + return; } + resume_application(debugger); + debugger.stack_frames.remove(&thread_id); + } else { + cx.editor + .set_error("Currently active thread is not stopped. Switch the thread.".into()); } } pub fn dap_next(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - if debugger.is_running { - cx.editor - .set_status("Debuggee is already running".to_owned()); - return; - } + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; - let request = debugger.next(debugger.thread_id.unwrap()); + if let Some(thread_id) = debugger.thread_id { + let request = debugger.next(thread_id); if let Err(e) = block_on(request) { - cx.editor.set_error(format!("Failed to step: {:?}", e)); + cx.editor.set_error(format!("Failed to continue: {:?}", e)); + return; } + resume_application(debugger); + debugger.stack_frames.remove(&thread_id); + } else { + cx.editor + .set_error("Currently active thread is not stopped. Switch the thread.".into()); } } pub fn dap_variables(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - if debugger.is_running { + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; + + if debugger.is_running { + cx.editor + .set_status("Cannot access variables while target is running".to_owned()); + return; + } + let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) { + (Some(frame), Some(thread_id)) => (frame, thread_id), + _ => { cx.editor - .set_status("Cannot access variables while target is running".to_owned()); + .set_status("Cannot find current stack frame to access variables".to_owned()); return; } - let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) { - (Some(frame), Some(thread_id)) => (frame, thread_id), - _ => { - cx.editor - .set_status("Cannot find current stack frame to access variables".to_owned()); - return; - } - }; - - let frame_id = debugger.stack_frames[&thread_id][frame].id; - let scopes = match block_on(debugger.scopes(frame_id)) { - Ok(s) => s, - Err(e) => { - cx.editor - .set_error(format!("Failed to get scopes: {:?}", e)); - return; - } - }; - let mut variables = Vec::new(); - - for scope in scopes.iter() { - let response = block_on(debugger.variables(scope.variables_reference)); - - if let Ok(vars) = response { - for var in vars { - let prefix = match var.data_type { - Some(data_type) => format!("{} ", data_type), - None => "".to_owned(), - }; - variables.push(format!("{}{} = {}\n", prefix, var.name, var.value)); - } + }; + + let frame_id = debugger.stack_frames[&thread_id][frame].id; + let scopes = match block_on(debugger.scopes(frame_id)) { + Ok(s) => s, + Err(e) => { + cx.editor + .set_error(format!("Failed to get scopes: {:?}", e)); + return; + } + }; + let mut variables = Vec::new(); + + for scope in scopes.iter() { + let response = block_on(debugger.variables(scope.variables_reference)); + + if let Ok(vars) = response { + variables.reserve(vars.len()); + for var in vars { + let prefix = match var.data_type { + Some(data_type) => format!("{} ", data_type), + None => "".to_owned(), + }; + variables.push(format!("{}{} = {}\n", prefix, var.name, var.value)); } } + } - if !variables.is_empty() { - cx.editor.variables = Some(variables); - cx.editor.variables_page = 0; - } + if !variables.is_empty() { + cx.editor.variables = Some(variables); + cx.editor.variables_page = 0; } } pub fn dap_terminate(cx: &mut Context) { - if let Some(debugger) = &mut cx.editor.debugger { - let request = debugger.disconnect(); - if let Err(e) = block_on(request) { - cx.editor - .set_error(format!("Failed to disconnect: {:?}", e)); - return; - } - cx.editor.debugger = None; + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; + + let request = debugger.disconnect(); + if let Err(e) = block_on(request) { + cx.editor + .set_error(format!("Failed to disconnect: {:?}", e)); + return; } + 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| { - block_on(select_thread_id(editor, thread.id, true)); - }, - ); - cx.push_layer(Box::new(picker)) - } + let debugger = match &mut cx.editor.debugger { + Some(debugger) => debugger, + None => return, + }; + + 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| { + block_on(select_thread_id(editor, thread.id, true)); + }, + ); + cx.push_layer(Box::new(picker)) }