dap: Add RunInTerminal reverse request, support replying to requests

This commit is contained in:
Blaž Hrastnik 2021-12-03 16:09:28 +09:00
parent bcf70d8e67
commit 5545f8ebb5
4 changed files with 89 additions and 15 deletions

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
transport::{Payload, Request, Transport}, transport::{Payload, Request, Response, Transport},
types::*, types::*,
Error, Result, ThreadId, Error, Result, ThreadId,
}; };
@ -29,7 +29,7 @@ use tokio::{
pub struct Client { pub struct Client {
id: usize, id: usize,
_process: Option<Child>, _process: Option<Child>,
server_tx: UnboundedSender<Request>, server_tx: UnboundedSender<Payload>,
request_counter: AtomicU64, request_counter: AtomicU64,
pub caps: Option<DebuggerCapabilities>, pub caps: Option<DebuggerCapabilities>,
// thread_id -> frames // thread_id -> frames
@ -234,7 +234,9 @@ impl Client {
arguments, arguments,
}; };
server_tx.send(req).map_err(|e| Error::Other(e.into()))?; server_tx
.send(Payload::Request(req))
.map_err(|e| Error::Other(e.into()))?;
// TODO: specifiable timeout, delay other calls until initialize success // TODO: specifiable timeout, delay other calls until initialize success
timeout(Duration::from_secs(20), callback_rx.recv()) timeout(Duration::from_secs(20), callback_rx.recv())
@ -257,6 +259,40 @@ impl Client {
Ok(response) Ok(response)
} }
pub fn reply(
&self,
request_seq: u64,
command: String,
result: core::result::Result<Value, Error>,
) -> impl Future<Output = Result<()>> {
let server_tx = self.server_tx.clone();
async move {
let response = match result {
Ok(result) => Response {
request_seq,
command,
success: true,
message: None,
body: Some(result),
},
Err(error) => Response {
request_seq,
command,
success: false,
message: Some(error.to_string()),
body: None,
},
};
server_tx
.send(Payload::Response(response))
.map_err(|e| Error::Other(e.into()))?;
Ok(())
}
}
pub fn capabilities(&self) -> &DebuggerCapabilities { pub fn capabilities(&self) -> &DebuggerCapabilities {
self.caps.as_ref().expect("debugger not yet initialized!") self.caps.as_ref().expect("debugger not yet initialized!")
} }

View file

@ -55,7 +55,7 @@ impl Transport {
server_stdin: Box<dyn AsyncWrite + Unpin + Send>, server_stdin: Box<dyn AsyncWrite + Unpin + Send>,
server_stderr: Option<Box<dyn AsyncBufRead + Unpin + Send>>, server_stderr: Option<Box<dyn AsyncBufRead + Unpin + Send>>,
id: usize, id: usize,
) -> (UnboundedReceiver<Payload>, UnboundedSender<Request>) { ) -> (UnboundedReceiver<Payload>, UnboundedSender<Payload>) {
let (client_tx, rx) = unbounded_channel(); let (client_tx, rx) = unbounded_channel();
let (tx, client_rx) = unbounded_channel(); let (tx, client_rx) = unbounded_channel();
@ -140,14 +140,14 @@ impl Transport {
async fn send_payload_to_server( async fn send_payload_to_server(
&self, &self,
server_stdin: &mut Box<dyn AsyncWrite + Unpin + Send>, server_stdin: &mut Box<dyn AsyncWrite + Unpin + Send>,
mut req: Request, mut payload: Payload,
) -> Result<()> { ) -> Result<()> {
let back_ch = req.back_ch.take(); if let Payload::Request(request) = &mut payload {
let seq = req.seq; if let Some(back) = request.back_ch.take() {
let json = serde_json::to_string(&Payload::Request(req))?; self.pending_requests.lock().await.insert(request.seq, back);
if let Some(back) = back_ch { }
self.pending_requests.lock().await.insert(seq, back);
} }
let json = serde_json::to_string(&payload)?;
self.send_string_to_server(server_stdin, json).await self.send_string_to_server(server_stdin, json).await
} }
@ -254,11 +254,11 @@ impl Transport {
async fn send( async fn send(
transport: Arc<Self>, transport: Arc<Self>,
mut server_stdin: Box<dyn AsyncWrite + Unpin + Send>, mut server_stdin: Box<dyn AsyncWrite + Unpin + Send>,
mut client_rx: UnboundedReceiver<Request>, mut client_rx: UnboundedReceiver<Payload>,
) { ) {
while let Some(req) = client_rx.recv().await { while let Some(payload) = client_rx.recv().await {
transport transport
.send_payload_to_server(&mut server_stdin, req) .send_payload_to_server(&mut server_stdin, payload)
.await .await
.unwrap() .unwrap()
} }

View file

@ -1,5 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap;
use std::path::PathBuf; use std::path::PathBuf;
#[derive( #[derive(
@ -541,6 +542,34 @@ pub mod requests {
type Result = SetExceptionBreakpointsResponse; type Result = SetExceptionBreakpointsResponse;
const COMMAND: &'static str = "setExceptionBreakpoints"; const COMMAND: &'static str = "setExceptionBreakpoints";
} }
// Reverse Requests
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RunInTerminalResponse {
pub process_id: Option<usize>,
pub shell_process_id: Option<usize>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RunInTerminalArguments {
pub kind: Option<String>,
pub title: Option<String>,
pub cwd: String,
pub args: Vec<String>,
pub env: Option<HashMap<String, Option<String>>>,
}
#[derive(Debug)]
pub enum RunInTerminal {}
impl Request for RunInTerminal {
type Arguments = RunInTerminalArguments;
type Result = RunInTerminalResponse;
const COMMAND: &'static str = "runInTerminal";
}
} }
// Events // Events

View file

@ -1,5 +1,5 @@
use helix_core::{merge_toml_values, syntax}; use helix_core::{merge_toml_values, syntax};
use helix_dap::Payload; use helix_dap::{self as dap, Payload, Request};
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{editor::Breakpoint, theme, Editor}; use helix_view::{editor::Breakpoint, theme, Editor};
@ -468,7 +468,16 @@ impl Application {
} }
} }
Payload::Response(_) => unreachable!(), Payload::Response(_) => unreachable!(),
Payload::Request(request) => unimplemented!("{:?}", request), Payload::Request(request) => match request.command.as_str() {
dap::requests::RunInTerminal::COMMAND => {
let arguments: dap::requests::RunInTerminalArguments =
serde_json::from_value(request.arguments.unwrap_or_default()).unwrap();
// TODO: no unwrap
// TODO: dap reply
}
_ => log::error!("DAP reverse request not implemented: {:?}", request),
},
} }
self.render(); self.render();
} }