Fix ruby debugger (#32407)
Closes #ISSUE Release Notes: - debugger: Fix Ruby (was broken by #30833) --------- Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Piotr Osiewicz <peterosiewicz@gmail.com> Co-authored-by: Cole Miller <m@cole-miller.net>
This commit is contained in:
parent
b103d7621b
commit
3dfbd9e57c
5 changed files with 116 additions and 174 deletions
|
@ -23,6 +23,7 @@ doctest = false
|
|||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
async-trait.workspace = true
|
||||
collections.workspace = true
|
||||
dap.workspace = true
|
||||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
use anyhow::Result;
|
||||
use anyhow::{Result, bail};
|
||||
use async_trait::async_trait;
|
||||
use collections::FxHashMap;
|
||||
use dap::{
|
||||
DebugRequest, StartDebuggingRequestArguments,
|
||||
DebugRequest, StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
|
||||
adapters::{
|
||||
DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition,
|
||||
},
|
||||
};
|
||||
use gpui::{AsyncApp, SharedString};
|
||||
use language::LanguageName;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::{ffi::OsStr, sync::Arc};
|
||||
use task::{DebugScenario, ZedDebugConfig};
|
||||
use util::command::new_smol_command;
|
||||
|
||||
|
@ -21,6 +23,18 @@ impl RubyDebugAdapter {
|
|||
const ADAPTER_NAME: &'static str = "Ruby";
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct RubyDebugConfig {
|
||||
script_or_command: Option<String>,
|
||||
script: Option<String>,
|
||||
command: Option<String>,
|
||||
#[serde(default)]
|
||||
args: Vec<String>,
|
||||
#[serde(default)]
|
||||
env: FxHashMap<String, String>,
|
||||
cwd: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl DebugAdapter for RubyDebugAdapter {
|
||||
fn name(&self) -> DebugAdapterName {
|
||||
|
@ -31,185 +45,70 @@ impl DebugAdapter for RubyDebugAdapter {
|
|||
Some(SharedString::new_static("Ruby").into())
|
||||
}
|
||||
|
||||
fn request_kind(&self, _: &serde_json::Value) -> Result<StartDebuggingRequestArgumentsRequest> {
|
||||
Ok(StartDebuggingRequestArgumentsRequest::Launch)
|
||||
}
|
||||
|
||||
async fn dap_schema(&self) -> serde_json::Value {
|
||||
json!({
|
||||
"oneOf": [
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["request"],
|
||||
"properties": {
|
||||
"request": {
|
||||
"type": "string",
|
||||
"enum": ["launch"],
|
||||
"description": "Request to launch a new process"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["script"],
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "Command name (ruby, rake, bin/rails, bundle exec ruby, etc)",
|
||||
"default": "ruby"
|
||||
},
|
||||
"script": {
|
||||
"type": "string",
|
||||
"description": "Absolute path to a Ruby file."
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string",
|
||||
"description": "Directory to execute the program in",
|
||||
"default": "${ZED_WORKTREE_ROOT}"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
"description": "Command line arguments passed to the program",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"env": {
|
||||
"type": "object",
|
||||
"description": "Additional environment variables to pass to the debugging (and debugged) process",
|
||||
"default": {}
|
||||
},
|
||||
"showProtocolLog": {
|
||||
"type": "boolean",
|
||||
"description": "Show a log of DAP requests, events, and responses",
|
||||
"default": false
|
||||
},
|
||||
"useBundler": {
|
||||
"type": "boolean",
|
||||
"description": "Execute Ruby programs with `bundle exec` instead of directly",
|
||||
"default": false
|
||||
},
|
||||
"bundlePath": {
|
||||
"type": "string",
|
||||
"description": "Location of the bundle executable"
|
||||
},
|
||||
"rdbgPath": {
|
||||
"type": "string",
|
||||
"description": "Location of the rdbg executable"
|
||||
},
|
||||
"askParameters": {
|
||||
"type": "boolean",
|
||||
"description": "Ask parameters at first."
|
||||
},
|
||||
"debugPort": {
|
||||
"type": "string",
|
||||
"description": "UNIX domain socket name or TPC/IP host:port"
|
||||
},
|
||||
"waitLaunchTime": {
|
||||
"type": "number",
|
||||
"description": "Wait time before connection in milliseconds"
|
||||
},
|
||||
"localfs": {
|
||||
"type": "boolean",
|
||||
"description": "true if the VSCode and debugger run on a same machine",
|
||||
"default": false
|
||||
},
|
||||
"useTerminal": {
|
||||
"type": "boolean",
|
||||
"description": "Create a new terminal and then execute commands there",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "Command name (ruby, rake, bin/rails, bundle exec ruby, etc)",
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["request"],
|
||||
"properties": {
|
||||
"request": {
|
||||
"type": "string",
|
||||
"enum": ["attach"],
|
||||
"description": "Request to attach to an existing process"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"rdbgPath": {
|
||||
"type": "string",
|
||||
"description": "Location of the rdbg executable"
|
||||
},
|
||||
"debugPort": {
|
||||
"type": "string",
|
||||
"description": "UNIX domain socket name or TPC/IP host:port"
|
||||
},
|
||||
"showProtocolLog": {
|
||||
"type": "boolean",
|
||||
"description": "Show a log of DAP requests, events, and responses",
|
||||
"default": false
|
||||
},
|
||||
"localfs": {
|
||||
"type": "boolean",
|
||||
"description": "true if the VSCode and debugger run on a same machine",
|
||||
"default": false
|
||||
},
|
||||
"localfsMap": {
|
||||
"type": "string",
|
||||
"description": "Specify pairs of remote root path and local root path like `/remote_dir:/local_dir`. You can specify multiple pairs like `/rem1:/loc1,/rem2:/loc2` by concatenating with `,`."
|
||||
},
|
||||
"env": {
|
||||
"type": "object",
|
||||
"description": "Additional environment variables to pass to the rdbg process",
|
||||
"default": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"script": {
|
||||
"type": "string",
|
||||
"description": "Absolute path to a Ruby file."
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string",
|
||||
"description": "Directory to execute the program in",
|
||||
"default": "${ZED_WORKTREE_ROOT}"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
"description": "Command line arguments passed to the program",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"env": {
|
||||
"type": "object",
|
||||
"description": "Additional environment variables to pass to the debugging (and debugged) process",
|
||||
"default": {}
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn config_from_zed_format(&self, zed_scenario: ZedDebugConfig) -> Result<DebugScenario> {
|
||||
let mut config = serde_json::Map::new();
|
||||
|
||||
match &zed_scenario.request {
|
||||
match zed_scenario.request {
|
||||
DebugRequest::Launch(launch) => {
|
||||
config.insert("request".to_string(), json!("launch"));
|
||||
config.insert("script".to_string(), json!(launch.program));
|
||||
config.insert("command".to_string(), json!("ruby"));
|
||||
let config = RubyDebugConfig {
|
||||
script_or_command: Some(launch.program),
|
||||
script: None,
|
||||
command: None,
|
||||
args: launch.args,
|
||||
env: launch.env,
|
||||
cwd: launch.cwd.clone(),
|
||||
};
|
||||
|
||||
if !launch.args.is_empty() {
|
||||
config.insert("args".to_string(), json!(launch.args));
|
||||
}
|
||||
let config = serde_json::to_value(config)?;
|
||||
|
||||
if !launch.env.is_empty() {
|
||||
config.insert("env".to_string(), json!(launch.env));
|
||||
}
|
||||
|
||||
if let Some(cwd) = &launch.cwd {
|
||||
config.insert("cwd".to_string(), json!(cwd));
|
||||
}
|
||||
|
||||
// Ruby stops on entry so there's no need to handle that case
|
||||
Ok(DebugScenario {
|
||||
adapter: zed_scenario.adapter,
|
||||
label: zed_scenario.label,
|
||||
config,
|
||||
tcp_connection: None,
|
||||
build: None,
|
||||
})
|
||||
}
|
||||
DebugRequest::Attach(attach) => {
|
||||
config.insert("request".to_string(), json!("attach"));
|
||||
|
||||
config.insert("processId".to_string(), json!(attach.process_id));
|
||||
DebugRequest::Attach(_) => {
|
||||
anyhow::bail!("Attach requests are unsupported");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(DebugScenario {
|
||||
adapter: zed_scenario.adapter,
|
||||
label: zed_scenario.label,
|
||||
config: serde_json::Value::Object(config),
|
||||
tcp_connection: None,
|
||||
build: None,
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
|
@ -247,13 +146,34 @@ impl DebugAdapter for RubyDebugAdapter {
|
|||
|
||||
let tcp_connection = definition.tcp_connection.clone().unwrap_or_default();
|
||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||
let ruby_config = serde_json::from_value::<RubyDebugConfig>(definition.config.clone())?;
|
||||
|
||||
let arguments = vec![
|
||||
let mut arguments = vec![
|
||||
"--open".to_string(),
|
||||
format!("--port={}", port),
|
||||
format!("--host={}", host),
|
||||
];
|
||||
|
||||
if let Some(script) = &ruby_config.script {
|
||||
arguments.push(script.clone());
|
||||
} else if let Some(command) = &ruby_config.command {
|
||||
arguments.push("--command".to_string());
|
||||
arguments.push(command.clone());
|
||||
} else if let Some(command_or_script) = &ruby_config.script_or_command {
|
||||
if delegate
|
||||
.which(OsStr::new(&command_or_script))
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
arguments.push("--command".to_string());
|
||||
}
|
||||
arguments.push(command_or_script.clone());
|
||||
} else {
|
||||
bail!("Ruby debug config must have 'script' or 'command' args");
|
||||
}
|
||||
|
||||
arguments.extend(ruby_config.args);
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
command: rdbg_path.to_string_lossy().to_string(),
|
||||
arguments,
|
||||
|
@ -262,8 +182,12 @@ impl DebugAdapter for RubyDebugAdapter {
|
|||
port,
|
||||
timeout,
|
||||
}),
|
||||
cwd: None,
|
||||
envs: std::collections::HashMap::default(),
|
||||
cwd: Some(
|
||||
ruby_config
|
||||
.cwd
|
||||
.unwrap_or(delegate.worktree_root_path().to_owned()),
|
||||
),
|
||||
envs: ruby_config.env.into_iter().collect(),
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
request: self.request_kind(&definition.config)?,
|
||||
configuration: definition.config.clone(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue