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, SharedString};
 10use language::LanguageName;
 11use std::path::PathBuf;
 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: &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()) {
 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()).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}