javascript.rs

  1use adapters::latest_github_release;
  2use gpui::AsyncApp;
  3use std::path::PathBuf;
  4use task::{DebugRequestType, DebugTaskDefinition};
  5
  6use crate::*;
  7
  8#[derive(Debug)]
  9pub(crate) struct JsDebugAdapter;
 10
 11impl JsDebugAdapter {
 12    const ADAPTER_NAME: &'static str = "JavaScript";
 13    const ADAPTER_NPM_NAME: &'static str = "vscode-js-debug";
 14    const ADAPTER_PATH: &'static str = "js-debug/src/dapDebugServer.js";
 15}
 16
 17#[async_trait(?Send)]
 18impl DebugAdapter for JsDebugAdapter {
 19    fn name(&self) -> DebugAdapterName {
 20        DebugAdapterName(Self::ADAPTER_NAME.into())
 21    }
 22
 23    async fn fetch_latest_adapter_version(
 24        &self,
 25        delegate: &dyn DapDelegate,
 26    ) -> Result<AdapterVersion> {
 27        let release = latest_github_release(
 28            &format!("{}/{}", "microsoft", Self::ADAPTER_NPM_NAME),
 29            true,
 30            false,
 31            delegate.http_client(),
 32        )
 33        .await?;
 34
 35        let asset_name = format!("js-debug-dap-{}.tar.gz", release.tag_name);
 36
 37        Ok(AdapterVersion {
 38            tag_name: release.tag_name,
 39            url: release
 40                .assets
 41                .iter()
 42                .find(|asset| asset.name == asset_name)
 43                .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?
 44                .browser_download_url
 45                .clone(),
 46        })
 47    }
 48
 49    async fn get_installed_binary(
 50        &self,
 51        delegate: &dyn DapDelegate,
 52        config: &DebugAdapterConfig,
 53        user_installed_path: Option<PathBuf>,
 54        _: &mut AsyncApp,
 55    ) -> Result<DebugAdapterBinary> {
 56        let adapter_path = if let Some(user_installed_path) = user_installed_path {
 57            user_installed_path
 58        } else {
 59            let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref());
 60
 61            let file_name_prefix = format!("{}_", self.name());
 62
 63            util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| {
 64                file_name.starts_with(&file_name_prefix)
 65            })
 66            .await
 67            .ok_or_else(|| anyhow!("Couldn't find JavaScript dap directory"))?
 68        };
 69
 70        let tcp_connection = config.tcp_connection.clone().unwrap_or_default();
 71        let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
 72
 73        Ok(DebugAdapterBinary {
 74            command: delegate
 75                .node_runtime()
 76                .binary_path()
 77                .await?
 78                .to_string_lossy()
 79                .into_owned(),
 80            arguments: Some(vec![
 81                adapter_path.join(Self::ADAPTER_PATH).into(),
 82                port.to_string().into(),
 83                host.to_string().into(),
 84            ]),
 85            cwd: None,
 86            envs: None,
 87            connection: Some(adapters::TcpArguments {
 88                host,
 89                port,
 90                timeout,
 91            }),
 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::GzipTar,
104            delegate,
105        )
106        .await?;
107
108        return Ok(());
109    }
110
111    fn request_args(&self, config: &DebugTaskDefinition) -> Value {
112        let mut args = json!({
113            "type": "pwa-node",
114            "request": match config.request {
115                DebugRequestType::Launch(_) => "launch",
116                DebugRequestType::Attach(_) => "attach",
117            },
118        });
119        let map = args.as_object_mut().unwrap();
120        match &config.request {
121            DebugRequestType::Attach(attach) => {
122                map.insert("processId".into(), attach.process_id.into());
123            }
124            DebugRequestType::Launch(launch) => {
125                map.insert("program".into(), launch.program.clone().into());
126
127                if !launch.args.is_empty() {
128                    map.insert("args".into(), launch.args.clone().into());
129                }
130
131                if let Some(stop_on_entry) = config.stop_on_entry {
132                    map.insert("stopOnEntry".into(), stop_on_entry.into());
133                }
134                if let Some(cwd) = launch.cwd.as_ref() {
135                    map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
136                }
137            }
138        }
139        args
140    }
141}