php.rs

  1use adapters::latest_github_release;
  2use dap::adapters::{DebugTaskDefinition, TcpArguments};
  3use gpui::AsyncApp;
  4use std::{collections::HashMap, path::PathBuf};
  5
  6use crate::*;
  7
  8#[derive(Default)]
  9pub(crate) struct PhpDebugAdapter;
 10
 11impl PhpDebugAdapter {
 12    const ADAPTER_NAME: &'static str = "PHP";
 13    const ADAPTER_PACKAGE_NAME: &'static str = "vscode-php-debug";
 14    const ADAPTER_PATH: &'static str = "extension/out/phpDebug.js";
 15
 16    fn request_args(
 17        &self,
 18        config: &DebugTaskDefinition,
 19    ) -> Result<dap::StartDebuggingRequestArguments> {
 20        match &config.request {
 21            dap::DebugRequest::Attach(_) => {
 22                anyhow::bail!("php adapter does not support attaching")
 23            }
 24            dap::DebugRequest::Launch(launch_config) => Ok(dap::StartDebuggingRequestArguments {
 25                configuration: json!({
 26                    "program": launch_config.program,
 27                    "cwd": launch_config.cwd,
 28                    "args": launch_config.args,
 29                    "stopOnEntry": config.stop_on_entry.unwrap_or_default(),
 30                }),
 31                request: config.request.to_dap(),
 32            }),
 33        }
 34    }
 35}
 36
 37#[async_trait(?Send)]
 38impl DebugAdapter for PhpDebugAdapter {
 39    fn name(&self) -> DebugAdapterName {
 40        DebugAdapterName(Self::ADAPTER_NAME.into())
 41    }
 42
 43    async fn fetch_latest_adapter_version(
 44        &self,
 45        delegate: &dyn DapDelegate,
 46    ) -> Result<AdapterVersion> {
 47        let release = latest_github_release(
 48            &format!("{}/{}", "xdebug", Self::ADAPTER_PACKAGE_NAME),
 49            true,
 50            false,
 51            delegate.http_client(),
 52        )
 53        .await?;
 54
 55        let asset_name = format!("php-debug-{}.vsix", release.tag_name.replace("v", ""));
 56
 57        Ok(AdapterVersion {
 58            tag_name: release.tag_name,
 59            url: release
 60                .assets
 61                .iter()
 62                .find(|asset| asset.name == asset_name)
 63                .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?
 64                .browser_download_url
 65                .clone(),
 66        })
 67    }
 68
 69    async fn get_installed_binary(
 70        &self,
 71        delegate: &dyn DapDelegate,
 72        config: &DebugTaskDefinition,
 73        user_installed_path: Option<PathBuf>,
 74        _: &mut AsyncApp,
 75    ) -> Result<DebugAdapterBinary> {
 76        let adapter_path = if let Some(user_installed_path) = user_installed_path {
 77            user_installed_path
 78        } else {
 79            let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref());
 80
 81            let file_name_prefix = format!("{}_", self.name());
 82
 83            util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| {
 84                file_name.starts_with(&file_name_prefix)
 85            })
 86            .await
 87            .ok_or_else(|| anyhow!("Couldn't find PHP dap directory"))?
 88        };
 89
 90        let tcp_connection = config.tcp_connection.clone().unwrap_or_default();
 91        let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
 92
 93        Ok(DebugAdapterBinary {
 94            command: delegate
 95                .node_runtime()
 96                .binary_path()
 97                .await?
 98                .to_string_lossy()
 99                .into_owned(),
100            arguments: vec![
101                adapter_path
102                    .join(Self::ADAPTER_PATH)
103                    .to_string_lossy()
104                    .to_string(),
105                format!("--server={}", port),
106            ],
107            connection: Some(TcpArguments {
108                port,
109                host,
110                timeout,
111            }),
112            cwd: None,
113            envs: HashMap::default(),
114            request_args: self.request_args(config)?,
115        })
116    }
117
118    async fn install_binary(
119        &self,
120        version: AdapterVersion,
121        delegate: &dyn DapDelegate,
122    ) -> Result<()> {
123        adapters::download_adapter_from_github(
124            self.name(),
125            version,
126            adapters::DownloadedFileType::Vsix,
127            delegate,
128        )
129        .await?;
130
131        Ok(())
132    }
133}