diff --git a/Cargo.lock b/Cargo.lock index 1252c64..6adc67e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -813,9 +813,7 @@ dependencies = [ [[package]] name = "zed_extension_api" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc7f7867316e62864b4f0953e3ce1d05501ba7278cca4e5e5a9694d9182f5c7" +version = "0.6.0" dependencies = [ "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index a953435..d96888c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["cdylib"] [dependencies] regex = "1.11.1" -zed_extension_api = "0.4.0" +zed_extension_api = { path = "../../zed/crates/extension_api" } diff --git a/extension.toml b/extension.toml index 810a379..b00febb 100644 --- a/extension.toml +++ b/extension.toml @@ -5,6 +5,8 @@ version = "0.7.3" schema_version = 1 authors = ["Vitaly Slobodin "] repository = "https://github.com/zed-extensions/ruby" +debug_adapters = ["Ruby"] + [language_servers.solargraph] name = "Solargraph" diff --git a/src/ruby.rs b/src/ruby.rs index 752c287..1b62d1c 100644 --- a/src/ruby.rs +++ b/src/ruby.rs @@ -1,12 +1,20 @@ mod bundler; mod gemset; mod language_servers; + +use std::net::{Ipv4Addr, SocketAddrV4, TcpListener}; +use std::path::Path; + use language_servers::{LanguageServer, Rubocop, RubyLsp, Solargraph}; use zed::lsp::{Completion, Symbol}; use zed::settings::LspSettings; use zed::{serde_json, CodeLabel, LanguageServerId}; -use zed_extension_api::{self as zed, Result}; +use zed::{DebugAdapterBinary, DebugRequest, DebugTaskDefinition}; +use zed_extension_api::{ + self as zed, resolve_tcp_template, Command, Result, StartDebuggingRequestArguments, + StartDebuggingRequestArgumentsRequest, TcpArgumentsTemplate, Worktree, +}; #[derive(Default)] struct RubyExtension { @@ -79,6 +87,79 @@ impl zed::Extension for RubyExtension { Ok(Some(serde_json::json!(initialization_options))) } + fn get_dap_binary( + &mut self, + adapter_name: String, + config: DebugTaskDefinition, + _: Option, + worktree: &Worktree, + ) -> Result { + let mut rdbg_path = Path::new(&adapter_name) + .join("rdbg") + .to_string_lossy() + .into_owned(); + + if worktree.which(&rdbg_path).is_none() { + match worktree.which("rdbg".as_ref()) { + Some(path) => rdbg_path = path.into(), + None => { + let output = Command::new("gem") + .arg("install") + .arg("--no-document") + .arg("--bindir") + .arg(&adapter_name) + .arg("debug") + .output()?; + if !output.status.is_none_or(|status| status != 0) { + return Err(format!( + "Failed to install rdbg:\n{}", + String::from_utf8_lossy(&output.stderr).to_string() + )); + } + } + } + } + + let tcp_connection = + config + .tcp_connection + .clone() + .unwrap_or_else(|| TcpArgumentsTemplate { + port: None, + host: None, + timeout: None, + }); + let connection = resolve_tcp_template(tcp_connection)?; + let DebugRequest::Launch(launch) = config.request.clone() else { + return Err("rdbg does not yet support attaching".to_string()); + }; + + let mut arguments = vec![ + "--open".to_string(), + format!("--port={}", connection.port), + format!("--host={}", connection.host), + ]; + if worktree.which(launch.program.as_ref()).is_some() { + arguments.push("--command".to_string()) + } + arguments.push(launch.program); + arguments.extend(launch.args); + let request = match config.request { + DebugRequest::Launch(_) => StartDebuggingRequestArgumentsRequest::Launch, + DebugRequest::Attach(_) => StartDebuggingRequestArgumentsRequest::Attach, + }; + Ok(DebugAdapterBinary { + command: rdbg_path.to_string(), + arguments, + connection: Some(connection), + cwd: launch.cwd, + envs: launch.envs.into_iter().collect(), + request_args: StartDebuggingRequestArguments { + configuration: serde_json::Value::Object(Default::default()).to_string(), + request, + }, + }) + } } zed::register_extension!(RubyExtension);