Detailed changes
@@ -344,6 +344,7 @@ pub trait DebugAdapter: 'static + Send + Sync {
delegate: &Arc<dyn DapDelegate>,
config: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary>;
@@ -434,6 +435,7 @@ impl DebugAdapter for FakeAdapter {
_: &Arc<dyn DapDelegate>,
task_definition: &DebugTaskDefinition,
_: Option<PathBuf>,
+ _: Option<Vec<String>>,
_: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
Ok(DebugAdapterBinary {
@@ -329,6 +329,7 @@ impl DebugAdapter for CodeLldbDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
config: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
_: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
let mut command = user_installed_path
@@ -364,10 +365,12 @@ impl DebugAdapter for CodeLldbDebugAdapter {
Ok(DebugAdapterBinary {
command: Some(command.unwrap()),
cwd: Some(delegate.worktree_root_path().to_path_buf()),
- arguments: vec![
- "--settings".into(),
- json!({"sourceLanguages": ["cpp", "rust"]}).to_string(),
- ],
+ arguments: user_args.unwrap_or_else(|| {
+ vec![
+ "--settings".into(),
+ json!({"sourceLanguages": ["cpp", "rust"]}).to_string(),
+ ]
+ }),
request_args: self.request_args(delegate, &config).await?,
envs: HashMap::default(),
connection: None,
@@ -159,6 +159,7 @@ impl DebugAdapter for GdbDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
config: &DebugTaskDefinition,
user_installed_path: Option<std::path::PathBuf>,
+ user_args: Option<Vec<String>>,
_: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
let user_setting_path = user_installed_path
@@ -186,7 +187,7 @@ impl DebugAdapter for GdbDebugAdapter {
Ok(DebugAdapterBinary {
command: Some(gdb_path),
- arguments: vec!["-i=dap".into()],
+ arguments: user_args.unwrap_or_else(|| vec!["-i=dap".into()]),
envs: HashMap::default(),
cwd: Some(delegate.worktree_root_path().to_path_buf()),
connection: None,
@@ -399,6 +399,7 @@ impl DebugAdapter for GoDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
task_definition: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
_cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
let adapter_path = paths::debug_adapters_dir().join(&Self::ADAPTER_NAME);
@@ -470,7 +471,10 @@ impl DebugAdapter for GoDebugAdapter {
crate::configure_tcp_connection(TcpArgumentsTemplate::default()).await?;
command = Some(minidelve_path.to_string_lossy().into_owned());
connection = None;
- arguments = if cfg!(windows) {
+ arguments = if let Some(mut args) = user_args {
+ args.insert(0, delve_path);
+ args
+ } else if cfg!(windows) {
vec![
delve_path,
"dap".into(),
@@ -50,6 +50,7 @@ impl JsDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
task_definition: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
_: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
let adapter_path = if let Some(user_installed_path) = user_installed_path {
@@ -109,6 +110,26 @@ impl JsDebugAdapter {
.or_insert(true.into());
}
+ let arguments = if let Some(mut args) = user_args {
+ args.insert(
+ 0,
+ adapter_path
+ .join(Self::ADAPTER_PATH)
+ .to_string_lossy()
+ .to_string(),
+ );
+ args
+ } else {
+ vec![
+ adapter_path
+ .join(Self::ADAPTER_PATH)
+ .to_string_lossy()
+ .to_string(),
+ port.to_string(),
+ host.to_string(),
+ ]
+ };
+
Ok(DebugAdapterBinary {
command: Some(
delegate
@@ -118,14 +139,7 @@ impl JsDebugAdapter {
.to_string_lossy()
.into_owned(),
),
- arguments: vec![
- adapter_path
- .join(Self::ADAPTER_PATH)
- .to_string_lossy()
- .to_string(),
- port.to_string(),
- host.to_string(),
- ],
+ arguments,
cwd: Some(delegate.worktree_root_path().to_path_buf()),
envs: HashMap::default(),
connection: Some(adapters::TcpArguments {
@@ -464,6 +478,7 @@ impl DebugAdapter for JsDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
config: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
if self.checked.set(()).is_ok() {
@@ -481,7 +496,7 @@ impl DebugAdapter for JsDebugAdapter {
}
}
- self.get_installed_binary(delegate, &config, user_installed_path, cx)
+ self.get_installed_binary(delegate, &config, user_installed_path, user_args, cx)
.await
}
@@ -52,6 +52,7 @@ impl PhpDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
task_definition: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
_: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
let adapter_path = if let Some(user_installed_path) = user_installed_path {
@@ -77,6 +78,25 @@ impl PhpDebugAdapter {
.or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into());
}
+ let arguments = if let Some(mut args) = user_args {
+ args.insert(
+ 0,
+ adapter_path
+ .join(Self::ADAPTER_PATH)
+ .to_string_lossy()
+ .to_string(),
+ );
+ args
+ } else {
+ vec![
+ adapter_path
+ .join(Self::ADAPTER_PATH)
+ .to_string_lossy()
+ .to_string(),
+ format!("--server={}", port),
+ ]
+ };
+
Ok(DebugAdapterBinary {
command: Some(
delegate
@@ -86,13 +106,7 @@ impl PhpDebugAdapter {
.to_string_lossy()
.into_owned(),
),
- arguments: vec![
- adapter_path
- .join(Self::ADAPTER_PATH)
- .to_string_lossy()
- .to_string(),
- format!("--server={}", port),
- ],
+ arguments,
connection: Some(TcpArguments {
port,
host,
@@ -326,6 +340,7 @@ impl DebugAdapter for PhpDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
task_definition: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
if self.checked.set(()).is_ok() {
@@ -341,7 +356,13 @@ impl DebugAdapter for PhpDebugAdapter {
}
}
- self.get_installed_binary(delegate, &task_definition, user_installed_path, cx)
- .await
+ self.get_installed_binary(
+ delegate,
+ &task_definition,
+ user_installed_path,
+ user_args,
+ cx,
+ )
+ .await
}
}
@@ -32,29 +32,23 @@ impl PythonDebugAdapter {
host: &Ipv4Addr,
port: u16,
user_installed_path: Option<&Path>,
+ user_args: Option<Vec<String>>,
installed_in_venv: bool,
) -> Result<Vec<String>> {
- if let Some(user_installed_path) = user_installed_path {
+ let mut args = if let Some(user_installed_path) = user_installed_path {
log::debug!(
"Using user-installed debugpy adapter from: {}",
user_installed_path.display()
);
- Ok(vec![
+ vec![
user_installed_path
.join(Self::ADAPTER_PATH)
.to_string_lossy()
.to_string(),
- format!("--host={}", host),
- format!("--port={}", port),
- ])
+ ]
} else if installed_in_venv {
log::debug!("Using venv-installed debugpy");
- Ok(vec![
- "-m".to_string(),
- "debugpy.adapter".to_string(),
- format!("--host={}", host),
- format!("--port={}", port),
- ])
+ vec!["-m".to_string(), "debugpy.adapter".to_string()]
} else {
let adapter_path = paths::debug_adapters_dir().join(Self::DEBUG_ADAPTER_NAME.as_ref());
let file_name_prefix = format!("{}_", Self::ADAPTER_NAME);
@@ -70,15 +64,20 @@ impl PythonDebugAdapter {
"Using GitHub-downloaded debugpy adapter from: {}",
debugpy_dir.display()
);
- Ok(vec![
+ vec![
debugpy_dir
.join(Self::ADAPTER_PATH)
.to_string_lossy()
.to_string(),
- format!("--host={}", host),
- format!("--port={}", port),
- ])
- }
+ ]
+ };
+
+ args.extend(if let Some(args) = user_args {
+ args
+ } else {
+ vec![format!("--host={}", host), format!("--port={}", port)]
+ });
+ Ok(args)
}
async fn request_args(
@@ -151,6 +150,7 @@ impl PythonDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
config: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
toolchain: Option<Toolchain>,
installed_in_venv: bool,
) -> Result<DebugAdapterBinary> {
@@ -182,6 +182,7 @@ impl PythonDebugAdapter {
&host,
port,
user_installed_path.as_deref(),
+ user_args,
installed_in_venv,
)
.await?;
@@ -595,6 +596,7 @@ impl DebugAdapter for PythonDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
config: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ user_args: Option<Vec<String>>,
cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
if let Some(local_path) = &user_installed_path {
@@ -603,7 +605,14 @@ impl DebugAdapter for PythonDebugAdapter {
local_path.display()
);
return self
- .get_installed_binary(delegate, &config, Some(local_path.clone()), None, false)
+ .get_installed_binary(
+ delegate,
+ &config,
+ Some(local_path.clone()),
+ user_args,
+ None,
+ false,
+ )
.await;
}
@@ -630,6 +639,7 @@ impl DebugAdapter for PythonDebugAdapter {
delegate,
&config,
None,
+ user_args,
Some(toolchain.clone()),
true,
)
@@ -647,7 +657,7 @@ impl DebugAdapter for PythonDebugAdapter {
}
}
- self.get_installed_binary(delegate, &config, None, toolchain, false)
+ self.get_installed_binary(delegate, &config, None, user_args, toolchain, false)
.await
}
}
@@ -682,15 +692,21 @@ mod tests {
// Case 1: User-defined debugpy path (highest precedence)
let user_path = PathBuf::from("/custom/path/to/debugpy");
- let user_args =
- PythonDebugAdapter::generate_debugpy_arguments(&host, port, Some(&user_path), false)
- .await
- .unwrap();
+ let user_args = PythonDebugAdapter::generate_debugpy_arguments(
+ &host,
+ port,
+ Some(&user_path),
+ None,
+ false,
+ )
+ .await
+ .unwrap();
// Case 2: Venv-installed debugpy (uses -m debugpy.adapter)
- let venv_args = PythonDebugAdapter::generate_debugpy_arguments(&host, port, None, true)
- .await
- .unwrap();
+ let venv_args =
+ PythonDebugAdapter::generate_debugpy_arguments(&host, port, None, None, true)
+ .await
+ .unwrap();
assert!(user_args[0].ends_with("src/debugpy/adapter"));
assert_eq!(user_args[1], "--host=127.0.0.1");
@@ -701,6 +717,33 @@ mod tests {
assert_eq!(venv_args[2], "--host=127.0.0.1");
assert_eq!(venv_args[3], "--port=5678");
+ // The same cases, with arguments overridden by the user
+ let user_args = PythonDebugAdapter::generate_debugpy_arguments(
+ &host,
+ port,
+ Some(&user_path),
+ Some(vec!["foo".into()]),
+ false,
+ )
+ .await
+ .unwrap();
+ let venv_args = PythonDebugAdapter::generate_debugpy_arguments(
+ &host,
+ port,
+ None,
+ Some(vec!["foo".into()]),
+ true,
+ )
+ .await
+ .unwrap();
+
+ assert!(user_args[0].ends_with("src/debugpy/adapter"));
+ assert_eq!(user_args[1], "foo");
+
+ assert_eq!(venv_args[0], "-m");
+ assert_eq!(venv_args[1], "debugpy.adapter");
+ assert_eq!(venv_args[2], "foo");
+
// Note: Case 3 (GitHub-downloaded debugpy) is not tested since this requires mocking the Github API.
}
}
@@ -119,6 +119,7 @@ impl DebugAdapter for RubyDebugAdapter {
delegate: &Arc<dyn DapDelegate>,
definition: &DebugTaskDefinition,
_user_installed_path: Option<PathBuf>,
+ _user_args: Option<Vec<String>>,
_cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref());
@@ -88,6 +88,8 @@ impl DebugAdapter for ExtensionDapAdapter {
delegate: &Arc<dyn DapDelegate>,
config: &DebugTaskDefinition,
user_installed_path: Option<PathBuf>,
+ // TODO support user args in the extension API
+ _user_args: Option<Vec<String>>,
_cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
self.extension
@@ -40,7 +40,7 @@ use rpc::{
AnyProtoClient, TypedEnvelope,
proto::{self},
};
-use settings::{Settings, WorktreeId};
+use settings::{Settings, SettingsLocation, WorktreeId};
use std::{
borrow::Borrow,
collections::BTreeMap,
@@ -190,17 +190,23 @@ impl DapStore {
return Task::ready(Err(anyhow!("Failed to find a debug adapter")));
};
- let user_installed_path = ProjectSettings::get_global(cx)
+ let settings_location = SettingsLocation {
+ worktree_id: worktree.read(cx).id(),
+ path: Path::new(""),
+ };
+ let dap_settings = ProjectSettings::get(Some(settings_location), cx)
.dap
- .get(&adapter.name())
- .and_then(|s| s.binary.as_ref().map(PathBuf::from));
+ .get(&adapter.name());
+ let user_installed_path =
+ dap_settings.and_then(|s| s.binary.as_ref().map(PathBuf::from));
+ let user_args = dap_settings.map(|s| s.args.clone());
let delegate = self.delegate(&worktree, console, cx);
let cwd: Arc<Path> = worktree.read(cx).abs_path().as_ref().into();
cx.spawn(async move |this, cx| {
let mut binary = adapter
- .get_binary(&delegate, &definition, user_installed_path, cx)
+ .get_binary(&delegate, &definition, user_installed_path, user_args, cx)
.await?;
let env = this
@@ -82,6 +82,8 @@ pub struct ProjectSettings {
#[serde(rename_all = "snake_case")]
pub struct DapSettings {
pub binary: Option<String>,
+ #[serde(default)]
+ pub args: Vec<String>,
}
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]