From 43fbb6d965ad5a1a6cd07c0646a0e6b278ff5397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 3 Dec 2021 13:27:00 +0900 Subject: [PATCH] Make dap_start non-blocking --- helix-dap/src/client.rs | 12 ++--- helix-term/src/commands.rs | 7 +-- helix-term/src/commands/dap.rs | 91 ++++++++++++++++++++-------------- 3 files changed, 59 insertions(+), 51 deletions(-) diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index 09b4eaa18..61c05a0b7 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -288,16 +288,12 @@ impl Client { self.request::(()).await } - pub async fn launch(&mut self, args: serde_json::Value) -> Result { - let response = self.request::(args).await?; - log::error!("launch response {}", response); - Ok(response) + pub fn launch(&self, args: serde_json::Value) -> impl Future> { + self.call::(args) } - pub async fn attach(&mut self, args: serde_json::Value) -> Result { - let response = self.request::(args).await?; - log::error!("attach response {}", response); - Ok(response) + pub fn attach(&self, args: serde_json::Value) -> impl Future> { + self.call::(args) } pub async fn set_breakpoints( diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 9a978c4c9..1871c67e1 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2571,8 +2571,7 @@ mod cmd { 0 => None, _ => Some(args.remove(0)), }; - dap_start_impl(&mut cx.editor, name, None, Some(args)); - Ok(()) + dap_start_impl(cx, name, None, Some(args)) } fn debug_remote( @@ -2589,9 +2588,7 @@ mod cmd { 0 => None, _ => Some(args.remove(0)), }; - dap_start_impl(&mut cx.editor, name, address, Some(args)); - - Ok(()) + dap_start_impl(cx, name, address, Some(args)) } fn tutor( diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index f2be3a6c6..66c20cac0 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -1,7 +1,7 @@ use super::{align_view, Align, Context, Editor}; use crate::{ - compositor::Compositor, - job::Callback, + compositor::{self, Compositor}, + job::{Callback, Jobs}, ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent, Text}, }; use helix_core::{ @@ -16,8 +16,11 @@ use serde_json::{to_value, Value}; use tokio_stream::wrappers::UnboundedReceiverStream; use std::collections::HashMap; +use std::future::Future; use std::path::PathBuf; +use anyhow::bail; + // general utils: pub fn dap_pos_to_pos(doc: &helix_core::Rope, line: usize, column: usize) -> Option { // 1-indexing to 0 indexing @@ -174,23 +177,39 @@ fn get_breakpoint_at_current_line(editor: &mut Editor) -> Option<(usize, Breakpo // -- DAP +fn dap_callback( + jobs: &mut Jobs, + call: impl Future> + 'static + Send, + callback: F, +) where + T: for<'de> serde::Deserialize<'de> + Send + 'static, + F: FnOnce(&mut Editor, &mut Compositor, T) + Send + 'static, +{ + let callback = Box::pin(async move { + let json = call.await?; + let response = serde_json::from_value(json)?; + let call: Callback = Box::new(move |editor: &mut Editor, compositor: &mut Compositor| { + callback(editor, compositor, response) + }); + Ok(call) + }); + jobs.callback(callback); +} + pub fn dap_start_impl( - editor: &mut Editor, + cx: &mut compositor::Context, name: Option<&str>, socket: Option, params: Option>, -) { - let doc = doc!(editor); +) -> Result<(), anyhow::Error> { + let doc = doc!(cx.editor); let config = match doc .language_config() .and_then(|config| config.debugger.as_ref()) { Some(c) => c, - None => { - editor.set_error("No debug adapter available for language".to_string()); - return; - } + None => bail!("No debug adapter available for language"), }; let result = match socket { @@ -206,16 +225,12 @@ pub fn dap_start_impl( let (mut debugger, events) = match result { Ok(r) => r, - Err(e) => { - editor.set_error(format!("Failed to start debug session: {}", e)); - return; - } + Err(e) => bail!("Failed to start debug session: {}", e), }; let request = debugger.initialize(config.name.clone()); if let Err(e) = block_on(request) { - editor.set_error(format!("Failed to initialize debug adapter: {}", e)); - return; + bail!("Failed to initialize debug adapter: {}", e); } debugger.quirks = config.quirks.clone(); @@ -227,10 +242,7 @@ pub fn dap_start_impl( }; let template = match template { Some(template) => template, - None => { - editor.set_error("No debug config with given name".to_string()); - return; - } + None => bail!("No debug config with given name"), }; let mut args: HashMap<&str, Value> = HashMap::new(); @@ -282,28 +294,29 @@ pub fn dap_start_impl( let args = to_value(args).unwrap(); - // problem: this blocks for too long while we get back the startInTerminal REQ + let callback = |_editor: &mut Editor, _compositor: &mut Compositor, _response: Value| { + // if let Err(e) = result { + // editor.set_error(format!("Failed {} target: {}", template.request, e)); + // } + }; - log::error!("pre start"); - let result = match &template.request[..] { - "launch" => block_on(debugger.launch(args)), - "attach" => block_on(debugger.attach(args)), - _ => { - editor.set_error("Unsupported request".to_string()); - return; + match &template.request[..] { + "launch" => { + let call = debugger.launch(args); + dap_callback(cx.jobs, call, callback); + } + "attach" => { + let call = debugger.attach(args); + dap_callback(cx.jobs, call, callback); } + request => bail!("Unsupported request '{}'", request), }; - log::error!("post start"); - if let Err(e) = result { - let msg = format!("Failed {} target: {}", template.request, e); - editor.set_error(msg); - return; - } // TODO: either await "initialized" or buffer commands until event is received - editor.debugger = Some(debugger); + cx.editor.debugger = Some(debugger); let stream = UnboundedReceiverStream::new(events); - editor.debugger_events.push(stream); + cx.editor.debugger_events.push(stream); + Ok(()) } pub fn dap_launch(cx: &mut Context) { @@ -404,12 +417,14 @@ fn debug_parameter_prompt( }); cx.jobs.callback(callback); } else { - dap_start_impl( - cx.editor, + if let Err(e) = dap_start_impl( + cx, Some(&config_name), None, Some(params.iter().map(|x| x.as_str()).collect()), - ); + ) { + cx.editor.set_error(e.to_string()); + } } }, )