php.rs

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