debugger: Remove fake adapter and un-gate GDB (#27557)

This is a clean-up PR in anticipation of introduction of Debugger
Registry. I wanna get rid of DebugAdapterKind (or rather, it being an
enum).
Release Notes:

- N/A

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
Piotr Osiewicz 2025-03-27 23:31:58 +01:00 committed by GitHub
parent 56eb650f09
commit 4839195003
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 1315 additions and 924 deletions

View file

@ -1,6 +1,6 @@
use dap_types::StartDebuggingRequestArguments;
use schemars::{gen::SchemaSettings, JsonSchema};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::path::PathBuf;
use util::ResultExt;
@ -45,97 +45,121 @@ pub struct AttachConfig {
pub process_id: Option<u32>,
}
/// Represents the launch request information of the debug adapter
#[derive(Deserialize, Serialize, Default, PartialEq, Eq, JsonSchema, Clone, Debug)]
pub struct LaunchConfig {
/// The program that you trying to debug
pub program: String,
/// The current working directory of your project
pub cwd: Option<PathBuf>,
}
/// Represents the type that will determine which request to call on the debug adapter
#[derive(Default, Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(rename_all = "lowercase")]
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(rename_all = "lowercase", untagged)]
pub enum DebugRequestType {
/// Call the `launch` request on the debug adapter
#[default]
Launch,
Launch(LaunchConfig),
/// Call the `attach` request on the debug adapter
Attach(AttachConfig),
}
/// The Debug adapter to use
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(rename_all = "lowercase", tag = "adapter")]
pub enum DebugAdapterKind {
/// Manually setup starting a debug adapter
/// The argument within is used to start the DAP
Custom(CustomArgs),
/// Use debugpy
Python(TCPHost),
/// Use vscode-php-debug
Php(TCPHost),
/// Use vscode-js-debug
Javascript(TCPHost),
/// Use delve
Go(TCPHost),
/// Use lldb
Lldb,
/// Use GDB's built-in DAP support
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Gdb,
/// Used for integration tests
#[cfg(any(test, feature = "test-support"))]
#[serde(skip)]
Fake((bool, dap_types::Capabilities)),
/// Represents a request for starting the debugger.
/// Contrary to `DebugRequestType`, `DebugRequestDisposition` is not Serializable.
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum DebugRequestDisposition {
/// Debug session configured by the user.
UserConfigured(DebugRequestType),
/// Debug session configured by the debug adapter
ReverseRequest(StartDebuggingRequestArguments),
}
impl DebugAdapterKind {
/// Returns the display name for the adapter kind
pub fn display_name(&self) -> &str {
impl DebugRequestDisposition {
/// Get the current working directory from request if it's a launch request and exits
pub fn cwd(&self) -> Option<PathBuf> {
match self {
Self::Custom(_) => "Custom",
Self::Python(_) => "Python",
Self::Php(_) => "PHP",
Self::Javascript(_) => "JavaScript",
Self::Lldb => "LLDB",
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Self::Gdb => "GDB",
Self::Go(_) => "Go",
#[cfg(any(test, feature = "test-support"))]
Self::Fake(_) => "Fake",
Self::UserConfigured(DebugRequestType::Launch(launch_config)) => {
launch_config.cwd.clone()
}
_ => None,
}
}
}
/// Custom arguments used to setup a custom debugger
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
pub struct CustomArgs {
/// The connection that a custom debugger should use
#[serde(flatten)]
pub connection: DebugConnectionType,
/// The cli command used to start the debug adapter e.g. `python3`, `node` or the adapter binary
pub command: String,
/// The cli arguments used to start the debug adapter
pub args: Option<Vec<String>>,
/// The cli envs used to start the debug adapter
pub envs: Option<HashMap<String, String>>,
}
/// Represents the configuration for the debug adapter
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(rename_all = "snake_case")]
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct DebugAdapterConfig {
/// Name of the debug task
pub label: String,
/// The type of adapter you want to use
#[serde(flatten)]
pub kind: DebugAdapterKind,
pub adapter: String,
/// The type of request that should be called on the debug adapter
#[serde(default)]
pub request: DebugRequestType,
/// The program that you trying to debug
pub program: Option<String>,
/// The current working directory of your project
pub cwd: Option<PathBuf>,
pub request: DebugRequestDisposition,
/// Additional initialization arguments to be sent on DAP initialization
pub initialize_args: Option<serde_json::Value>,
/// Whether the debug adapter supports attaching to a running process.
pub supports_attach: bool,
/// Optional TCP connection information
///
/// If provided, this will be used to connect to the debug adapter instead of
/// spawning a new process. This is useful for connecting to a debug adapter
/// that is already running or is started by another process.
pub tcp_connection: Option<TCPHost>,
}
impl From<DebugTaskDefinition> for DebugAdapterConfig {
fn from(def: DebugTaskDefinition) -> Self {
Self {
label: def.label,
adapter: def.adapter,
request: DebugRequestDisposition::UserConfigured(def.request),
initialize_args: def.initialize_args,
tcp_connection: def.tcp_connection,
}
}
}
impl TryFrom<DebugAdapterConfig> for DebugTaskDefinition {
type Error = ();
fn try_from(def: DebugAdapterConfig) -> Result<Self, Self::Error> {
let request = match def.request {
DebugRequestDisposition::UserConfigured(debug_request_type) => debug_request_type,
DebugRequestDisposition::ReverseRequest(_) => return Err(()),
};
Ok(Self {
label: def.label,
adapter: def.adapter,
request,
initialize_args: def.initialize_args,
tcp_connection: def.tcp_connection,
})
}
}
impl DebugTaskDefinition {
/// Translate from debug definition to a task template
pub fn to_zed_format(self) -> anyhow::Result<TaskTemplate> {
let command = "".to_string();
let cwd = if let DebugRequestType::Launch(ref launch) = self.request {
launch
.cwd
.as_ref()
.map(|path| path.to_string_lossy().into_owned())
} else {
None
};
let label = self.label.clone();
let task_type = TaskType::Debug(self);
Ok(TaskTemplate {
label,
command,
args: vec![],
task_type,
cwd,
..Default::default()
})
}
}
/// Represents the type of the debugger adapter connection
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(rename_all = "lowercase", tag = "connection")]
@ -151,48 +175,20 @@ pub enum DebugConnectionType {
#[serde(rename_all = "snake_case")]
pub struct DebugTaskDefinition {
/// The adapter to run
#[serde(flatten)]
kind: DebugAdapterKind,
pub adapter: String,
/// The type of request that should be called on the debug adapter
#[serde(default)]
request: DebugRequestType,
#[serde(flatten)]
pub request: DebugRequestType,
/// Name of the debug task
label: String,
/// Program to run the debugger on
program: Option<String>,
/// The current working directory of your project
cwd: Option<String>,
pub label: String,
/// Additional initialization arguments to be sent on DAP initialization
initialize_args: Option<serde_json::Value>,
}
impl DebugTaskDefinition {
/// Translate from debug definition to a task template
pub fn to_zed_format(self) -> anyhow::Result<TaskTemplate> {
let command = "".to_string();
let cwd = self.cwd.clone().map(PathBuf::from).take_if(|p| p.exists());
let task_type = TaskType::Debug(DebugAdapterConfig {
label: self.label.clone(),
kind: self.kind,
request: self.request,
program: self.program,
cwd: cwd.clone(),
initialize_args: self.initialize_args,
supports_attach: true,
});
let args: Vec<String> = Vec::new();
Ok(TaskTemplate {
label: self.label,
command,
args,
task_type,
cwd: self.cwd,
..Default::default()
})
}
pub initialize_args: Option<serde_json::Value>,
/// Optional TCP connection information
///
/// If provided, this will be used to connect to the debug adapter instead of
/// spawning a new process. This is useful for connecting to a debug adapter
/// that is already running or is started by another process.
pub tcp_connection: Option<TCPHost>,
}
/// A group of Debug Tasks defined in a JSON file.

View file

@ -15,8 +15,8 @@ use std::path::PathBuf;
use std::str::FromStr;
pub use debug_format::{
AttachConfig, CustomArgs, DebugAdapterConfig, DebugAdapterKind, DebugConnectionType,
DebugRequestType, DebugTaskDefinition, DebugTaskFile, TCPHost,
AttachConfig, DebugAdapterConfig, DebugConnectionType, DebugRequestDisposition,
DebugRequestType, DebugTaskDefinition, DebugTaskFile, LaunchConfig, TCPHost,
};
pub use task_template::{
HideStrategy, RevealStrategy, TaskModal, TaskTemplate, TaskTemplates, TaskType,
@ -104,14 +104,20 @@ impl ResolvedTask {
}
/// Get the configuration for the debug adapter that should be used for this task.
pub fn resolved_debug_adapter_config(&self) -> Option<DebugAdapterConfig> {
pub fn resolved_debug_adapter_config(&self) -> Option<DebugTaskDefinition> {
match self.original_task.task_type.clone() {
TaskType::Script => None,
TaskType::Debug(mut adapter_config) => {
if let Some(resolved) = &self.resolved {
adapter_config.label = resolved.label.clone();
adapter_config.program = resolved.program.clone().or(adapter_config.program);
adapter_config.cwd = resolved.cwd.clone().or(adapter_config.cwd);
if let DebugRequestType::Launch(ref mut launch) = adapter_config.request {
if let Some(program) = resolved.program.clone() {
launch.program = program;
}
if let Some(cwd) = resolved.cwd.clone() {
launch.cwd = Some(cwd);
}
}
}
Some(adapter_config)

View file

@ -9,7 +9,7 @@ use sha2::{Digest, Sha256};
use util::{truncate_and_remove_front, ResultExt};
use crate::{
debug_format::DebugAdapterConfig, ResolvedTask, RevealTarget, Shell, SpawnInTerminal,
DebugRequestType, DebugTaskDefinition, ResolvedTask, RevealTarget, Shell, SpawnInTerminal,
TaskContext, TaskId, VariableName, ZED_VARIABLE_NAME_PREFIX,
};
@ -78,18 +78,18 @@ pub struct TaskTemplate {
/// Represents the type of task that is being ran
#[derive(Default, Deserialize, Serialize, Eq, PartialEq, JsonSchema, Clone, Debug)]
#[serde(rename_all = "snake_case", tag = "type")]
#[expect(clippy::large_enum_variant)]
#[allow(clippy::large_enum_variant)]
pub enum TaskType {
/// Act like a typically task that runs commands
#[default]
Script,
/// This task starts the debugger for a language
Debug(DebugAdapterConfig),
Debug(DebugTaskDefinition),
}
#[cfg(test)]
mod deserialization_tests {
use crate::{DebugAdapterKind, TCPHost};
use crate::LaunchConfig;
use super::*;
use serde_json::json;
@ -105,19 +105,20 @@ mod deserialization_tests {
#[test]
fn deserialize_task_type_debug() {
let adapter_config = DebugAdapterConfig {
let adapter_config = DebugTaskDefinition {
label: "test config".into(),
kind: DebugAdapterKind::Python(TCPHost::default()),
request: crate::DebugRequestType::Launch,
program: Some("main".to_string()),
supports_attach: false,
cwd: None,
adapter: "Debugpy".into(),
request: crate::DebugRequestType::Launch(LaunchConfig {
program: "main".to_string(),
cwd: None,
}),
initialize_args: None,
tcp_connection: None,
};
let json = json!({
"label": "test config",
"type": "debug",
"adapter": "python",
"adapter": "Debugpy",
"program": "main",
"supports_attach": false,
});
@ -272,9 +273,9 @@ impl TaskTemplate {
let program = match &self.task_type {
TaskType::Script => None,
TaskType::Debug(adapter_config) => {
if let Some(program) = &adapter_config.program {
if let DebugRequestType::Launch(ref launch) = &adapter_config.request {
Some(substitute_all_template_variables_in_str(
program,
&launch.program,
&task_variables,
&variable_names,
&mut substituted_variables,