From 4693f1675903d5c4b820aace164f61bbb3c9090f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Jul 2025 01:36:32 +0200 Subject: [PATCH] debugger: Remove PHP debug adapter (#34020) This commit removes the PHP debug adapter in favor of a new version (0.3.0) of PHP extension. The name of a debug adapter has been changed from "PHP" to "Xdebug", which makes this a breaking change in user-configured scenarios Release Notes: - debugger: PHP debug adapter is no longer shipped in core Zed editor; it is now available in PHP extension (starting with version 0.3.0). The adapter has been renamed from `PHP` to `Xdebug`, which might break your user-defined debug scenarios. --- assets/settings/initial_debug_tasks.json | 7 - crates/dap_adapters/src/dap_adapters.rs | 3 - crates/dap_adapters/src/php.rs | 368 ------------------ .../src/tests/new_process_modal.rs | 1 - crates/task/src/vscode_debug_format.rs | 2 +- 5 files changed, 1 insertion(+), 380 deletions(-) delete mode 100644 crates/dap_adapters/src/php.rs diff --git a/assets/settings/initial_debug_tasks.json b/assets/settings/initial_debug_tasks.json index 75e42b2d1b..78fc1fc5f0 100644 --- a/assets/settings/initial_debug_tasks.json +++ b/assets/settings/initial_debug_tasks.json @@ -3,13 +3,6 @@ // For more documentation on how to configure debug tasks, // see: https://zed.dev/docs/debugger [ - { - "label": "Debug active PHP file", - "adapter": "PHP", - "program": "$ZED_FILE", - "request": "launch", - "cwd": "$ZED_WORKTREE_ROOT" - }, { "label": "Debug active Python file", "adapter": "Debugpy", diff --git a/crates/dap_adapters/src/dap_adapters.rs b/crates/dap_adapters/src/dap_adapters.rs index c254302e71..a147861f8d 100644 --- a/crates/dap_adapters/src/dap_adapters.rs +++ b/crates/dap_adapters/src/dap_adapters.rs @@ -2,7 +2,6 @@ mod codelldb; mod gdb; mod go; mod javascript; -mod php; mod python; use std::sync::Arc; @@ -22,7 +21,6 @@ use gdb::GdbDebugAdapter; use go::GoDebugAdapter; use gpui::{App, BorrowAppContext}; use javascript::JsDebugAdapter; -use php::PhpDebugAdapter; use python::PythonDebugAdapter; use serde_json::json; use task::{DebugScenario, ZedDebugConfig}; @@ -31,7 +29,6 @@ pub fn init(cx: &mut App) { cx.update_default_global(|registry: &mut DapRegistry, _cx| { registry.add_adapter(Arc::from(CodeLldbDebugAdapter::default())); registry.add_adapter(Arc::from(PythonDebugAdapter::default())); - registry.add_adapter(Arc::from(PhpDebugAdapter::default())); registry.add_adapter(Arc::from(JsDebugAdapter::default())); registry.add_adapter(Arc::from(GoDebugAdapter::default())); registry.add_adapter(Arc::from(GdbDebugAdapter)); diff --git a/crates/dap_adapters/src/php.rs b/crates/dap_adapters/src/php.rs deleted file mode 100644 index 7d7dee00c9..0000000000 --- a/crates/dap_adapters/src/php.rs +++ /dev/null @@ -1,368 +0,0 @@ -use adapters::latest_github_release; -use anyhow::Context as _; -use anyhow::bail; -use dap::StartDebuggingRequestArguments; -use dap::StartDebuggingRequestArgumentsRequest; -use dap::adapters::{DebugTaskDefinition, TcpArguments}; -use gpui::{AsyncApp, SharedString}; -use language::LanguageName; -use std::{collections::HashMap, path::PathBuf, sync::OnceLock}; -use util::ResultExt; - -use crate::*; - -#[derive(Default)] -pub(crate) struct PhpDebugAdapter { - checked: OnceLock<()>, -} - -impl PhpDebugAdapter { - const ADAPTER_NAME: &'static str = "PHP"; - const ADAPTER_PACKAGE_NAME: &'static str = "vscode-php-debug"; - const ADAPTER_PATH: &'static str = "extension/out/phpDebug.js"; - - async fn fetch_latest_adapter_version( - &self, - delegate: &Arc, - ) -> Result { - let release = latest_github_release( - &format!("{}/{}", "xdebug", Self::ADAPTER_PACKAGE_NAME), - true, - false, - delegate.http_client(), - ) - .await?; - - let asset_name = format!("php-debug-{}.vsix", release.tag_name.replace("v", "")); - - Ok(AdapterVersion { - tag_name: release.tag_name, - url: release - .assets - .iter() - .find(|asset| asset.name == asset_name) - .with_context(|| format!("no asset found matching {asset_name:?}"))? - .browser_download_url - .clone(), - }) - } - - async fn get_installed_binary( - &self, - delegate: &Arc, - task_definition: &DebugTaskDefinition, - user_installed_path: Option, - user_args: Option>, - _: &mut AsyncApp, - ) -> Result { - let adapter_path = if let Some(user_installed_path) = user_installed_path { - user_installed_path - } else { - let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref()); - - let file_name_prefix = format!("{}_", self.name()); - - util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| { - file_name.starts_with(&file_name_prefix) - }) - .await - .context("Couldn't find PHP dap directory")? - }; - - let tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default(); - let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; - - let mut configuration = task_definition.config.clone(); - if let Some(obj) = configuration.as_object_mut() { - obj.entry("cwd") - .or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into()); - } - - let arguments = if let Some(mut args) = user_args { - args.insert( - 0, - adapter_path - .join(Self::ADAPTER_PATH) - .to_string_lossy() - .to_string(), - ); - args - } else { - vec![ - adapter_path - .join(Self::ADAPTER_PATH) - .to_string_lossy() - .to_string(), - format!("--server={}", port), - ] - }; - - Ok(DebugAdapterBinary { - command: Some( - delegate - .node_runtime() - .binary_path() - .await? - .to_string_lossy() - .into_owned(), - ), - arguments, - connection: Some(TcpArguments { - port, - host, - timeout, - }), - cwd: Some(delegate.worktree_root_path().to_path_buf()), - envs: HashMap::default(), - request_args: StartDebuggingRequestArguments { - configuration, - request: ::request_kind(self, &task_definition.config) - .await?, - }, - }) - } -} - -#[async_trait(?Send)] -impl DebugAdapter for PhpDebugAdapter { - fn dap_schema(&self) -> serde_json::Value { - json!({ - "properties": { - "request": { - "type": "string", - "enum": ["launch"], - "description": "The request type for the PHP debug adapter, always \"launch\"", - "default": "launch" - }, - "hostname": { - "type": "string", - "description": "The address to bind to when listening for Xdebug (default: all IPv6 connections if available, else all IPv4 connections) or Unix Domain socket (prefix with unix://) or Windows Pipe (\\\\?\\pipe\\name) - cannot be combined with port" - }, - "port": { - "type": "integer", - "description": "The port on which to listen for Xdebug (default: 9003). If port is set to 0 a random port is chosen by the system and a placeholder ${port} is replaced with the chosen port in env and runtimeArgs.", - "default": 9003 - }, - "program": { - "type": "string", - "description": "The PHP script to debug (typically a path to a file)", - "default": "${file}" - }, - "cwd": { - "type": "string", - "description": "Working directory for the debugged program" - }, - "args": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Command line arguments to pass to the program" - }, - "env": { - "type": "object", - "description": "Environment variables to pass to the program", - "additionalProperties": { - "type": "string" - } - }, - "stopOnEntry": { - "type": "boolean", - "description": "Whether to break at the beginning of the script", - "default": false - }, - "pathMappings": { - "type": "object", - "description": "A mapping of server paths to local paths.", - }, - "log": { - "type": "boolean", - "description": "Whether to log all communication between editor and the adapter to the debug console", - "default": false - }, - "ignore": { - "type": "array", - "description": "An array of glob patterns that errors should be ignored from (for example **/vendor/**/*.php)", - "items": { - "type": "string" - } - }, - "ignoreExceptions": { - "type": "array", - "description": "An array of exception class names that should be ignored (for example BaseException, \\NS1\\Exception, \\*\\Exception or \\**\\Exception*)", - "items": { - "type": "string" - } - }, - "skipFiles": { - "type": "array", - "description": "An array of glob patterns to skip when debugging. Star patterns and negations are allowed.", - "items": { - "type": "string" - } - }, - "skipEntryPaths": { - "type": "array", - "description": "An array of glob patterns to immediately detach from and ignore for debugging if the entry script matches", - "items": { - "type": "string" - } - }, - "maxConnections": { - "type": "integer", - "description": "Accept only this number of parallel debugging sessions. Additional connections will be dropped.", - "default": 1 - }, - "proxy": { - "type": "object", - "description": "DBGp Proxy settings", - "properties": { - "enable": { - "type": "boolean", - "description": "To enable proxy registration", - "default": false - }, - "host": { - "type": "string", - "description": "The address of the proxy. Supports host name, IP address, or Unix domain socket.", - "default": "127.0.0.1" - }, - "port": { - "type": "integer", - "description": "The port where the adapter will register with the proxy", - "default": 9001 - }, - "key": { - "type": "string", - "description": "A unique key that allows the proxy to match requests to your editor", - "default": "vsc" - }, - "timeout": { - "type": "integer", - "description": "The number of milliseconds to wait before giving up on the connection to proxy", - "default": 3000 - }, - "allowMultipleSessions": { - "type": "boolean", - "description": "If the proxy should forward multiple sessions/connections at the same time or not", - "default": true - } - } - }, - "xdebugSettings": { - "type": "object", - "description": "Allows you to override Xdebug's remote debugging settings to fine tune Xdebug to your needs", - "properties": { - "max_children": { - "type": "integer", - "description": "Max number of array or object children to initially retrieve" - }, - "max_data": { - "type": "integer", - "description": "Max amount of variable data to initially retrieve" - }, - "max_depth": { - "type": "integer", - "description": "Maximum depth that the debugger engine may return when sending arrays, hashes or object structures to the IDE" - }, - "show_hidden": { - "type": "integer", - "description": "Whether to show detailed internal information on properties (e.g. private members of classes). Zero means hidden members are not shown.", - "enum": [0, 1] - }, - "breakpoint_include_return_value": { - "type": "boolean", - "description": "Determines whether to enable an additional \"return from function\" debugging step, allowing inspection of the return value when a function call returns" - } - } - }, - "xdebugCloudToken": { - "type": "string", - "description": "Instead of listening locally, open a connection and register with Xdebug Cloud and accept debugging sessions on that connection" - }, - "stream": { - "type": "object", - "description": "Allows to influence DBGp streams. Xdebug only supports stdout", - "properties": { - "stdout": { - "type": "integer", - "description": "Redirect stdout stream: 0 (disable), 1 (copy), 2 (redirect)", - "enum": [0, 1, 2], - "default": 0 - } - } - } - }, - "required": ["request", "program"] - }) - } - - fn name(&self) -> DebugAdapterName { - DebugAdapterName(Self::ADAPTER_NAME.into()) - } - - fn adapter_language_name(&self) -> Option { - Some(SharedString::new_static("PHP").into()) - } - - async fn request_kind( - &self, - _: &serde_json::Value, - ) -> Result { - Ok(StartDebuggingRequestArgumentsRequest::Launch) - } - - async fn config_from_zed_format(&self, zed_scenario: ZedDebugConfig) -> Result { - let obj = match &zed_scenario.request { - dap::DebugRequest::Attach(_) => { - bail!("Php adapter doesn't support attaching") - } - dap::DebugRequest::Launch(launch_config) => json!({ - "program": launch_config.program, - "cwd": launch_config.cwd, - "args": launch_config.args, - "env": launch_config.env_json(), - "stopOnEntry": zed_scenario.stop_on_entry.unwrap_or_default(), - }), - }; - - Ok(DebugScenario { - adapter: zed_scenario.adapter, - label: zed_scenario.label, - build: None, - config: obj, - tcp_connection: None, - }) - } - - async fn get_binary( - &self, - delegate: &Arc, - task_definition: &DebugTaskDefinition, - user_installed_path: Option, - user_args: Option>, - cx: &mut AsyncApp, - ) -> Result { - if self.checked.set(()).is_ok() { - delegate.output_to_console(format!("Checking latest version of {}...", self.name())); - if let Some(version) = self.fetch_latest_adapter_version(delegate).await.log_err() { - adapters::download_adapter_from_github( - self.name(), - version, - adapters::DownloadedFileType::Vsix, - delegate.as_ref(), - ) - .await?; - } - } - - self.get_installed_binary( - delegate, - &task_definition, - user_installed_path, - user_args, - cx, - ) - .await - } -} diff --git a/crates/debugger_ui/src/tests/new_process_modal.rs b/crates/debugger_ui/src/tests/new_process_modal.rs index a4616eaa3b..0805060bf4 100644 --- a/crates/debugger_ui/src/tests/new_process_modal.rs +++ b/crates/debugger_ui/src/tests/new_process_modal.rs @@ -290,7 +290,6 @@ async fn test_dap_adapter_config_conversion_and_validation(cx: &mut TestAppConte let mut expected_adapters = vec![ "CodeLLDB", "Debugpy", - "PHP", "JavaScript", "Delve", "GDB", diff --git a/crates/task/src/vscode_debug_format.rs b/crates/task/src/vscode_debug_format.rs index a74401a2c6..2990716686 100644 --- a/crates/task/src/vscode_debug_format.rs +++ b/crates/task/src/vscode_debug_format.rs @@ -90,7 +90,7 @@ fn task_type_to_adapter_name(task_type: &str) -> String { "pwa-node" | "node" | "node-terminal" | "chrome" | "pwa-chrome" | "edge" | "pwa-edge" | "msedge" | "pwa-msedge" => "JavaScript", "go" => "Delve", - "php" => "PHP", + "php" => "Xdebug", "cppdbg" | "lldb" => "CodeLLDB", "debugpy" => "Debugpy", "rdbg" => "rdbg",