1use anyhow::{Result, anyhow};
2use async_trait::async_trait;
3use dap::{
4 DebugRequest, StartDebuggingRequestArguments,
5 adapters::{
6 self, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition,
7 },
8};
9use gpui::AsyncApp;
10use std::path::PathBuf;
11use util::command::new_smol_command;
12
13use crate::ToDap;
14
15#[derive(Default)]
16pub(crate) struct RubyDebugAdapter;
17
18impl RubyDebugAdapter {
19 const ADAPTER_NAME: &'static str = "Ruby";
20}
21
22#[async_trait(?Send)]
23impl DebugAdapter for RubyDebugAdapter {
24 fn name(&self) -> DebugAdapterName {
25 DebugAdapterName(Self::ADAPTER_NAME.into())
26 }
27
28 async fn get_binary(
29 &self,
30 delegate: &dyn DapDelegate,
31 definition: &DebugTaskDefinition,
32 _user_installed_path: Option<PathBuf>,
33 _cx: &mut AsyncApp,
34 ) -> Result<DebugAdapterBinary> {
35 let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref());
36 let mut rdbg_path = adapter_path.join("rdbg");
37 if !delegate.fs().is_file(&rdbg_path).await {
38 match delegate.which("rdbg".as_ref()) {
39 Some(path) => rdbg_path = path,
40 None => {
41 delegate.output_to_console(
42 "rdbg not found on path, trying `gem install debug`".to_string(),
43 );
44 let output = new_smol_command("gem")
45 .arg("install")
46 .arg("--no-document")
47 .arg("--bindir")
48 .arg(adapter_path)
49 .arg("debug")
50 .output()
51 .await?;
52 if !output.status.success() {
53 return Err(anyhow!(
54 "Failed to install rdbg:\n{}",
55 String::from_utf8_lossy(&output.stderr).to_string()
56 ));
57 }
58 }
59 }
60 }
61
62 let tcp_connection = definition.tcp_connection.clone().unwrap_or_default();
63 let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
64
65 let DebugRequest::Launch(launch) = definition.request.clone() else {
66 anyhow::bail!("rdbg does not yet support attaching");
67 };
68
69 let mut arguments = vec![
70 "--open".to_string(),
71 format!("--port={}", port),
72 format!("--host={}", host),
73 ];
74 if delegate.which(launch.program.as_ref()).is_some() {
75 arguments.push("--command".to_string())
76 }
77 arguments.push(launch.program);
78 arguments.extend(launch.args);
79
80 Ok(DebugAdapterBinary {
81 command: rdbg_path.to_string_lossy().to_string(),
82 arguments,
83 connection: Some(adapters::TcpArguments {
84 host,
85 port,
86 timeout,
87 }),
88 cwd: launch.cwd,
89 envs: launch.env.into_iter().collect(),
90 request_args: StartDebuggingRequestArguments {
91 configuration: serde_json::Value::Object(Default::default()),
92 request: definition.request.to_dap(),
93 },
94 })
95 }
96}