debugger: Interpret user-specified debug adapter binary paths in a more intuitive way for JS and Python (#33926)

Cole Miller and Remco Smits created

Previously we would append `js-debug/src/dapDebugServer.js` to the value
of the `dap.JavaScript.binary` setting and `src/debugpy/adapter` to the
value of the `dap.Debugpy.binary` setting, which isn't particularly
intuitive. This PR fixes that.

Release Notes:

- debugger: Made the semantics of the `dap.$ADAPTER.binary` setting more
intuitive for the `JavaScript` and `Debugpy` adapters. In the new
semantics, this should be the path to `dapDebugServer.js` for
`JavaScript` and the path to the `src/debugpy/adapter` directory for
`Debugpy`.

---------

Co-authored-by: Remco Smits <djsmits12@gmail.com>

Change summary

crates/dap_adapters/src/javascript.rs | 42 +++++++++++-----------------
crates/dap_adapters/src/python.rs     | 11 ++-----
2 files changed, 20 insertions(+), 33 deletions(-)

Detailed changes

crates/dap_adapters/src/javascript.rs 🔗

@@ -54,20 +54,6 @@ impl JsDebugAdapter {
         user_args: Option<Vec<String>>,
         _: &mut AsyncApp,
     ) -> Result<DebugAdapterBinary> {
-        let adapter_path = if let Some(user_installed_path) = user_installed_path {
-            user_installed_path
-        } else {
-            let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref());
-
-            let file_name_prefix = format!("{}_", self.name());
-
-            util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| {
-                file_name.starts_with(&file_name_prefix)
-            })
-            .await
-            .context("Couldn't find JavaScript dap directory")?
-        };
-
         let tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default();
         let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
 
@@ -136,21 +122,27 @@ impl JsDebugAdapter {
                 .or_insert(true.into());
         }
 
+        let adapter_path = if let Some(user_installed_path) = user_installed_path {
+            user_installed_path
+        } else {
+            let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref());
+
+            let file_name_prefix = format!("{}_", self.name());
+
+            util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| {
+                file_name.starts_with(&file_name_prefix)
+            })
+            .await
+            .context("Couldn't find JavaScript dap directory")?
+            .join(Self::ADAPTER_PATH)
+        };
+
         let arguments = if let Some(mut args) = user_args {
-            args.insert(
-                0,
-                adapter_path
-                    .join(Self::ADAPTER_PATH)
-                    .to_string_lossy()
-                    .to_string(),
-            );
+            args.insert(0, adapter_path.to_string_lossy().to_string());
             args
         } else {
             vec![
-                adapter_path
-                    .join(Self::ADAPTER_PATH)
-                    .to_string_lossy()
-                    .to_string(),
+                adapter_path.to_string_lossy().to_string(),
                 port.to_string(),
                 host.to_string(),
             ]

crates/dap_adapters/src/python.rs 🔗

@@ -40,12 +40,7 @@ impl PythonDebugAdapter {
                 "Using user-installed debugpy adapter from: {}",
                 user_installed_path.display()
             );
-            vec![
-                user_installed_path
-                    .join(Self::ADAPTER_PATH)
-                    .to_string_lossy()
-                    .to_string(),
-            ]
+            vec![user_installed_path.to_string_lossy().to_string()]
         } else if installed_in_venv {
             log::debug!("Using venv-installed debugpy");
             vec!["-m".to_string(), "debugpy.adapter".to_string()]
@@ -700,7 +695,7 @@ mod tests {
         let port = 5678;
 
         // Case 1: User-defined debugpy path (highest precedence)
-        let user_path = PathBuf::from("/custom/path/to/debugpy");
+        let user_path = PathBuf::from("/custom/path/to/debugpy/src/debugpy/adapter");
         let user_args = PythonDebugAdapter::generate_debugpy_arguments(
             &host,
             port,
@@ -717,7 +712,7 @@ mod tests {
                 .await
                 .unwrap();
 
-        assert!(user_args[0].ends_with("src/debugpy/adapter"));
+        assert_eq!(user_args[0], "/custom/path/to/debugpy/src/debugpy/adapter");
         assert_eq!(user_args[1], "--host=127.0.0.1");
         assert_eq!(user_args[2], "--port=5678");