1use anyhow::Result;
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 anyhow::ensure!(
58 output.status.success(),
59 "Failed to install rdbg:\n{}",
60 String::from_utf8_lossy(&output.stderr).to_string()
61 );
62 }
63 }
64 }
65
66 let tcp_connection = definition.tcp_connection.clone().unwrap_or_default();
67 let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
68
69 let DebugRequest::Launch(launch) = definition.request.clone() else {
70 anyhow::bail!("rdbg does not yet support attaching");
71 };
72
73 let mut arguments = vec![
74 "--open".to_string(),
75 format!("--port={}", port),
76 format!("--host={}", host),
77 ];
78 if delegate.which(launch.program.as_ref()).await.is_some() {
79 arguments.push("--command".to_string())
80 }
81 arguments.push(launch.program);
82 arguments.extend(launch.args);
83
84 Ok(DebugAdapterBinary {
85 command: rdbg_path.to_string_lossy().to_string(),
86 arguments,
87 connection: Some(adapters::TcpArguments {
88 host,
89 port,
90 timeout,
91 }),
92 cwd: launch.cwd,
93 envs: launch.env.into_iter().collect(),
94 request_args: StartDebuggingRequestArguments {
95 configuration: serde_json::Value::Object(Default::default()),
96 request: definition.request.to_dap(),
97 },
98 })
99 }
100}