php.rs

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