ruby.rs

 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}