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