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(mut 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 launch.args.is_empty() {
 75            let program = launch.program.clone();
 76            let mut split = program.split(" ");
 77            launch.program = split.next().unwrap().to_string();
 78            launch.args = split.map(|s| s.to_string()).collect();
 79        }
 80        if delegate.which(launch.program.as_ref()).is_some() {
 81            arguments.push("--command".to_string())
 82        }
 83        arguments.push(launch.program);
 84        arguments.extend(launch.args);
 85
 86        Ok(DebugAdapterBinary {
 87            command: rdbg_path.to_string_lossy().to_string(),
 88            arguments,
 89            connection: Some(adapters::TcpArguments {
 90                host,
 91                port,
 92                timeout,
 93            }),
 94            cwd: launch.cwd,
 95            envs: launch.env.into_iter().collect(),
 96            request_args: StartDebuggingRequestArguments {
 97                configuration: serde_json::Value::Object(Default::default()),
 98                request: definition.request.to_dap(),
 99            },
100        })
101    }
102}