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