Skip to content

Commit

Permalink
Implement Attach debugger + picker (#58)
Browse files Browse the repository at this point in the history
* Rename StopDebugAdapters to ShutdownDebugAdapters

* Remove debug config from install methods

* Move requests methods to background executor

* Wip attach with picker

* Move find client to the first line of the method

The client should always be there at this point.

* Fix correctly determine when to restart

While debugging an reverse request issue, the top level client did send terminated event with `restart: false` but we tried to restart the client resulting in the client never being cleaned up by us.

Because before this change we always assumed if we got a json value we are going to restart the client, which is wrong.

We no try to restart the client if:
- restart arg is a boolean and its true
- restart arg is a json value but no boolean

* Clean up response to adapter

* Fix clippy errors

* WIP tasks

* Simplified debug task schema

This changes debug.json to look for adapter: adapter_name instead of
and object when a user selects a debug adatper and fixes the default
behavior of request (to launch)

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

* Make default and flatten work for request

* Rename enum case

* Remove dbg

* Dismiss when candidate is not found

* Add docs for why we update the process id on the config

* Show error when `attach` request is selected but not supported

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
  • Loading branch information
RemcoSmitsDev and Anthony-Eid authored Nov 2, 2024
1 parent 591f6cc commit 65cd774
Show file tree
Hide file tree
Showing 17 changed files with 582 additions and 172 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/dap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ serde_json.workspace = true
settings.workspace = true
smallvec.workspace = true
smol.workspace = true
sysinfo.workspace = true
task.workspace = true
util.workspace = true
24 changes: 20 additions & 4 deletions crates/dap/src/adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
use sysinfo::{Pid, Process};
use task::DebugAdapterConfig;

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -210,7 +211,7 @@ pub trait DebugAdapter: 'static + Send + Sync {
);

let binary = self
.get_installed_binary(delegate, config, Some(adapter_path))
.get_installed_binary(delegate, &config, Some(adapter_path))
.await;

if binary.is_ok() {
Expand Down Expand Up @@ -240,14 +241,14 @@ pub trait DebugAdapter: 'static + Send + Sync {
{
log::info!("Using cached debug adapter binary {}", self.name());

return self.get_installed_binary(delegate, config, None).await;
return self.get_installed_binary(delegate, &config, None).await;
}

log::info!("Getting latest version of debug adapter {}", self.name());
delegate.update_status(self.name(), DapStatus::CheckingForUpdate);
let version = self.fetch_latest_adapter_version(delegate).await.ok();

let mut binary = self.get_installed_binary(delegate, config, None).await;
let mut binary = self.get_installed_binary(delegate, &config, None).await;

if let Some(version) = version {
if binary
Expand All @@ -265,7 +266,8 @@ pub trait DebugAdapter: 'static + Send + Sync {

delegate.update_status(self.name(), DapStatus::Downloading);
self.install_binary(version, delegate).await?;
binary = self.get_installed_binary(delegate, config, None).await;

binary = self.get_installed_binary(delegate, &config, None).await;
} else {
log::error!(
"Failed getting latest version of debug adapter {}",
Expand Down Expand Up @@ -309,4 +311,18 @@ pub trait DebugAdapter: 'static + Send + Sync {

/// Should return base configuration to make the debug adapter work
fn request_args(&self, config: &DebugAdapterConfig) -> Value;

/// Whether the adapter supports `attach` request,
/// if not support and the request is selected we will show an error message
fn supports_attach(&self) -> bool {
false
}

/// Filters out the processes that the adapter can attach to for debugging
fn attach_processes<'a>(
&self,
_: &'a HashMap<Pid, Process>,
) -> Option<Vec<(&'a Pid, &'a Process)>> {
None
}
}
37 changes: 19 additions & 18 deletions crates/dap/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ use crate::{
transport::{IoKind, LogKind, TransportDelegate},
};
use anyhow::{anyhow, Result};

use dap_types::{
messages::{Message, Response},
requests::Request,
};
use gpui::{AppContext, AsyncAppContext};
use serde_json::Value;
use smol::channel::{bounded, Receiver, Sender};
use std::{
hash::Hash,
sync::{
atomic::{AtomicU64, Ordering},
Arc,
Arc, Mutex,
},
};
use task::{DebugAdapterConfig, DebugRequestType};
Expand All @@ -35,27 +33,26 @@ pub struct DebugAdapterClientId(pub usize);

pub struct DebugAdapterClient {
id: DebugAdapterClientId,
adapter_id: String,
request_args: Value,
sequence_count: AtomicU64,
config: DebugAdapterConfig,
adapter: Arc<Box<dyn DebugAdapter>>,
transport_delegate: TransportDelegate,
config: Arc<Mutex<DebugAdapterConfig>>,
}

impl DebugAdapterClient {
pub fn new(
id: DebugAdapterClientId,
request_args: Value,
config: DebugAdapterConfig,
adapter: Arc<Box<dyn DebugAdapter>>,
) -> Self {
let transport_delegate = TransportDelegate::new(adapter.transport());

Self {
id,
config,
request_args,
adapter,
transport_delegate,
sequence_count: AtomicU64::new(1),
adapter_id: adapter.name().to_string(),
transport_delegate: TransportDelegate::new(adapter.transport()),
config: Arc::new(Mutex::new(config)),
}
}

Expand Down Expand Up @@ -141,19 +138,23 @@ impl DebugAdapterClient {
}

pub fn config(&self) -> DebugAdapterConfig {
self.config.clone()
self.config.lock().unwrap().clone()
}

pub fn adapter_id(&self) -> String {
self.adapter_id.clone()
pub fn adapter(&self) -> &Arc<Box<dyn DebugAdapter>> {
&self.adapter
}

pub fn request_args(&self) -> Value {
self.request_args.clone()
pub fn adapter_id(&self) -> String {
self.adapter.name().to_string()
}

pub fn request_type(&self) -> DebugRequestType {
self.config.request.clone()
pub fn set_process_id(&self, process_id: u32) {
let mut config = self.config.lock().unwrap();

config.request = DebugRequestType::Attach(task::AttachConfig {
process_id: Some(process_id),
});
}

/// Get the next sequence id to be used in a request
Expand Down
2 changes: 2 additions & 0 deletions crates/dap_adapters/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ anyhow.workspace = true
async-trait.workspace = true
dap.workspace = true
paths.workspace = true
regex.workspace = true
serde.workspace = true
serde_json.workspace = true
sysinfo.workspace = true
task.workspace = true
util.workspace = true
6 changes: 3 additions & 3 deletions crates/dap_adapters/src/dap_adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ use serde_json::{json, Value};
use std::path::PathBuf;
use task::{CustomArgs, DebugAdapterConfig, DebugAdapterKind, DebugConnectionType, TCPHost};

pub async fn build_adapter(adapter_config: &DebugAdapterConfig) -> Result<Box<dyn DebugAdapter>> {
match &adapter_config.kind {
pub async fn build_adapter(kind: &DebugAdapterKind) -> Result<Box<dyn DebugAdapter>> {
match &kind {
DebugAdapterKind::Custom(start_args) => {
Ok(Box::new(CustomDebugAdapter::new(start_args.clone()).await?))
}
DebugAdapterKind::Python(host) => Ok(Box::new(PythonDebugAdapter::new(host).await?)),
DebugAdapterKind::PHP(host) => Ok(Box::new(PhpDebugAdapter::new(host.clone()).await?)),
DebugAdapterKind::Php(host) => Ok(Box::new(PhpDebugAdapter::new(host.clone()).await?)),
DebugAdapterKind::Javascript(host) => {
Ok(Box::new(JsDebugAdapter::new(host.clone()).await?))
}
Expand Down
34 changes: 33 additions & 1 deletion crates/dap_adapters/src/javascript.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use dap::transport::{TcpTransport, Transport};
use std::net::Ipv4Addr;
use regex::Regex;
use std::{collections::HashMap, net::Ipv4Addr};
use sysinfo::{Pid, Process};
use task::DebugRequestType;
use util::maybe;

use crate::*;
Expand Down Expand Up @@ -124,10 +127,39 @@ impl DebugAdapter for JsDebugAdapter {
}

fn request_args(&self, config: &DebugAdapterConfig) -> Value {
let pid = if let DebugRequestType::Attach(attach_config) = &config.request {
attach_config.process_id
} else {
None
};

json!({
"program": config.program,
"type": "pwa-node",
"request": match config.request {
DebugRequestType::Launch => "launch",
DebugRequestType::Attach(_) => "attach",
},
"processId": pid,
"cwd": config.cwd,
})
}

fn supports_attach(&self) -> bool {
true
}

fn attach_processes<'a>(
&self,
processes: &'a HashMap<Pid, Process>,
) -> Option<Vec<(&'a Pid, &'a Process)>> {
let regex = Regex::new(r"(?i)^(?:node|bun|iojs)(?:$|\b)").unwrap();

Some(
processes
.iter()
.filter(|(_, process)| regex.is_match(&process.name().to_string_lossy()))
.collect::<Vec<_>>(),
)
}
}
1 change: 0 additions & 1 deletion crates/dap_adapters/src/lldb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ impl DebugAdapter for LldbDebugAdapter {
async fn get_binary(
&self,
_: &dyn DapDelegate,
_: &DebugAdapterConfig,
_: Option<PathBuf>,
) -> Result<DebugAdapterBinary> {
Err(anyhow::anyhow!(
Expand Down
4 changes: 3 additions & 1 deletion crates/debugger_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ workspace = true

[dependencies]
anyhow.workspace = true
command_palette_hooks.workspace = true
collections.workspace = true
command_palette_hooks.workspace = true
dap.workspace = true
editor.workspace = true
futures.workspace = true
Expand All @@ -20,10 +20,12 @@ gpui.workspace = true
language.workspace = true
menu.workspace = true
parking_lot.workspace = true
picker.workspace = true
project.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
sysinfo.workspace = true
task.workspace = true
tasks_ui.workspace = true
terminal_view.workspace = true
Expand Down
Loading

0 comments on commit 65cd774

Please sign in to comment.