Make dap_start non-blocking

This commit is contained in:
Blaž Hrastnik 2021-12-03 13:27:00 +09:00
parent 032aaffa15
commit 43fbb6d965
3 changed files with 61 additions and 53 deletions

View file

@ -288,16 +288,12 @@ impl Client {
self.request::<requests::Disconnect>(()).await self.request::<requests::Disconnect>(()).await
} }
pub async fn launch(&mut self, args: serde_json::Value) -> Result<Value> { pub fn launch(&self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
let response = self.request::<requests::Launch>(args).await?; self.call::<requests::Launch>(args)
log::error!("launch response {}", response);
Ok(response)
} }
pub async fn attach(&mut self, args: serde_json::Value) -> Result<Value> { pub fn attach(&self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
let response = self.request::<requests::Attach>(args).await?; self.call::<requests::Attach>(args)
log::error!("attach response {}", response);
Ok(response)
} }
pub async fn set_breakpoints( pub async fn set_breakpoints(

View file

@ -2571,8 +2571,7 @@ mod cmd {
0 => None, 0 => None,
_ => Some(args.remove(0)), _ => Some(args.remove(0)),
}; };
dap_start_impl(&mut cx.editor, name, None, Some(args)); dap_start_impl(cx, name, None, Some(args))
Ok(())
} }
fn debug_remote( fn debug_remote(
@ -2589,9 +2588,7 @@ mod cmd {
0 => None, 0 => None,
_ => Some(args.remove(0)), _ => Some(args.remove(0)),
}; };
dap_start_impl(&mut cx.editor, name, address, Some(args)); dap_start_impl(cx, name, address, Some(args))
Ok(())
} }
fn tutor( fn tutor(

View file

@ -1,7 +1,7 @@
use super::{align_view, Align, Context, Editor}; use super::{align_view, Align, Context, Editor};
use crate::{ use crate::{
compositor::Compositor, compositor::{self, Compositor},
job::Callback, job::{Callback, Jobs},
ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent, Text}, ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent, Text},
}; };
use helix_core::{ use helix_core::{
@ -16,8 +16,11 @@ use serde_json::{to_value, Value};
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
use std::collections::HashMap; use std::collections::HashMap;
use std::future::Future;
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::bail;
// general utils: // general utils:
pub fn dap_pos_to_pos(doc: &helix_core::Rope, line: usize, column: usize) -> Option<usize> { pub fn dap_pos_to_pos(doc: &helix_core::Rope, line: usize, column: usize) -> Option<usize> {
// 1-indexing to 0 indexing // 1-indexing to 0 indexing
@ -174,23 +177,39 @@ fn get_breakpoint_at_current_line(editor: &mut Editor) -> Option<(usize, Breakpo
// -- DAP // -- DAP
fn dap_callback<T, F>(
jobs: &mut Jobs,
call: impl Future<Output = helix_dap::Result<serde_json::Value>> + '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( pub fn dap_start_impl(
editor: &mut Editor, cx: &mut compositor::Context,
name: Option<&str>, name: Option<&str>,
socket: Option<std::net::SocketAddr>, socket: Option<std::net::SocketAddr>,
params: Option<Vec<&str>>, params: Option<Vec<&str>>,
) { ) -> Result<(), anyhow::Error> {
let doc = doc!(editor); let doc = doc!(cx.editor);
let config = match doc let config = match doc
.language_config() .language_config()
.and_then(|config| config.debugger.as_ref()) .and_then(|config| config.debugger.as_ref())
{ {
Some(c) => c, Some(c) => c,
None => { None => bail!("No debug adapter available for language"),
editor.set_error("No debug adapter available for language".to_string());
return;
}
}; };
let result = match socket { let result = match socket {
@ -206,16 +225,12 @@ pub fn dap_start_impl(
let (mut debugger, events) = match result { let (mut debugger, events) = match result {
Ok(r) => r, Ok(r) => r,
Err(e) => { Err(e) => bail!("Failed to start debug session: {}", e),
editor.set_error(format!("Failed to start debug session: {}", e));
return;
}
}; };
let request = debugger.initialize(config.name.clone()); let request = debugger.initialize(config.name.clone());
if let Err(e) = block_on(request) { if let Err(e) = block_on(request) {
editor.set_error(format!("Failed to initialize debug adapter: {}", e)); bail!("Failed to initialize debug adapter: {}", e);
return;
} }
debugger.quirks = config.quirks.clone(); debugger.quirks = config.quirks.clone();
@ -227,10 +242,7 @@ pub fn dap_start_impl(
}; };
let template = match template { let template = match template {
Some(template) => template, Some(template) => template,
None => { None => bail!("No debug config with given name"),
editor.set_error("No debug config with given name".to_string());
return;
}
}; };
let mut args: HashMap<&str, Value> = HashMap::new(); let mut args: HashMap<&str, Value> = HashMap::new();
@ -282,28 +294,29 @@ pub fn dap_start_impl(
let args = to_value(args).unwrap(); 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 {
log::error!("pre start"); // editor.set_error(format!("Failed {} target: {}", template.request, e));
let result = match &template.request[..] { // }
"launch" => block_on(debugger.launch(args)), };
"attach" => block_on(debugger.attach(args)),
_ => { match &template.request[..] {
editor.set_error("Unsupported request".to_string()); "launch" => {
return; 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 // 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); let stream = UnboundedReceiverStream::new(events);
editor.debugger_events.push(stream); cx.editor.debugger_events.push(stream);
Ok(())
} }
pub fn dap_launch(cx: &mut Context) { pub fn dap_launch(cx: &mut Context) {
@ -404,12 +417,14 @@ fn debug_parameter_prompt(
}); });
cx.jobs.callback(callback); cx.jobs.callback(callback);
} else { } else {
dap_start_impl( if let Err(e) = dap_start_impl(
cx.editor, cx,
Some(&config_name), Some(&config_name),
None, None,
Some(params.iter().map(|x| x.as_str()).collect()), Some(params.iter().map(|x| x.as_str()).collect()),
); ) {
cx.editor.set_error(e.to_string());
}
} }
}, },
) )