diff --git a/crates/dap/src/client.rs b/crates/dap/src/client.rs index 85e7d875e1..2f5fa0d0ae 100644 --- a/crates/dap/src/client.rs +++ b/crates/dap/src/client.rs @@ -270,6 +270,17 @@ impl DebugAdapterClient { transport.as_fake().on_request::(handler).await; } + #[cfg(any(test, feature = "test-support"))] + pub async fn fake_reverse_request(&self, args: R::Arguments) { + self.send_message(Message::Request(dap_types::messages::Request { + seq: self.sequence_count.load(Ordering::Relaxed), + command: R::COMMAND.into(), + arguments: serde_json::to_value(args).ok(), + })) + .await + .unwrap(); + } + #[cfg(any(test, feature = "test-support"))] pub async fn fake_event(&self, event: dap_types::messages::Events) { self.send_message(Message::Event(Box::new(event))) @@ -285,10 +296,13 @@ mod tests { adapters::FakeAdapter, client::DebugAdapterClient, debugger_settings::DebuggerSettings, }; use dap_types::{ - messages::Events, requests::Initialize, Capabilities, InitializeRequestArguments, - InitializeRequestArgumentsPathFormat, + messages::Events, + requests::{Initialize, Request, RunInTerminal}, + Capabilities, InitializeRequestArguments, InitializeRequestArgumentsPathFormat, + RunInTerminalRequestArguments, }; use gpui::TestAppContext; + use serde_json::json; use settings::{Settings, SettingsStore}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -430,4 +444,71 @@ mod tests { client.shutdown().await.unwrap(); } + + #[gpui::test] + pub async fn test_calls_event_handler_for_reverse_request(cx: &mut TestAppContext) { + init_test(cx); + + let adapter = Arc::new(FakeAdapter::new()); + let called_event_handler = Arc::new(AtomicBool::new(false)); + + let mut client = DebugAdapterClient::new( + crate::client::DebugAdapterClientId(1), + adapter, + DebugAdapterBinary { + command: "command".into(), + arguments: Default::default(), + envs: Default::default(), + cwd: None, + }, + &mut cx.to_async(), + ); + + client + .start( + { + let called_event_handler = called_event_handler.clone(); + move |event, _| { + called_event_handler.store(true, Ordering::SeqCst); + + assert_eq!( + Message::Request(dap_types::messages::Request { + seq: 1, + command: RunInTerminal::COMMAND.into(), + arguments: Some(json!({ + "cwd": "/project/path/src", + "args": ["node", "test.js"], + })) + }), + event + ); + } + }, + &mut cx.to_async(), + ) + .await + .unwrap(); + + cx.run_until_parked(); + + client + .fake_reverse_request::(RunInTerminalRequestArguments { + kind: None, + title: None, + cwd: "/project/path/src".into(), + args: vec!["node".into(), "test.js".into()], + env: None, + args_can_be_interpreted_by_shell: None, + }) + .await; + + cx.run_until_parked(); + + assert!( + called_event_handler.load(std::sync::atomic::Ordering::SeqCst), + "Event handler was not called" + ); + + client.shutdown().await.unwrap(); + } } diff --git a/crates/dap/src/transport.rs b/crates/dap/src/transport.rs index c062c86995..f54b9115ee 100644 --- a/crates/dap/src/transport.rs +++ b/crates/dap/src/transport.rs @@ -809,6 +809,7 @@ impl Transport for FakeTransport { _binary: &DebugAdapterBinary, cx: &mut AsyncAppContext, ) -> Result { + use dap_types::requests::{Request, RunInTerminal, StartDebugging}; use serde_json::json; let (stdin_writer, stdin_reader) = async_pipe::pipe(); @@ -817,51 +818,69 @@ impl Transport for FakeTransport { let handlers = self.request_handlers.clone(); let stdout_writer = Arc::new(Mutex::new(stdout_writer)); - cx.background_executor().spawn(async move { - let mut reader = BufReader::new(stdin_reader); - let mut buffer = String::new(); + cx.background_executor() + .spawn(async move { + let mut reader = BufReader::new(stdin_reader); + let mut buffer = String::new(); - loop { - let message = TransportDelegate::receive_server_message( - &mut reader, - &mut buffer, - None, - ) - .await; - - match message { - Err(error) => { - break anyhow!(error); - } - Ok(Message::Request(request)) => { - if let Some(handle) = - handlers.lock().await.get_mut(request.command.as_str()) - { - handle( - request.seq, - request.arguments.unwrap_or(json!({})), - stdout_writer.clone(), - ) + loop { + let message = + TransportDelegate::receive_server_message(&mut reader, &mut buffer, None) .await; - } else { - log::debug!("No handler for {}", request.command); + + match message { + Err(error) => { + break anyhow!(error); + } + Ok(message) => { + if let Message::Request(request) = message { + // redirect reverse requests to stdout writer/reader + if request.command == RunInTerminal::COMMAND + || request.command == StartDebugging::COMMAND + { + let message = + serde_json::to_string(&Message::Request(request)).unwrap(); + + let mut writer = stdout_writer.lock().await; + writer + .write_all( + TransportDelegate::build_rpc_message(message) + .as_bytes(), + ) + .await + .unwrap(); + writer.flush().await.unwrap(); + } else { + if let Some(handle) = + handlers.lock().await.get_mut(request.command.as_str()) + { + handle( + request.seq, + request.arguments.unwrap_or(json!({})), + stdout_writer.clone(), + ) + .await; + } else { + log::debug!("No handler for {}", request.command); + } + } + } else if let Message::Event(event) = message { + let message = serde_json::to_string(&Message::Event(event)).unwrap(); + + let mut writer = stdout_writer.lock().await; + writer + .write_all(TransportDelegate::build_rpc_message(message).as_bytes()) + .await + .unwrap(); + writer.flush().await.unwrap(); + } else { + unreachable!("You can only send a request and an event that is redirected to the output reader") + } } } - Ok(Message::Event(event)) => { - let message = serde_json::to_string(&Message::Event(event)).unwrap(); - - let mut writer = stdout_writer.lock().await; - writer - .write_all(TransportDelegate::build_rpc_message(message).as_bytes()) - .await - .unwrap(); - writer.flush().await.unwrap(); - } - _ => unreachable!("You can only send a request and an event that is redirected to the output reader"), } - } - }) - .detach(); + }) + .detach(); Ok(TransportPipe::new( Box::new(stdin_writer),