Merge pull request #115 from zed-industries/remove-dap-session

Remove dap session
This commit is contained in:
Piotr Osiewicz
2025-02-18 02:22:14 +01:00
committed by GitHub
36 changed files with 2334 additions and 4012 deletions

View File

@@ -429,7 +429,6 @@ impl Server {
.add_message_handler( .add_message_handler(
broadcast_project_message_from_host::<proto::RemoveActiveDebugLine>, broadcast_project_message_from_host::<proto::RemoveActiveDebugLine>,
) )
.add_message_handler(broadcast_project_message_from_host::<proto::SetDebuggerPanelItem>)
.add_message_handler(broadcast_project_message_from_host::<proto::UpdateDebugAdapter>) .add_message_handler(broadcast_project_message_from_host::<proto::UpdateDebugAdapter>)
.add_message_handler( .add_message_handler(
broadcast_project_message_from_host::<proto::SetDebugClientCapabilities>, broadcast_project_message_from_host::<proto::SetDebugClientCapabilities>,

View File

@@ -5,7 +5,7 @@ use dap::{
SourceBreakpoint, StackFrame, SourceBreakpoint, StackFrame,
}; };
use debugger_ui::debugger_panel::DebugPanel; use debugger_ui::debugger_panel::DebugPanel;
use debugger_ui::debugger_panel_item::DebugPanelItem; use debugger_ui::session::DebugSession;
use editor::Editor; use editor::Editor;
use gpui::{Entity, TestAppContext, VisualTestContext}; use gpui::{Entity, TestAppContext, VisualTestContext};
use project::{Project, ProjectPath, WorktreeId}; use project::{Project, ProjectPath, WorktreeId};
@@ -52,7 +52,7 @@ async fn add_debugger_panel(workspace: &Entity<Workspace>, cx: &mut VisualTestCo
pub fn active_debug_panel_item( pub fn active_debug_panel_item(
workspace: Entity<Workspace>, workspace: Entity<Workspace>,
cx: &mut VisualTestContext, cx: &mut VisualTestContext,
) -> Entity<DebugPanelItem> { ) -> Entity<DebugSession> {
workspace.update_in(cx, |workspace, _window, cx| { workspace.update_in(cx, |workspace, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel debug_panel
@@ -1251,9 +1251,7 @@ async fn test_module_list(
debug_panel_item.update(cx, |item, cx| { debug_panel_item.update(cx, |item, cx| {
assert_eq!( assert_eq!(
true, true,
item.capabilities(cx) item.capabilities(cx).supports_modules_request.unwrap(),
.and_then(|caps| caps.supports_modules_request)
.unwrap(),
"Local supports modules request should be true" "Local supports modules request should be true"
); );
@@ -1281,9 +1279,7 @@ async fn test_module_list(
debug_panel_item.update(cx, |item, cx| { debug_panel_item.update(cx, |item, cx| {
assert_eq!( assert_eq!(
true, true,
item.capabilities(cx) item.capabilities(cx).supports_modules_request.unwrap(),
.and_then(|caps| caps.supports_modules_request)
.unwrap(),
"Remote capabilities supports modules request should be true" "Remote capabilities supports modules request should be true"
); );
let remote_module_list = item.module_list().update(cx, |list, cx| list.modules(cx)); let remote_module_list = item.module_list().update(cx, |list, cx| list.modules(cx));
@@ -1314,9 +1310,7 @@ async fn test_module_list(
debug_panel_item.update(cx, |item, cx| { debug_panel_item.update(cx, |item, cx| {
assert_eq!( assert_eq!(
true, true,
item.capabilities(cx) item.capabilities(cx).supports_modules_request.unwrap(),
.and_then(|caps| caps.supports_modules_request)
.unwrap(),
"Remote (mid session join) capabilities supports modules request should be true" "Remote (mid session join) capabilities supports modules request should be true"
); );
let remote_module_list = item.module_list().update(cx, |list, cx| list.modules(cx)); let remote_module_list = item.module_list().update(cx, |list, cx| list.modules(cx));

View File

@@ -1,6 +1,5 @@
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
use crate::transport::FakeTransport; use crate::transport::FakeTransport;
use crate::transport::Transport;
use ::fs::Fs; use ::fs::Fs;
use anyhow::{anyhow, Context as _, Ok, Result}; use anyhow::{anyhow, Context as _, Ok, Result};
use async_compression::futures::bufread::GzipDecoder; use async_compression::futures::bufread::GzipDecoder;
@@ -19,9 +18,11 @@ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
ffi::{OsStr, OsString}, ffi::{OsStr, OsString},
fmt::Debug, fmt::Debug,
net::Ipv4Addr,
ops::Deref, ops::Deref,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
time::Duration,
}; };
use sysinfo::{Pid, Process}; use sysinfo::{Pid, Process};
use task::DebugAdapterConfig; use task::DebugAdapterConfig;
@@ -89,12 +90,19 @@ impl<'a> From<&'a str> for DebugAdapterName {
} }
} }
#[derive(Debug, Clone)]
pub struct TcpArguments {
pub host: Ipv4Addr,
pub port: Option<u16>,
pub timeout: Option<u64>,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugAdapterBinary { pub struct DebugAdapterBinary {
pub command: String, pub command: String,
pub arguments: Option<Vec<OsString>>, pub arguments: Option<Vec<OsString>>,
pub envs: Option<HashMap<String, String>>, pub envs: Option<HashMap<String, String>>,
pub cwd: Option<PathBuf>, pub cwd: Option<PathBuf>,
pub connection: Option<TcpArguments>,
} }
pub struct AdapterVersion { pub struct AdapterVersion {
@@ -261,8 +269,6 @@ pub trait DebugAdapter: 'static + Send + Sync {
.await .await
} }
fn transport(&self) -> Arc<dyn Transport>;
async fn fetch_latest_adapter_version( async fn fetch_latest_adapter_version(
&self, &self,
delegate: &dyn DapDelegate, delegate: &dyn DapDelegate,
@@ -288,12 +294,6 @@ pub trait DebugAdapter: 'static + Send + Sync {
/// Should return base configuration to make the debug adapter work /// Should return base configuration to make the debug adapter work
fn request_args(&self, config: &DebugAdapterConfig) -> Value; 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 /// Filters out the processes that the adapter can attach to for debugging
fn attach_processes<'a>( fn attach_processes<'a>(
&self, &self,
@@ -322,10 +322,6 @@ impl DebugAdapter for FakeAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into()) DebugAdapterName(Self::ADAPTER_NAME.into())
} }
fn transport(&self) -> Arc<dyn Transport> {
Arc::new(FakeTransport::new())
}
async fn get_binary( async fn get_binary(
&self, &self,
_: &dyn DapDelegate, _: &dyn DapDelegate,
@@ -336,6 +332,11 @@ impl DebugAdapter for FakeAdapter {
Ok(DebugAdapterBinary { Ok(DebugAdapterBinary {
command: "command".into(), command: "command".into(),
arguments: None, arguments: None,
connection: Some(TcpArguments {
host: Ipv4Addr::LOCALHOST,
port: None,
timeout: None,
}),
envs: None, envs: None,
cwd: None, cwd: None,
}) })
@@ -383,10 +384,6 @@ impl DebugAdapter for FakeAdapter {
}) })
} }
fn supports_attach(&self) -> bool {
true
}
fn attach_processes<'a>( fn attach_processes<'a>(
&self, &self,
processes: &'a HashMap<Pid, Process>, processes: &'a HashMap<Pid, Process>,

View File

@@ -27,9 +27,9 @@ const DAP_REQUEST_TIMEOUT: Duration = Duration::from_secs(12);
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)] #[repr(transparent)]
pub struct DebugAdapterClientId(pub u32); pub struct SessionId(pub u32);
impl DebugAdapterClientId { impl SessionId {
pub fn from_proto(client_id: u64) -> Self { pub fn from_proto(client_id: u64) -> Self {
Self(client_id as u32) Self(client_id as u32)
} }
@@ -41,69 +41,35 @@ impl DebugAdapterClientId {
/// Represents a connection to the debug adapter process, either via stdout/stdin or a socket. /// Represents a connection to the debug adapter process, either via stdout/stdin or a socket.
pub struct DebugAdapterClient { pub struct DebugAdapterClient {
id: DebugAdapterClientId, id: SessionId,
sequence_count: AtomicU64, sequence_count: AtomicU64,
binary: DebugAdapterBinary, binary: DebugAdapterBinary,
executor: BackgroundExecutor, executor: BackgroundExecutor,
adapter: Arc<dyn DebugAdapter>,
transport_delegate: TransportDelegate, transport_delegate: TransportDelegate,
} }
impl DebugAdapterClient { impl DebugAdapterClient {
pub fn new( pub async fn start<F>(
id: DebugAdapterClientId, id: SessionId,
adapter: Arc<dyn DebugAdapter>,
binary: DebugAdapterBinary, binary: DebugAdapterBinary,
cx: &AsyncApp, message_handler: F,
) -> Self { cx: AsyncApp,
let transport_delegate = TransportDelegate::new(adapter.transport()); ) -> Result<Self>
where
Self { F: FnMut(Message, &mut App) + 'static + Send + Sync + Clone,
{
let ((server_rx, server_tx), transport_delegate) =
TransportDelegate::start(&binary, cx.clone()).await?;
let this = Self {
id, id,
binary, binary,
adapter,
transport_delegate, transport_delegate,
sequence_count: AtomicU64::new(1), sequence_count: AtomicU64::new(1),
executor: cx.background_executor().clone(), executor: cx.background_executor().clone(),
} };
}
pub async fn reconnect<F>(&mut self, message_handler: F, cx: &mut AsyncApp) -> Result<()>
where
F: FnMut(Message, &mut App) + 'static + Send + Sync + Clone,
{
let (server_rx, server_tx) = self.transport_delegate.reconnect(cx).await?;
log::info!("Successfully reconnected to debug adapter");
let client_id = self.id;
// start handling events/reverse requests
cx.update(|cx| {
cx.spawn({
let server_tx = server_tx.clone();
|mut cx| async move {
Self::handle_receive_messages(
client_id,
server_rx,
server_tx,
message_handler,
&mut cx,
)
.await
}
})
.detach_and_log_err(cx);
})
}
pub async fn start<F>(&mut self, message_handler: F, cx: &mut AsyncApp) -> Result<()>
where
F: FnMut(Message, &mut App) + 'static + Send + Sync + Clone,
{
let (server_rx, server_tx) = self.transport_delegate.start(&self.binary, cx).await?;
log::info!("Successfully connected to debug adapter"); log::info!("Successfully connected to debug adapter");
let client_id = self.id; let client_id = this.id;
// start handling events/reverse requests // start handling events/reverse requests
cx.update(|cx| { cx.update(|cx| {
@@ -121,11 +87,13 @@ impl DebugAdapterClient {
} }
}) })
.detach_and_log_err(cx); .detach_and_log_err(cx);
this
}) })
} }
async fn handle_receive_messages<F>( async fn handle_receive_messages<F>(
client_id: DebugAdapterClientId, client_id: SessionId,
server_rx: Receiver<Message>, server_rx: Receiver<Message>,
client_tx: Sender<Message>, client_tx: Sender<Message>,
mut event_handler: F, mut event_handler: F,
@@ -225,22 +193,14 @@ impl DebugAdapterClient {
self.transport_delegate.send_message(message).await self.transport_delegate.send_message(message).await
} }
pub fn id(&self) -> DebugAdapterClientId { pub fn id(&self) -> SessionId {
self.id self.id
} }
pub fn adapter(&self) -> &Arc<dyn DebugAdapter> {
&self.adapter
}
pub fn binary(&self) -> &DebugAdapterBinary { pub fn binary(&self) -> &DebugAdapterBinary {
&self.binary &self.binary
} }
pub fn adapter_id(&self) -> String {
self.adapter.name().to_string()
}
/// Get the next sequence id to be used in a request /// Get the next sequence id to be used in a request
pub fn next_sequence_id(&self) -> u64 { pub fn next_sequence_id(&self) -> u64 {
self.sequence_count.fetch_add(1, Ordering::Relaxed) self.sequence_count.fetch_add(1, Ordering::Relaxed)
@@ -335,15 +295,17 @@ mod tests {
pub async fn test_initialize_client(cx: &mut TestAppContext) { pub async fn test_initialize_client(cx: &mut TestAppContext) {
init_test(cx); init_test(cx);
let adapter = Arc::new(FakeAdapter::new());
let mut client = DebugAdapterClient::new( let mut client = DebugAdapterClient::new(
crate::client::DebugAdapterClientId(1), crate::client::SessionId(1),
adapter,
DebugAdapterBinary { DebugAdapterBinary {
command: "command".into(), command: "command".into(),
arguments: Default::default(), arguments: Default::default(),
envs: Default::default(), envs: Default::default(),
connection: Some(TcpArguments {
host: Ipv4Addr::LOCALHOST,
port: None,
timeout: None,
}),
cwd: None, cwd: None,
}, },
&mut cx.to_async(), &mut cx.to_async(),
@@ -411,12 +373,16 @@ mod tests {
let called_event_handler = Arc::new(AtomicBool::new(false)); let called_event_handler = Arc::new(AtomicBool::new(false));
let mut client = DebugAdapterClient::new( let mut client = DebugAdapterClient::new(
crate::client::DebugAdapterClientId(1), crate::client::SessionId(1),
adapter,
DebugAdapterBinary { DebugAdapterBinary {
command: "command".into(), command: "command".into(),
arguments: Default::default(), arguments: Default::default(),
envs: Default::default(), envs: Default::default(),
connection: Some(TCPArguments {
host: Ipv4Addr::LOCALHOST,
port: None,
path: None,
}),
cwd: None, cwd: None,
}, },
&mut cx.to_async(), &mut cx.to_async(),
@@ -466,12 +432,17 @@ mod tests {
let called_event_handler = Arc::new(AtomicBool::new(false)); let called_event_handler = Arc::new(AtomicBool::new(false));
let mut client = DebugAdapterClient::new( let mut client = DebugAdapterClient::new(
crate::client::DebugAdapterClientId(1), crate::client::SessionId(1),
adapter,
DebugAdapterBinary { DebugAdapterBinary {
command: "command".into(), command: "command".into(),
arguments: Default::default(), arguments: Default::default(),
envs: Default::default(), envs: Default::default(),
connection: Some(TCPArguments {
host: Ipv4Addr::LOCALHOST,
port: None,
path: None,
}),
cwd: None, cwd: None,
}, },
&mut cx.to_async(), &mut cx.to_async(),

View File

@@ -357,11 +357,9 @@ pub fn capabilities_to_proto(
capabilities: &Capabilities, capabilities: &Capabilities,
project_id: u64, project_id: u64,
session_id: u64, session_id: u64,
client_id: u64,
) -> SetDebugClientCapabilities { ) -> SetDebugClientCapabilities {
SetDebugClientCapabilities { SetDebugClientCapabilities {
session_id, session_id,
client_id,
project_id, project_id,
supports_loaded_sources_request: capabilities supports_loaded_sources_request: capabilities
.supports_loaded_sources_request .supports_loaded_sources_request

View File

@@ -23,7 +23,7 @@ use std::{
sync::Arc, sync::Arc,
time::Duration, time::Duration,
}; };
use task::TCPHost; use task::{DebugAdapterKind, TCPHost};
use util::ResultExt as _; use util::ResultExt as _;
use crate::{adapters::DebugAdapterBinary, debugger_settings::DebuggerSettings}; use crate::{adapters::DebugAdapterBinary, debugger_settings::DebuggerSettings};
@@ -68,18 +68,80 @@ impl TransportPipe {
type Requests = Arc<Mutex<HashMap<u64, oneshot::Sender<Result<Response>>>>>; type Requests = Arc<Mutex<HashMap<u64, oneshot::Sender<Result<Response>>>>>;
type LogHandlers = Arc<parking_lot::Mutex<SmallVec<[(LogKind, IoHandler); 2]>>>; type LogHandlers = Arc<parking_lot::Mutex<SmallVec<[(LogKind, IoHandler); 2]>>>;
enum Transport {
Stdio(StdioTransport),
Tcp(TcpTransport),
#[cfg(any(test, feature = "test-support"))]
Fake(FakeTransport),
}
impl Transport {
async fn start(binary: &DebugAdapterBinary, cx: AsyncApp) -> Result<(TransportPipe, Self)> {
#[cfg(any(test, feature = "test-support"))]
if binary.kind == DebugAdapterKind::Fake {
return FakeTransport::start(cx)
.await
.map(|(transports, fake)| (transports, Self::Fake(fake)));
}
if binary.connection.is_some() {
TcpTransport::start(binary, cx)
.await
.map(|(transports, tcp)| (transports, Self::Tcp(tcp)))
} else {
StdioTransport::start(binary, cx)
.await
.map(|(transports, stdio)| (transports, Self::Stdio(stdio)))
}
}
fn has_adapter_logs(&self) -> bool {
match self {
Transport::Stdio(stdio_transport) => stdio_transport.has_adapter_logs(),
Transport::Tcp(tcp_transport) => tcp_transport.has_adapter_logs(),
#[cfg(any(test, feature = "test-support"))]
Transport::Fake(fake_transport) => fake_transport.has_adapter_logs(),
}
}
async fn kill(&self) -> Result<()> {
match self {
Transport::Stdio(stdio_transport) => stdio_transport.kill().await,
Transport::Tcp(tcp_transport) => tcp_transport.kill().await,
#[cfg(any(test, feature = "test-support"))]
Transport::Fake(fake_transport) => fake_transport.kill().await,
}
}
#[cfg(any(test, feature = "test-support"))]
fn as_fake(&self) -> &FakeTransport {
match self {
Transport::Fake(fake_transport) => fake_transport,
_ => panic!("Not a fake transport layer"),
}
}
}
pub(crate) struct TransportDelegate { pub(crate) struct TransportDelegate {
log_handlers: LogHandlers, log_handlers: LogHandlers,
current_requests: Requests, current_requests: Requests,
pending_requests: Requests, pending_requests: Requests,
transport: Arc<dyn Transport>, transport: Transport,
server_tx: Arc<Mutex<Option<Sender<Message>>>>, server_tx: Arc<Mutex<Option<Sender<Message>>>>,
} }
impl Transport {
#[cfg(any(test, feature = "test-support"))]
fn fake(args: DebugAdapterBinary) -> Self {
let this = Self::Fake(FakeTransport::new());
}
}
impl TransportDelegate { impl TransportDelegate {
pub fn new(transport: Arc<dyn Transport>) -> Self { #[cfg(any(test, feature = "test-support"))]
pub fn fake(args: DebugAdapterBinary) -> Self {
Self { Self {
transport, transport: Transport::fake(args),
server_tx: Default::default(), server_tx: Default::default(),
log_handlers: Default::default(), log_handlers: Default::default(),
current_requests: Default::default(), current_requests: Default::default(),
@@ -87,27 +149,26 @@ impl TransportDelegate {
} }
} }
pub(crate) async fn reconnect(
&mut self,
cx: &mut AsyncApp,
) -> Result<(Receiver<Message>, Sender<Message>)> {
self.start_handlers(self.transport.reconnect(cx).await?, cx)
.await
}
pub(crate) async fn start( pub(crate) async fn start(
&mut self,
binary: &DebugAdapterBinary, binary: &DebugAdapterBinary,
cx: &mut AsyncApp, cx: AsyncApp,
) -> Result<(Receiver<Message>, Sender<Message>)> { ) -> Result<((Receiver<Message>, Sender<Message>), Self)> {
self.start_handlers(self.transport.start(binary, cx).await?, cx) let (transport_pipes, transport) = Transport::start(binary, cx.clone()).await?;
.await let mut this = Self {
transport,
server_tx: Default::default(),
log_handlers: Default::default(),
current_requests: Default::default(),
pending_requests: Default::default(),
};
let messages = this.start_handlers(transport_pipes, cx).await?;
Ok((messages, this))
} }
async fn start_handlers( async fn start_handlers(
&mut self, &mut self,
mut params: TransportPipe, mut params: TransportPipe,
cx: &mut AsyncApp, cx: AsyncApp,
) -> Result<(Receiver<Message>, Sender<Message>)> { ) -> Result<(Receiver<Message>, Sender<Message>)> {
let (client_tx, server_rx) = unbounded::<Message>(); let (client_tx, server_rx) = unbounded::<Message>();
let (server_tx, client_rx) = unbounded::<Message>(); let (server_tx, client_rx) = unbounded::<Message>();
@@ -475,41 +536,14 @@ impl TransportDelegate {
} }
} }
#[async_trait(?Send)]
pub trait Transport: 'static + Send + Sync + Any {
async fn start(&self, binary: &DebugAdapterBinary, cx: &mut AsyncApp) -> Result<TransportPipe>;
fn has_adapter_logs(&self) -> bool;
async fn kill(&self) -> Result<()>;
async fn reconnect(&self, _: &mut AsyncApp) -> Result<TransportPipe> {
bail!("Cannot reconnect to adapter")
}
#[cfg(any(test, feature = "test-support"))]
fn as_fake(&self) -> &FakeTransport {
panic!("Called as_fake on a real adapter");
}
}
pub struct TcpTransport { pub struct TcpTransport {
port: u16, port: u16,
host: Ipv4Addr, host: Ipv4Addr,
timeout: Option<u64>, timeout: u64,
process: Arc<Mutex<Option<Child>>>, process: Mutex<Child>,
} }
impl TcpTransport { impl TcpTransport {
pub fn new(host: Ipv4Addr, port: u16, timeout: Option<u64>) -> Self {
Self {
port,
host,
timeout,
process: Arc::new(Mutex::new(None)),
}
}
/// Get an open port to use with the tcp client when not supplied by debug config /// Get an open port to use with the tcp client when not supplied by debug config
pub async fn port(host: &TCPHost) -> Result<u16> { pub async fn port(host: &TCPHost) -> Result<u16> {
if let Some(port) = host.port { if let Some(port) = host.port {
@@ -521,49 +555,33 @@ impl TcpTransport {
.port()) .port())
} }
} }
} async fn port_for_host(host: Ipv4Addr) -> Result<u16> {
Ok(TcpListener::bind(SocketAddrV4::new(host, 0))
#[async_trait(?Send)] .await?
impl Transport for TcpTransport { .local_addr()?
async fn reconnect(&self, cx: &mut AsyncApp) -> Result<TransportPipe> { .port())
let address = SocketAddrV4::new(self.host, self.port);
let timeout = self.timeout.unwrap_or_else(|| {
cx.update(|cx| DebuggerSettings::get_global(cx).timeout)
.unwrap_or(2000u64)
});
let (rx, tx) = select! {
_ = cx.background_executor().timer(Duration::from_millis(timeout)).fuse() => {
return Err(anyhow!(format!("Reconnect to TCP DAP timeout {}:{}", self.host, self.port)))
},
result = cx.spawn(|cx| async move {
loop {
match TcpStream::connect(address).await {
Ok(stream) => return stream.split(),
Err(_) => {
cx.background_executor().timer(Duration::from_millis(100)).await;
}
}
}
}).fuse() => result
};
log::info!(
"Debug adapter has reconnected to TCP server {}:{}",
self.host,
self.port
);
Ok(TransportPipe::new(
Box::new(tx),
Box::new(BufReader::new(rx)),
None,
None,
))
} }
async fn start(&self, binary: &DebugAdapterBinary, cx: &mut AsyncApp) -> Result<TransportPipe> { async fn start(binary: &DebugAdapterBinary, cx: AsyncApp) -> Result<(TransportPipe, Self)> {
let Some(connection_args) = binary.connection.as_ref() else {
return Err(anyhow!("No connection arguments provided"));
};
let host = connection_args.host;
let port = if let Some(port) = connection_args.port {
port
} else {
TcpListener::bind(SocketAddrV4::new(host, 0))
.await
.with_context(|| {
format!(
"Failed to connect to debug adapter over tcp. host: {}",
host
)
})?
.local_addr()?
.port()
};
let mut command = util::command::new_smol_command(&binary.command); let mut command = util::command::new_smol_command(&binary.command);
if let Some(cwd) = &binary.cwd { if let Some(cwd) = &binary.cwd {
@@ -588,16 +606,16 @@ impl Transport for TcpTransport {
.spawn() .spawn()
.with_context(|| "failed to start debug adapter.")?; .with_context(|| "failed to start debug adapter.")?;
let address = SocketAddrV4::new(self.host, self.port); let address = SocketAddrV4::new(host, port);
let timeout = self.timeout.unwrap_or_else(|| { let timeout = connection_args.timeout.unwrap_or_else(|| {
cx.update(|cx| DebuggerSettings::get_global(cx).timeout) cx.update(|cx| DebuggerSettings::get_global(cx).timeout)
.unwrap_or(2000u64) .unwrap_or(2000u64)
}); });
let (rx, tx) = select! { let (rx, tx) = select! {
_ = cx.background_executor().timer(Duration::from_millis(timeout)).fuse() => { _ = cx.background_executor().timer(Duration::from_millis(timeout)).fuse() => {
return Err(anyhow!(format!("Connection to TCP DAP timeout {}:{}", self.host, self.port))) return Err(anyhow!(format!("Connection to TCP DAP timeout {}:{}", host, port)))
}, },
result = cx.spawn(|cx| async move { result = cx.spawn(|cx| async move {
loop { loop {
@@ -612,23 +630,27 @@ impl Transport for TcpTransport {
}; };
log::info!( log::info!(
"Debug adapter has connected to TCP server {}:{}", "Debug adapter has connected to TCP server {}:{}",
self.host, host,
self.port port
); );
let stdout = process.stdout.take(); let stdout = process.stdout.take();
let stderr = process.stderr.take(); let stderr = process.stderr.take();
{ let this = Self {
*self.process.lock().await = Some(process); port,
} host,
process: Mutex::new(process),
timeout,
};
Ok(TransportPipe::new( let pipe = TransportPipe::new(
Box::new(tx), Box::new(tx),
Box::new(BufReader::new(rx)), Box::new(BufReader::new(rx)),
stdout.map(|s| Box::new(s) as Box<dyn AsyncRead + Unpin + Send>), stdout.map(|s| Box::new(s) as Box<dyn AsyncRead + Unpin + Send>),
stderr.map(|s| Box::new(s) as Box<dyn AsyncRead + Unpin + Send>), stderr.map(|s| Box::new(s) as Box<dyn AsyncRead + Unpin + Send>),
)) );
Ok((pipe, this))
} }
fn has_adapter_logs(&self) -> bool { fn has_adapter_logs(&self) -> bool {
@@ -636,29 +658,18 @@ impl Transport for TcpTransport {
} }
async fn kill(&self) -> Result<()> { async fn kill(&self) -> Result<()> {
if let Some(mut process) = self.process.lock().await.take() { self.process.lock().await.kill()?;
process.kill()?;
}
Ok(()) Ok(())
} }
} }
pub struct StdioTransport { pub struct StdioTransport {
process: Arc<Mutex<Option<Child>>>, process: Mutex<Child>,
} }
impl StdioTransport { impl StdioTransport {
pub fn new() -> Self { async fn start(binary: &DebugAdapterBinary, _: AsyncApp) -> Result<(TransportPipe, Self)> {
Self {
process: Arc::new(Mutex::new(None)),
}
}
}
#[async_trait(?Send)]
impl Transport for StdioTransport {
async fn start(&self, binary: &DebugAdapterBinary, _: &mut AsyncApp) -> Result<TransportPipe> {
let mut command = util::command::new_smol_command(&binary.command); let mut command = util::command::new_smol_command(&binary.command);
if let Some(cwd) = &binary.cwd { if let Some(cwd) = &binary.cwd {
@@ -705,15 +716,16 @@ impl Transport for StdioTransport {
log::info!("Debug adapter has connected to stdio adapter"); log::info!("Debug adapter has connected to stdio adapter");
{ let process = Mutex::new(process);
*self.process.lock().await = Some(process);
}
Ok(TransportPipe::new( Ok((
Box::new(stdin), TransportPipe::new(
Box::new(BufReader::new(stdout)), Box::new(stdin),
None, Box::new(BufReader::new(stdout)),
stderr, None,
stderr,
),
Self { process },
)) ))
} }
@@ -721,11 +733,12 @@ impl Transport for StdioTransport {
false false
} }
async fn kill(&self) -> Result<()> { async fn reconnect(&self, _: AsyncApp) -> Result<TransportPipe> {
if let Some(mut process) = self.process.lock().await.take() { bail!("Cannot reconnect to adapter")
process.kill()?; }
}
async fn kill(&self) -> Result<()> {
self.process.lock().await.kill()?;
Ok(()) Ok(())
} }
} }
@@ -753,13 +766,6 @@ pub struct FakeTransport {
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
impl FakeTransport { impl FakeTransport {
pub fn new() -> Self {
Self {
request_handlers: Arc::new(Mutex::new(HashMap::default())),
response_handlers: Arc::new(Mutex::new(HashMap::default())),
}
}
pub async fn on_request<R: dap_types::requests::Request, F>(&self, mut handler: F) pub async fn on_request<R: dap_types::requests::Request, F>(&self, mut handler: F)
where where
F: 'static + Send + FnMut(u64, R::Arguments) -> Result<R::Response, ErrorResponse>, F: 'static + Send + FnMut(u64, R::Arguments) -> Result<R::Response, ErrorResponse>,
@@ -803,37 +809,34 @@ impl FakeTransport {
.await .await
.insert(R::COMMAND, Box::new(handler)); .insert(R::COMMAND, Box::new(handler));
} }
}
#[cfg(any(test, feature = "test-support"))] async fn reconnect(&self, cx: AsyncApp) -> Result<TransportPipe> {
#[async_trait(?Send)]
impl Transport for FakeTransport {
async fn reconnect(&self, cx: &mut AsyncApp) -> Result<TransportPipe> {
self.start( self.start(
&DebugAdapterBinary { &DebugAdapterBinary {
command: "command".into(), command: "command".into(),
arguments: None, arguments: None,
envs: None, envs: None,
cwd: None, cwd: None,
connection: TcpTransport::new(None, None),
}, },
cx, cx,
) )
.await .await
} }
async fn start( async fn start(cx: AsyncApp) -> Result<TransportPipe> {
&self, let this = Self {
_binary: &DebugAdapterBinary, request_handlers: Arc::new(Mutex::new(HashMap::default())),
cx: &mut AsyncApp, response_handlers: Arc::new(Mutex::new(HashMap::default())),
) -> Result<TransportPipe> { };
use dap_types::requests::{Request, RunInTerminal, StartDebugging}; use dap_types::requests::{Request, RunInTerminal, StartDebugging};
use serde_json::json; use serde_json::json;
let (stdin_writer, stdin_reader) = async_pipe::pipe(); let (stdin_writer, stdin_reader) = async_pipe::pipe();
let (stdout_writer, stdout_reader) = async_pipe::pipe(); let (stdout_writer, stdout_reader) = async_pipe::pipe();
let request_handlers = self.request_handlers.clone(); let request_handlers = this.request_handlers.clone();
let response_handlers = self.response_handlers.clone(); let response_handlers = this.response_handlers.clone();
let stdout_writer = Arc::new(Mutex::new(stdout_writer)); let stdout_writer = Arc::new(Mutex::new(stdout_writer));
cx.background_executor() cx.background_executor()

View File

@@ -1,6 +1,6 @@
use std::{ffi::OsString, path::PathBuf, sync::Arc}; use std::{ffi::OsString, path::PathBuf, sync::Arc};
use dap::transport::{StdioTransport, TcpTransport, Transport}; use dap::transport::{StdioTransport, TcpTransport};
use gpui::AsyncApp; use gpui::AsyncApp;
use serde_json::Value; use serde_json::Value;
use task::DebugAdapterConfig; use task::DebugAdapterConfig;
@@ -9,24 +9,13 @@ use crate::*;
pub(crate) struct CustomDebugAdapter { pub(crate) struct CustomDebugAdapter {
custom_args: CustomArgs, custom_args: CustomArgs,
transport: Arc<dyn Transport>,
} }
impl CustomDebugAdapter { impl CustomDebugAdapter {
const ADAPTER_NAME: &'static str = "custom_dap"; const ADAPTER_NAME: &'static str = "custom_dap";
pub(crate) async fn new(custom_args: CustomArgs) -> Result<Self> { pub(crate) async fn new(custom_args: CustomArgs) -> Result<Self> {
Ok(CustomDebugAdapter { Ok(CustomDebugAdapter { custom_args })
transport: match &custom_args.connection {
DebugConnectionType::TCP(host) => Arc::new(TcpTransport::new(
host.host(),
TcpTransport::port(&host).await?,
host.timeout,
)),
DebugConnectionType::STDIO => Arc::new(StdioTransport::new()),
},
custom_args,
})
} }
} }
@@ -36,10 +25,6 @@ impl DebugAdapter for CustomDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into()) DebugAdapterName(Self::ADAPTER_NAME.into())
} }
fn transport(&self) -> Arc<dyn Transport> {
self.transport.clone()
}
async fn get_binary( async fn get_binary(
&self, &self,
_: &dyn DapDelegate, _: &dyn DapDelegate,
@@ -47,7 +32,17 @@ impl DebugAdapter for CustomDebugAdapter {
_: Option<PathBuf>, _: Option<PathBuf>,
_: &mut AsyncApp, _: &mut AsyncApp,
) -> Result<DebugAdapterBinary> { ) -> Result<DebugAdapterBinary> {
Ok(DebugAdapterBinary { let connection = if let DebugConnectionType::TCP(connection) = &self.custom_args.connection
{
Some(adapters::TcpArguments {
host: connection.host(),
port: connection.port,
timeout: connection.timeout,
})
} else {
None
};
let ret = DebugAdapterBinary {
command: self.custom_args.command.clone(), command: self.custom_args.command.clone(),
arguments: self arguments: self
.custom_args .custom_args
@@ -56,7 +51,9 @@ impl DebugAdapter for CustomDebugAdapter {
.map(|args| args.iter().map(OsString::from).collect()), .map(|args| args.iter().map(OsString::from).collect()),
cwd: config.cwd.clone(), cwd: config.cwd.clone(),
envs: self.custom_args.envs.clone(), envs: self.custom_args.envs.clone(),
}) connection,
};
Ok(ret)
} }
async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> { async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {

View File

@@ -1,4 +1,4 @@
use dap::transport::{TcpTransport, Transport}; use dap::transport::TcpTransport;
use gpui::AsyncApp; use gpui::AsyncApp;
use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc}; use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc};
@@ -28,10 +28,6 @@ impl DebugAdapter for GoDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into()) DebugAdapterName(Self::ADAPTER_NAME.into())
} }
fn transport(&self) -> Arc<dyn Transport> {
Arc::new(TcpTransport::new(self.host, self.port, self.timeout))
}
async fn get_binary( async fn get_binary(
&self, &self,
delegate: &dyn DapDelegate, delegate: &dyn DapDelegate,
@@ -86,6 +82,7 @@ impl DebugAdapter for GoDebugAdapter {
]), ]),
cwd: config.cwd.clone(), cwd: config.cwd.clone(),
envs: None, envs: None,
connection: None,
}) })
} }

View File

@@ -1,5 +1,5 @@
use adapters::latest_github_release; use adapters::latest_github_release;
use dap::transport::{TcpTransport, Transport}; use dap::transport::TcpTransport;
use gpui::AsyncApp; use gpui::AsyncApp;
use regex::Regex; use regex::Regex;
use std::{collections::HashMap, net::Ipv4Addr, path::PathBuf, sync::Arc}; use std::{collections::HashMap, net::Ipv4Addr, path::PathBuf, sync::Arc};
@@ -33,10 +33,6 @@ impl DebugAdapter for JsDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into()) DebugAdapterName(Self::ADAPTER_NAME.into())
} }
fn transport(&self) -> Arc<dyn Transport> {
Arc::new(TcpTransport::new(self.host, self.port, self.timeout))
}
async fn fetch_latest_adapter_version( async fn fetch_latest_adapter_version(
&self, &self,
delegate: &dyn DapDelegate, delegate: &dyn DapDelegate,
@@ -98,6 +94,11 @@ impl DebugAdapter for JsDebugAdapter {
]), ]),
cwd: config.cwd.clone(), cwd: config.cwd.clone(),
envs: None, envs: None,
connection: Some(adapters::TcpArguments {
host: self.host,
port: Some(self.port),
timeout: self.timeout,
}),
}) })
} }
@@ -136,10 +137,6 @@ impl DebugAdapter for JsDebugAdapter {
}) })
} }
fn supports_attach(&self) -> bool {
true
}
fn attach_processes<'a>( fn attach_processes<'a>(
&self, &self,
processes: &'a HashMap<Pid, Process>, processes: &'a HashMap<Pid, Process>,

View File

@@ -2,7 +2,7 @@ use std::{collections::HashMap, ffi::OsStr, path::PathBuf, sync::Arc};
use anyhow::Result; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
use dap::transport::{StdioTransport, Transport}; use dap::transport::StdioTransport;
use gpui::AsyncApp; use gpui::AsyncApp;
use sysinfo::{Pid, Process}; use sysinfo::{Pid, Process};
use task::{DebugAdapterConfig, DebugRequestType}; use task::{DebugAdapterConfig, DebugRequestType};
@@ -25,10 +25,6 @@ impl DebugAdapter for LldbDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into()) DebugAdapterName(Self::ADAPTER_NAME.into())
} }
fn transport(&self) -> Arc<dyn Transport> {
Arc::new(StdioTransport::new())
}
async fn get_binary( async fn get_binary(
&self, &self,
delegate: &dyn DapDelegate, delegate: &dyn DapDelegate,
@@ -59,6 +55,7 @@ impl DebugAdapter for LldbDebugAdapter {
arguments: None, arguments: None,
envs: None, envs: None,
cwd: config.cwd.clone(), cwd: config.cwd.clone(),
connection: None,
}) })
} }
@@ -102,10 +99,6 @@ impl DebugAdapter for LldbDebugAdapter {
}) })
} }
fn supports_attach(&self) -> bool {
true
}
fn attach_processes<'a>( fn attach_processes<'a>(
&self, &self,
processes: &'a HashMap<Pid, Process>, processes: &'a HashMap<Pid, Process>,

View File

@@ -1,5 +1,5 @@
use adapters::latest_github_release; use adapters::latest_github_release;
use dap::transport::{TcpTransport, Transport}; use dap::{adapters::TcpArguments, transport::TcpTransport};
use gpui::AsyncApp; use gpui::AsyncApp;
use std::{net::Ipv4Addr, path::PathBuf, sync::Arc}; use std::{net::Ipv4Addr, path::PathBuf, sync::Arc};
@@ -30,10 +30,6 @@ impl DebugAdapter for PhpDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into()) DebugAdapterName(Self::ADAPTER_NAME.into())
} }
fn transport(&self) -> Arc<dyn Transport> {
Arc::new(TcpTransport::new(self.host, self.port, self.timeout))
}
async fn fetch_latest_adapter_version( async fn fetch_latest_adapter_version(
&self, &self,
delegate: &dyn DapDelegate, delegate: &dyn DapDelegate,
@@ -92,6 +88,11 @@ impl DebugAdapter for PhpDebugAdapter {
adapter_path.join(Self::ADAPTER_PATH).into(), adapter_path.join(Self::ADAPTER_PATH).into(),
format!("--server={}", self.port).into(), format!("--server={}", self.port).into(),
]), ]),
connection: Some(TcpArguments {
port: Some(self.port),
host: Ipv4Addr::LOCALHOST,
timeout: None,
}),
cwd: config.cwd.clone(), cwd: config.cwd.clone(),
envs: None, envs: None,
}) })

View File

@@ -1,5 +1,5 @@
use crate::*; use crate::*;
use dap::transport::{TcpTransport, Transport}; use dap::transport::TcpTransport;
use gpui::AsyncApp; use gpui::AsyncApp;
use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc}; use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc};
@@ -29,10 +29,6 @@ impl DebugAdapter for PythonDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into()) DebugAdapterName(Self::ADAPTER_NAME.into())
} }
fn transport(&self) -> Arc<dyn Transport> {
Arc::new(TcpTransport::new(self.host, self.port, self.timeout))
}
async fn fetch_latest_adapter_version( async fn fetch_latest_adapter_version(
&self, &self,
delegate: &dyn DapDelegate, delegate: &dyn DapDelegate,
@@ -125,6 +121,11 @@ impl DebugAdapter for PythonDebugAdapter {
format!("--port={}", self.port).into(), format!("--port={}", self.port).into(),
format!("--host={}", self.host).into(), format!("--host={}", self.host).into(),
]), ]),
connection: Some(adapters::TcpArguments {
host: self.host,
port: Some(self.port),
timeout: self.timeout,
}),
cwd: config.cwd.clone(), cwd: config.cwd.clone(),
envs: None, envs: None,
}) })

View File

@@ -1,5 +1,5 @@
use dap::{ use dap::{
client::{DebugAdapterClient, DebugAdapterClientId}, client::{DebugAdapterClient, SessionId},
debugger_settings::DebuggerSettings, debugger_settings::DebuggerSettings,
transport::{IoKind, LogKind}, transport::{IoKind, LogKind},
}; };
@@ -12,11 +12,7 @@ use gpui::{
actions, div, App, AppContext, Context, Empty, Entity, EventEmitter, FocusHandle, Focusable, actions, div, App, AppContext, Context, Empty, Entity, EventEmitter, FocusHandle, Focusable,
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, WeakEntity, Window, IntoElement, ParentElement, Render, SharedString, Styled, Subscription, WeakEntity, Window,
}; };
use project::{ use project::{debugger::session::Session, search::SearchQuery, Project};
debugger::dap_session::{DebugSession, DebugSessionId},
search::SearchQuery,
Project,
};
use settings::Settings as _; use settings::Settings as _;
use std::{ use std::{
borrow::Cow, borrow::Cow,
@@ -36,16 +32,16 @@ struct DapLogView {
focus_handle: FocusHandle, focus_handle: FocusHandle,
log_store: Entity<LogStore>, log_store: Entity<LogStore>,
editor_subscriptions: Vec<Subscription>, editor_subscriptions: Vec<Subscription>,
current_view: Option<(DebugAdapterClientId, LogKind)>, current_view: Option<(SessionId, LogKind)>,
project: Entity<Project>, project: Entity<Project>,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
struct LogStore { struct LogStore {
projects: HashMap<WeakEntity<Project>, ProjectState>, projects: HashMap<WeakEntity<Project>, ProjectState>,
debug_clients: HashMap<DebugAdapterClientId, DebugAdapterState>, debug_clients: HashMap<SessionId, DebugAdapterState>,
rpc_tx: UnboundedSender<(DebugAdapterClientId, IoKind, String)>, rpc_tx: UnboundedSender<(SessionId, IoKind, String)>,
adapter_log_tx: UnboundedSender<(DebugAdapterClientId, IoKind, String)>, adapter_log_tx: UnboundedSender<(SessionId, IoKind, String)>,
} }
struct ProjectState { struct ProjectState {
@@ -102,7 +98,7 @@ impl DebugAdapterState {
impl LogStore { impl LogStore {
fn new(cx: &Context<Self>) -> Self { fn new(cx: &Context<Self>) -> Self {
let (rpc_tx, mut rpc_rx) = unbounded::<(DebugAdapterClientId, IoKind, String)>(); let (rpc_tx, mut rpc_rx) = unbounded::<(SessionId, IoKind, String)>();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
while let Some((client_id, io_kind, message)) = rpc_rx.next().await { while let Some((client_id, io_kind, message)) = rpc_rx.next().await {
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
@@ -117,8 +113,7 @@ impl LogStore {
}) })
.detach_and_log_err(cx); .detach_and_log_err(cx);
let (adapter_log_tx, mut adapter_log_rx) = let (adapter_log_tx, mut adapter_log_rx) = unbounded::<(SessionId, IoKind, String)>();
unbounded::<(DebugAdapterClientId, IoKind, String)>();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
while let Some((client_id, io_kind, message)) = adapter_log_rx.next().await { while let Some((client_id, io_kind, message)) = adapter_log_rx.next().await {
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
@@ -142,7 +137,7 @@ impl LogStore {
fn on_rpc_log( fn on_rpc_log(
&mut self, &mut self,
client_id: DebugAdapterClientId, client_id: SessionId,
io_kind: IoKind, io_kind: IoKind,
message: &str, message: &str,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -152,7 +147,7 @@ impl LogStore {
fn on_adapter_log( fn on_adapter_log(
&mut self, &mut self,
client_id: DebugAdapterClientId, client_id: SessionId,
io_kind: IoKind, io_kind: IoKind,
message: &str, message: &str,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -170,19 +165,17 @@ impl LogStore {
this.projects.remove(&weak_project); this.projects.remove(&weak_project);
}), }),
cx.subscribe(project, |this, project, event, cx| match event { cx.subscribe(project, |this, project, event, cx| match event {
project::Event::DebugClientStarted((_, client_id)) => { project::Event::DebugClientStarted(client_id) => {
this.add_debug_client( let client = project.update(cx, |project, cx| {
*client_id, project.dap_store().update(cx, |store, cx| {
project.update(cx, |project, cx| { store
project.dap_store().update(cx, |store, cx| { .session_by_id(client_id)
store.client_by_id(client_id, cx).and_then( .and_then(|client| Some(client))
|(session, client)| { })
Some((session, client.read(cx).adapter_client()?)) });
}, if let Some(client) = client {
) this.add_debug_client(*client_id, client, cx);
}) }
}),
);
} }
project::Event::DebugClientShutdown(client_id) => { project::Event::DebugClientShutdown(client_id) => {
this.remove_debug_client(*client_id, cx); this.remove_debug_client(*client_id, cx);
@@ -195,16 +188,13 @@ impl LogStore {
); );
} }
fn get_debug_adapter_state( fn get_debug_adapter_state(&mut self, id: SessionId) -> Option<&mut DebugAdapterState> {
&mut self,
id: DebugAdapterClientId,
) -> Option<&mut DebugAdapterState> {
self.debug_clients.get_mut(&id) self.debug_clients.get_mut(&id)
} }
fn add_debug_client_message( fn add_debug_client_message(
&mut self, &mut self,
id: DebugAdapterClientId, id: SessionId,
io_kind: IoKind, io_kind: IoKind,
message: String, message: String,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -236,7 +226,7 @@ impl LogStore {
fn add_debug_client_log( fn add_debug_client_log(
&mut self, &mut self,
id: DebugAdapterClientId, id: SessionId,
io_kind: IoKind, io_kind: IoKind,
message: String, message: String,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -266,7 +256,7 @@ impl LogStore {
fn add_debug_client_entry( fn add_debug_client_entry(
log_lines: &mut VecDeque<String>, log_lines: &mut VecDeque<String>,
id: DebugAdapterClientId, id: SessionId,
message: String, message: String,
kind: LogKind, kind: LogKind,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -295,56 +285,50 @@ impl LogStore {
fn add_debug_client( fn add_debug_client(
&mut self, &mut self,
client_id: DebugAdapterClientId, client_id: SessionId,
session_and_client: Option<(Entity<DebugSession>, Arc<DebugAdapterClient>)>, client: Entity<Session>,
cx: &App,
) -> Option<&mut DebugAdapterState> { ) -> Option<&mut DebugAdapterState> {
let client_state = self let client_state = self
.debug_clients .debug_clients
.entry(client_id) .entry(client_id)
.or_insert_with(DebugAdapterState::new); .or_insert_with(DebugAdapterState::new);
if let Some((_, client)) = session_and_client { let io_tx = self.rpc_tx.clone();
let io_tx = self.rpc_tx.clone();
client.add_log_handler( let client = client.read(cx).adapter_client()?;
move |io_kind, message| { client.add_log_handler(
io_tx move |io_kind, message| {
.unbounded_send((client_id, io_kind, message.to_string())) io_tx
.ok(); .unbounded_send((client_id, io_kind, message.to_string()))
}, .ok();
LogKind::Rpc, },
); LogKind::Rpc,
);
let log_io_tx = self.adapter_log_tx.clone(); let log_io_tx = self.adapter_log_tx.clone();
client.add_log_handler( client.add_log_handler(
move |io_kind, message| { move |io_kind, message| {
log_io_tx log_io_tx
.unbounded_send((client_id, io_kind, message.to_string())) .unbounded_send((client_id, io_kind, message.to_string()))
.ok(); .ok();
}, },
LogKind::Adapter, LogKind::Adapter,
); );
}
Some(client_state) Some(client_state)
} }
fn remove_debug_client(&mut self, client_id: DebugAdapterClientId, cx: &mut Context<Self>) { fn remove_debug_client(&mut self, client_id: SessionId, cx: &mut Context<Self>) {
self.debug_clients.remove(&client_id); self.debug_clients.remove(&client_id);
cx.notify(); cx.notify();
} }
fn log_messages_for_client( fn log_messages_for_client(&mut self, client_id: SessionId) -> Option<&mut VecDeque<String>> {
&mut self,
client_id: DebugAdapterClientId,
) -> Option<&mut VecDeque<String>> {
Some(&mut self.debug_clients.get_mut(&client_id)?.log_messages) Some(&mut self.debug_clients.get_mut(&client_id)?.log_messages)
} }
fn rpc_messages_for_client( fn rpc_messages_for_client(&mut self, client_id: SessionId) -> Option<&mut VecDeque<String>> {
&mut self,
client_id: DebugAdapterClientId,
) -> Option<&mut VecDeque<String>> {
Some( Some(
&mut self &mut self
.debug_clients .debug_clients
@@ -379,11 +363,9 @@ impl Render for DapLogToolbarItemView {
}); });
let current_client = current_client_id.and_then(|current_client_id| { let current_client = current_client_id.and_then(|current_client_id| {
menu_rows.iter().find_map(|row| { menu_rows
row.clients .iter()
.iter() .find(|row| row.client_id == current_client_id)
.find(|sub_item| sub_item.client_id == current_client_id)
})
}); });
let dap_menu: PopoverMenu<_> = PopoverMenu::new("DapLogView") let dap_menu: PopoverMenu<_> = PopoverMenu::new("DapLogView")
@@ -409,56 +391,48 @@ impl Render for DapLogToolbarItemView {
let menu_rows = menu_rows.clone(); let menu_rows = menu_rows.clone();
ContextMenu::build(&mut window, cx, move |mut menu, window, _cx| { ContextMenu::build(&mut window, cx, move |mut menu, window, _cx| {
for row in menu_rows.into_iter() { for row in menu_rows.into_iter() {
menu = menu.header(format!("{}. {}", row.session_id.0, row.session_name)); menu = menu.custom_row(move |_window, _cx| {
div()
for sub_item in row.clients.into_iter() { .w_full()
menu = menu.custom_row(move |_window, _cx| { .pl_2()
div() .child(
.w_full() Label::new(
.pl_2() format!("{}. {}", row.client_id.0, row.client_name,),
.child(
Label::new(format!(
"{}. {}",
sub_item.client_id.0, sub_item.client_name,
))
.color(workspace::ui::Color::Muted),
) )
.into_any_element() .color(workspace::ui::Color::Muted),
}); )
.into_any_element()
if sub_item.has_adapter_logs { });
menu = menu.custom_entry(
move |_window, _cx| {
div()
.w_full()
.pl_4()
.child(Label::new(ADAPTER_LOGS))
.into_any_element()
},
window.handler_for(&log_view, move |view, window, cx| {
view.show_log_messages_for_adapter(
sub_item.client_id,
window,
cx,
);
}),
);
}
if row.has_adapter_logs {
menu = menu.custom_entry( menu = menu.custom_entry(
move |_window, _cx| { move |_window, _cx| {
div() div()
.w_full() .w_full()
.pl_4() .pl_4()
.child(Label::new(RPC_MESSAGES)) .child(Label::new(ADAPTER_LOGS))
.into_any_element() .into_any_element()
}, },
window.handler_for(&log_view, move |view, window, cx| { window.handler_for(&log_view, move |view, window, cx| {
view.show_rpc_trace_for_server(sub_item.client_id, window, cx); view.show_log_messages_for_adapter(row.client_id, window, cx);
}), }),
); );
} }
menu = menu.custom_entry(
move |_window, _cx| {
div()
.w_full()
.pl_4()
.child(Label::new(RPC_MESSAGES))
.into_any_element()
},
window.handler_for(&log_view, move |view, window, cx| {
view.show_rpc_trace_for_server(row.client_id, window, cx);
}),
);
} }
menu menu
}) })
.into() .into()
@@ -585,36 +559,23 @@ impl DapLogView {
.dap_store() .dap_store()
.read(cx) .read(cx)
.sessions() .sessions()
.filter_map(|session| { .filter_map(|client| {
let client = client.read(cx).adapter_client()?;
Some(DapMenuItem { Some(DapMenuItem {
session_id: session.read(cx).id(), client_id: client.id(),
session_name: session.read(cx).name(), client_name: unimplemented!(),
clients: { has_adapter_logs: client.has_adapter_logs(),
let mut clients = session selected_entry: self.current_view.map_or(LogKind::Adapter, |(_, kind)| kind),
.read_with(cx, |session, cx| session.clients(cx))
.iter()
.map(|client| DapMenuSubItem {
client_id: client.id(),
client_name: client.adapter_id(),
has_adapter_logs: client.has_adapter_logs(),
selected_entry: self
.current_view
.map_or(LogKind::Adapter, |(_, kind)| kind),
})
.collect::<Vec<_>>();
clients.sort_by_key(|item| item.client_id.0);
clients
},
}) })
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
menu_items.sort_by_key(|item| item.session_id.0); menu_items.sort_by_key(|item| item.client_id.0);
Some(menu_items) Some(menu_items)
} }
fn show_rpc_trace_for_server( fn show_rpc_trace_for_server(
&mut self, &mut self,
client_id: DebugAdapterClientId, client_id: SessionId,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
@@ -656,7 +617,7 @@ impl DapLogView {
fn show_log_messages_for_adapter( fn show_log_messages_for_adapter(
&mut self, &mut self,
client_id: DebugAdapterClientId, client_id: SessionId,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
@@ -697,14 +658,7 @@ fn log_contents(lines: &VecDeque<String>) -> String {
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub(crate) struct DapMenuItem { pub(crate) struct DapMenuItem {
pub session_id: DebugSessionId, pub client_id: SessionId,
pub session_name: String,
pub clients: Vec<DapMenuSubItem>,
}
#[derive(Clone, PartialEq)]
pub(crate) struct DapMenuSubItem {
pub client_id: DebugAdapterClientId,
pub client_name: String, pub client_name: String,
pub has_adapter_logs: bool, pub has_adapter_logs: bool,
pub selected_entry: LogKind, pub selected_entry: LogKind,
@@ -870,7 +824,7 @@ impl Focusable for DapLogView {
pub enum Event { pub enum Event {
NewLogEntry { NewLogEntry {
id: DebugAdapterClientId, id: SessionId,
entry: String, entry: String,
kind: LogKind, kind: LogKind,
}, },

View File

@@ -1,9 +1,9 @@
use dap::client::DebugAdapterClientId; use dap::client::SessionId;
use fuzzy::{StringMatch, StringMatchCandidate}; use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::Subscription; use gpui::Subscription;
use gpui::{DismissEvent, Entity, EventEmitter, Focusable, Render}; use gpui::{DismissEvent, Entity, EventEmitter, Focusable, Render};
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use project::debugger::{dap_session::DebugSessionId, dap_store::DapStore}; use project::debugger::dap_store::DapStore;
use std::sync::Arc; use std::sync::Arc;
use sysinfo::System; use sysinfo::System;
use ui::{prelude::*, Context, Tooltip}; use ui::{prelude::*, Context, Tooltip};
@@ -20,19 +20,15 @@ struct Candidate {
pub(crate) struct AttachModalDelegate { pub(crate) struct AttachModalDelegate {
selected_index: usize, selected_index: usize,
matches: Vec<StringMatch>, matches: Vec<StringMatch>,
session_id: DebugSessionId, session_id: SessionId,
placeholder_text: Arc<str>, placeholder_text: Arc<str>,
dap_store: Entity<DapStore>, dap_store: Entity<DapStore>,
client_id: DebugAdapterClientId, client_id: SessionId,
candidates: Option<Vec<Candidate>>, candidates: Option<Vec<Candidate>>,
} }
impl AttachModalDelegate { impl AttachModalDelegate {
pub fn new( pub fn new(session_id: SessionId, client_id: SessionId, dap_store: Entity<DapStore>) -> Self {
session_id: DebugSessionId,
client_id: DebugAdapterClientId,
dap_store: Entity<DapStore>,
) -> Self {
Self { Self {
client_id, client_id,
dap_store, dap_store,
@@ -52,8 +48,8 @@ pub(crate) struct AttachModal {
impl AttachModal { impl AttachModal {
pub fn new( pub fn new(
session_id: &DebugSessionId, session_id: &SessionId,
client_id: DebugAdapterClientId, client_id: SessionId,
dap_store: Entity<DapStore>, dap_store: Entity<DapStore>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -132,18 +128,15 @@ impl PickerDelegate for AttachModalDelegate {
} else { } else {
let Some(client) = this.delegate.dap_store.update(cx, |store, cx| { let Some(client) = this.delegate.dap_store.update(cx, |store, cx| {
store store
.client_by_id(&this.delegate.client_id, cx) .session_by_id(&this.delegate.client_id)
.and_then(|(_, client)| client.read(cx).adapter_client()) .and_then(|client| client.read(cx).adapter_client())
}) else { }) else {
return Vec::new(); return Vec::new();
}; };
let system = System::new_all(); let system = System::new_all();
let Some(processes) = todo!("client.adapter().attach_processes(&system.processes())");
client.adapter().attach_processes(&system.processes()) let processes: Vec<(&sysinfo::Pid, &sysinfo::Process)> = vec![];
else {
return Vec::new();
};
let processes = processes let processes = processes
.into_iter() .into_iter()
@@ -156,7 +149,7 @@ impl PickerDelegate for AttachModalDelegate {
.map(|s| s.to_string_lossy().to_string()) .map(|s| s.to_string_lossy().to_string())
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
}) })
.collect::<Vec<_>>(); .collect::<Vec<Candidate>>();
let _ = this.delegate.candidates.insert(processes.clone()); let _ = this.delegate.candidates.insert(processes.clone());
@@ -224,7 +217,7 @@ impl PickerDelegate for AttachModalDelegate {
self.dap_store.update(cx, |store, cx| { self.dap_store.update(cx, |store, cx| {
store store
.attach(&self.session_id, self.client_id, candidate.pid, cx) .attach(self.client_id, candidate.pid, cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
use dap::debugger_settings::DebuggerSettings; use dap::debugger_settings::DebuggerSettings;
use debugger_panel::{DebugPanel, ToggleFocus}; use debugger_panel::{DebugPanel, ToggleFocus};
use debugger_panel_item::DebugPanelItem;
use gpui::App; use gpui::App;
use session::DebugSession;
use settings::Settings; use settings::Settings;
use workspace::{ use workspace::{
Continue, Pause, Restart, ShutdownDebugAdapters, Start, StepBack, StepInto, StepOut, StepOver, Continue, Pause, Restart, ShutdownDebugAdapters, Start, StepBack, StepInto, StepOut, StepOver,
@@ -9,20 +9,15 @@ use workspace::{
}; };
pub mod attach_modal; pub mod attach_modal;
pub mod console;
pub mod debugger_panel; pub mod debugger_panel;
pub mod debugger_panel_item; pub mod session;
pub mod loaded_source_list;
pub mod module_list;
pub mod stack_frame_list;
pub mod variable_list;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub fn init(cx: &mut App) { pub fn init(cx: &mut App) {
DebuggerSettings::register(cx); DebuggerSettings::register(cx);
workspace::FollowableViewRegistry::register::<DebugPanelItem>(cx); workspace::FollowableViewRegistry::register::<DebugSession>(cx);
cx.observe_new(|workspace: &mut Workspace, window, _cx| { cx.observe_new(|workspace: &mut Workspace, window, _cx| {
let Some(_) = window else { let Some(_) = window else {
@@ -45,108 +40,7 @@ pub fn init(cx: &mut App) {
}) })
}) })
}, },
) );
.register_action(|workspace: &mut Workspace, _: &Stop, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.stop_thread(cx))
});
})
.register_action(|workspace: &mut Workspace, _: &Continue, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.continue_thread(cx))
});
})
.register_action(|workspace: &mut Workspace, _: &StepInto, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.step_in(cx))
});
})
.register_action(|workspace: &mut Workspace, _: &StepBack, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.step_back(cx))
});
})
.register_action(|workspace: &mut Workspace, _: &StepOut, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.step_out(cx))
});
})
.register_action(|workspace: &mut Workspace, _: &StepOver, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.step_over(cx))
});
})
.register_action(|workspace: &mut Workspace, _: &Restart, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.restart_client(cx))
});
})
.register_action(
|workspace: &mut Workspace, _: &ToggleIgnoreBreakpoints, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.toggle_ignore_breakpoints(cx))
});
},
)
.register_action(|workspace: &mut Workspace, _: &Pause, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
debug_panel.update(cx, |panel, cx| {
let Some(active_item) = panel.active_debug_panel_item(cx) else {
return;
};
active_item.update(cx, |item, cx| item.pause_thread(cx))
});
});
}) })
.detach(); .detach();
} }

View File

@@ -0,0 +1,190 @@
mod inert;
mod running;
mod starting;
use crate::debugger_panel::{DebugPanel, DebugPanelEvent};
use dap::{
client::SessionId, debugger_settings::DebuggerSettings, Capabilities, ContinuedEvent,
LoadedSourceEvent, ModuleEvent, OutputEvent, OutputEventCategory, StoppedEvent, ThreadEvent,
};
use gpui::{
AnyElement, App, Entity, EventEmitter, FocusHandle, Focusable, Subscription, Task, WeakEntity,
};
use inert::InertState;
use project::debugger::session::Session;
use project::debugger::session::{ThreadId, ThreadStatus};
use rpc::proto::{self, PeerId};
use settings::Settings;
use starting::StartingState;
use ui::{prelude::*, ContextMenu, DropdownMenu, Indicator, Tooltip};
use workspace::{
item::{self, Item, ItemEvent},
FollowableItem, ViewId, Workspace,
};
enum DebugSessionState {
Inert(Entity<InertState>),
Starting(Entity<StartingState>),
Running(Entity<running::RunningState>),
}
pub struct DebugSession {
remote_id: Option<workspace::ViewId>,
mode: DebugSessionState,
}
#[derive(Debug)]
pub enum DebugPanelItemEvent {
Close,
Stopped { go_to_stack_frame: bool },
}
#[derive(Clone, PartialEq, Eq)]
pub enum ThreadItem {
Console,
LoadedSource,
Modules,
Variables,
}
impl ThreadItem {
fn _to_proto(&self) -> proto::DebuggerThreadItem {
match self {
ThreadItem::Console => proto::DebuggerThreadItem::Console,
ThreadItem::LoadedSource => proto::DebuggerThreadItem::LoadedSource,
ThreadItem::Modules => proto::DebuggerThreadItem::Modules,
ThreadItem::Variables => proto::DebuggerThreadItem::Variables,
}
}
fn from_proto(active_thread_item: proto::DebuggerThreadItem) -> Self {
match active_thread_item {
proto::DebuggerThreadItem::Console => ThreadItem::Console,
proto::DebuggerThreadItem::LoadedSource => ThreadItem::LoadedSource,
proto::DebuggerThreadItem::Modules => ThreadItem::Modules,
proto::DebuggerThreadItem::Variables => ThreadItem::Variables,
}
}
}
impl DebugSession {
pub(super) fn inert(cx: &mut App) -> Entity<Self> {
cx.new(|cx| Self {
remote_id: None,
mode: DebugSessionState::Inert(cx.new(|cx| InertState::new(cx))),
})
}
pub(crate) fn session_id(&self, cx: &App) -> Option<SessionId> {
match &self.mode {
DebugSessionState::Inert(_) => None,
DebugSessionState::Starting(_entity) => unimplemented!(),
DebugSessionState::Running(entity) => Some(entity.read(cx).client_id()),
}
}
}
impl EventEmitter<DebugPanelItemEvent> for DebugSession {}
impl Focusable for DebugSession {
fn focus_handle(&self, cx: &App) -> FocusHandle {
match &self.mode {
DebugSessionState::Inert(inert_state) => inert_state.focus_handle(cx),
DebugSessionState::Starting(starting_state) => starting_state.focus_handle(cx),
DebugSessionState::Running(running_state) => running_state.focus_handle(cx),
}
}
}
impl Item for DebugSession {
type Event = DebugPanelItemEvent;
fn tab_content(&self, _: item::TabContentParams, _: &Window, _: &App) -> AnyElement {
let label = match &self.mode {
DebugSessionState::Inert(_) => "New Session",
DebugSessionState::Starting(_) => "Starting",
DebugSessionState::Running(_) => "Running",
};
div().child(Label::new(label)).into_any_element()
}
}
impl FollowableItem for DebugSession {
fn remote_id(&self) -> Option<workspace::ViewId> {
self.remote_id
}
fn to_state_proto(&self, _window: &Window, _cx: &App) -> Option<proto::view::Variant> {
None
}
fn from_state_proto(
_workspace: Entity<Workspace>,
_remote_id: ViewId,
_state: &mut Option<proto::view::Variant>,
_window: &mut Window,
_cx: &mut App,
) -> Option<gpui::Task<gpui::Result<Entity<Self>>>> {
None
}
fn add_event_to_update_proto(
&self,
_event: &Self::Event,
_update: &mut Option<proto::update_view::Variant>,
_window: &Window,
_cx: &App,
) -> bool {
// update.get_or_insert_with(|| proto::update_view::Variant::DebugPanel(Default::default()));
true
}
fn apply_update_proto(
&mut self,
_project: &Entity<project::Project>,
_message: proto::update_view::Variant,
_window: &mut Window,
_cx: &mut Context<Self>,
) -> gpui::Task<gpui::Result<()>> {
Task::ready(Ok(()))
}
fn set_leader_peer_id(
&mut self,
_leader_peer_id: Option<PeerId>,
_window: &mut Window,
_cx: &mut Context<Self>,
) {
}
fn to_follow_event(_event: &Self::Event) -> Option<workspace::item::FollowEvent> {
None
}
fn dedup(&self, existing: &Self, _window: &Window, cx: &App) -> Option<workspace::item::Dedup> {
if existing.session_id(cx) == self.session_id(cx) {
Some(item::Dedup::KeepExisting)
} else {
None
}
}
fn is_project_item(&self, _window: &Window, _cx: &App) -> bool {
true
}
}
impl Render for DebugSession {
fn render(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
match &self.mode {
DebugSessionState::Inert(inert_state) => {
inert_state.update(cx, |this, cx| this.render(window, cx).into_any_element())
}
DebugSessionState::Starting(starting_state) => {
starting_state.update(cx, |this, cx| this.render(window, cx).into_any_element())
}
DebugSessionState::Running(running_state) => {
running_state.update(cx, |this, cx| this.render(window, cx).into_any_element())
}
}
}
}

View File

@@ -0,0 +1,51 @@
use gpui::{App, FocusHandle, Focusable};
use ui::{
div, h_flex, v_flex, Button, ButtonCommon, ButtonStyle, Context, ContextMenu, DropdownMenu,
Element, InteractiveElement, ParentElement, Render, Styled,
};
pub(super) struct InertState {
focus_handle: FocusHandle,
}
impl InertState {
pub(super) fn new(cx: &mut Context<Self>) -> Self {
Self {
focus_handle: cx.focus_handle(),
}
}
}
impl Focusable for InertState {
fn focus_handle(&self, cx: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl Render for InertState {
fn render(
&mut self,
window: &mut ui::Window,
cx: &mut ui::Context<'_, Self>,
) -> impl ui::IntoElement {
v_flex()
.track_focus(&self.focus_handle)
.size_full()
.gap_1()
.p_1()
.child(h_flex().child(DropdownMenu::new(
"dap-adapter-picker",
"Select Debug Adapter",
ContextMenu::build(window, cx, |this, _, _| {
this.entry("GDB", None, |_, _| {})
.entry("Delve", None, |_, _| {})
.entry("LLDB", None, |_, _| {})
}),
)))
.child(
h_flex()
.gap_1()
.child(Button::new("launch-dap", "Launch").style(ButtonStyle::Filled))
.child(Button::new("attach-dap", "Attach").style(ButtonStyle::Filled)),
)
}
}

View File

@@ -1,9 +1,9 @@
use crate::{ use super::{
stack_frame_list::{StackFrameList, StackFrameListEvent}, stack_frame_list::{StackFrameList, StackFrameListEvent},
variable_list::VariableList, variable_list::VariableList,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use dap::{client::DebugAdapterClientId, OutputEvent, OutputEventGroup}; use dap::{client::SessionId, OutputEvent, OutputEventGroup};
use editor::{ use editor::{
display_map::{Crease, CreaseId}, display_map::{Crease, CreaseId},
Anchor, CompletionProvider, Editor, EditorElement, EditorStyle, FoldPlaceholder, Anchor, CompletionProvider, Editor, EditorElement, EditorStyle, FoldPlaceholder,
@@ -13,7 +13,7 @@ use gpui::{Context, Entity, Render, Subscription, Task, TextStyle, WeakEntity};
use language::{Buffer, CodeLabel, LanguageServerId}; use language::{Buffer, CodeLabel, LanguageServerId};
use menu::Confirm; use menu::Confirm;
use project::{ use project::{
debugger::dap_session::{CompletionsQuery, DebugSession}, debugger::session::{CompletionsQuery, Session},
Completion, Completion,
}; };
use settings::Settings; use settings::Settings;
@@ -33,8 +33,8 @@ pub struct Console {
groups: Vec<OutputGroup>, groups: Vec<OutputGroup>,
console: Entity<Editor>, console: Entity<Editor>,
query_bar: Entity<Editor>, query_bar: Entity<Editor>,
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
variable_list: Entity<VariableList>, variable_list: Entity<VariableList>,
stack_frame_list: Entity<StackFrameList>, stack_frame_list: Entity<StackFrameList>,
@@ -42,8 +42,8 @@ pub struct Console {
impl Console { impl Console {
pub fn new( pub fn new(
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
stack_frame_list: Entity<StackFrameList>, stack_frame_list: Entity<StackFrameList>,
variable_list: Entity<VariableList>, variable_list: Entity<VariableList>,
window: &mut Window, window: &mut Window,
@@ -234,11 +234,7 @@ impl Console {
expression expression
}); });
let Some(client_state) = self.session.read(cx).client_state(self.client_id) else { self.session.update(cx, |state, cx| {
return;
};
client_state.update(cx, |state, cx| {
state.evaluate( state.evaluate(
expression, expression,
Some(dap::EvaluateArgumentsContext::Variables), Some(dap::EvaluateArgumentsContext::Variables),
@@ -369,10 +365,8 @@ impl CompletionProvider for ConsoleQueryBarCompletionProvider {
.read(cx) .read(cx)
.session .session
.read(cx) .read(cx)
.client_state(console.read(cx).client_id) .capabilities()
.map(|state| state.read(cx).capabilities()) .supports_completions_request
.map(|caps| caps.supports_completions_request)
.flatten()
.unwrap_or_default(); .unwrap_or_default();
if support_completions { if support_completions {
@@ -498,21 +492,15 @@ impl ConsoleQueryBarCompletionProvider {
buffer_position: language::Anchor, buffer_position: language::Anchor,
cx: &mut Context<Editor>, cx: &mut Context<Editor>,
) -> gpui::Task<gpui::Result<Vec<project::Completion>>> { ) -> gpui::Task<gpui::Result<Vec<project::Completion>>> {
let client_id = console.read(cx).client_id;
let completion_task = console.update(cx, |console, cx| { let completion_task = console.update(cx, |console, cx| {
if let Some(client_state) = console.session.read(cx).client_state(client_id) { console.session.update(cx, |state, cx| {
client_state.update(cx, |state, cx| { let frame_id = Some(console.stack_frame_list.read(cx).current_stack_frame_id());
let frame_id = Some(console.stack_frame_list.read(cx).current_stack_frame_id());
state.completions( state.completions(
CompletionsQuery::new(buffer.read(cx), buffer_position, frame_id), CompletionsQuery::new(buffer.read(cx), buffer_position, frame_id),
cx, cx,
) )
}) })
} else {
Task::ready(Err(anyhow!("failed to fetch completions")))
}
}); });
cx.background_executor().spawn(async move { cx.background_executor().spawn(async move {

View File

@@ -1,6 +1,6 @@
use dap::client::DebugAdapterClientId; use dap::client::SessionId;
use gpui::{list, AnyElement, Empty, Entity, FocusHandle, Focusable, ListState, Subscription}; use gpui::{list, AnyElement, Empty, Entity, FocusHandle, Focusable, ListState, Subscription};
use project::debugger::dap_session::DebugSession; use project::debugger::session::Session;
use ui::prelude::*; use ui::prelude::*;
use util::maybe; use util::maybe;
@@ -8,14 +8,14 @@ pub struct LoadedSourceList {
list: ListState, list: ListState,
focus_handle: FocusHandle, focus_handle: FocusHandle,
_subscription: Subscription, _subscription: Subscription,
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
} }
impl LoadedSourceList { impl LoadedSourceList {
pub fn new( pub fn new(
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Self { ) -> Self {
let weak_entity = cx.weak_entity(); let weak_entity = cx.weak_entity();
@@ -35,8 +35,7 @@ impl LoadedSourceList {
}, },
); );
let client_state = session.read(cx).client_state(client_id).unwrap(); let _subscription = cx.observe(&session, |loaded_source_list, state, cx| {
let _subscription = cx.observe(&client_state, |loaded_source_list, state, cx| {
let len = state.update(cx, |state, cx| state.loaded_sources(cx).len()); let len = state.update(cx, |state, cx| state.loaded_sources(cx).len());
loaded_source_list.list.reset(len); loaded_source_list.list.reset(len);
@@ -55,8 +54,6 @@ impl LoadedSourceList {
fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement { fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
let Some(source) = maybe!({ let Some(source) = maybe!({
self.session self.session
.read(cx)
.client_state(self.client_id)?
.update(cx, |state, cx| state.loaded_sources(cx).get(ix).cloned()) .update(cx, |state, cx| state.loaded_sources(cx).get(ix).cloned())
}) else { }) else {
return Empty.into_any(); return Empty.into_any();
@@ -92,11 +89,9 @@ impl Focusable for LoadedSourceList {
impl Render for LoadedSourceList { impl Render for LoadedSourceList {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if let Some(state) = self.session.read(cx).client_state(self.client_id) { self.session.update(cx, |state, cx| {
state.update(cx, |state, cx| { state.loaded_sources(cx);
state.loaded_sources(cx); });
});
}
div() div()
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)

View File

@@ -1,20 +1,20 @@
use dap::{client::DebugAdapterClientId, ModuleEvent}; use dap::{client::SessionId, ModuleEvent};
use gpui::{list, AnyElement, Empty, Entity, FocusHandle, Focusable, ListState, Subscription}; use gpui::{list, AnyElement, Empty, Entity, FocusHandle, Focusable, ListState, Subscription};
use project::debugger::dap_session::DebugSession; use project::debugger::session::Session;
use ui::prelude::*; use ui::prelude::*;
pub struct ModuleList { pub struct ModuleList {
list: ListState, list: ListState,
focus_handle: FocusHandle, focus_handle: FocusHandle,
_subscription: Subscription, _subscription: Subscription,
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
} }
impl ModuleList { impl ModuleList {
pub fn new( pub fn new(
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Self { ) -> Self {
let weak_entity = cx.weak_entity(); let weak_entity = cx.weak_entity();
@@ -32,9 +32,7 @@ impl ModuleList {
}, },
); );
let client_state = session.read(cx).client_state(client_id).unwrap(); let _subscription = cx.observe(&session, |module_list, state, cx| {
let _subscription = cx.observe(&client_state, |module_list, state, cx| {
let modules_len = state.update(cx, |state, cx| state.modules(cx).len()); let modules_len = state.update(cx, |state, cx| state.modules(cx).len());
module_list.list.reset(modules_len); module_list.list.reset(modules_len);
@@ -51,16 +49,13 @@ impl ModuleList {
} }
pub fn on_module_event(&mut self, event: &ModuleEvent, cx: &mut Context<Self>) { pub fn on_module_event(&mut self, event: &ModuleEvent, cx: &mut Context<Self>) {
if let Some(state) = self.session.read(cx).client_state(self.client_id) { self.session
state.update(cx, |state, cx| state.handle_module_event(event, cx)); .update(cx, |state, cx| state.handle_module_event(event, cx));
}
} }
fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement { fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
let Some(module) = maybe!({ let Some(module) = maybe!({
self.session self.session
.read(cx)
.client_state(self.client_id)?
.update(cx, |state, cx| state.modules(cx).get(ix).cloned()) .update(cx, |state, cx| state.modules(cx).get(ix).cloned())
}) else { }) else {
return Empty.into_any(); return Empty.into_any();
@@ -91,11 +86,9 @@ impl Focusable for ModuleList {
impl Render for ModuleList { impl Render for ModuleList {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if let Some(state) = self.session.read(cx).client_state(self.client_id) { self.session.update(cx, |state, cx| {
state.update(cx, |state, cx| { state.modules(cx);
state.modules(cx); });
});
}
div() div()
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)

View File

@@ -1,12 +1,13 @@
use std::path::Path; use std::path::Path;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use dap::client::DebugAdapterClientId; use dap::client::SessionId;
use gpui::{ use gpui::{
list, AnyElement, Entity, EventEmitter, FocusHandle, Focusable, ListState, Subscription, Task, list, AnyElement, Entity, EventEmitter, FocusHandle, Focusable, ListState, Subscription, Task,
WeakEntity, WeakEntity,
}; };
use project::debugger::dap_session::{DebugSession, StackFrame, ThreadId};
use project::debugger::session::{Session, StackFrame, ThreadId};
use project::ProjectPath; use project::ProjectPath;
use ui::{prelude::*, Tooltip}; use ui::{prelude::*, Tooltip};
use workspace::Workspace; use workspace::Workspace;
@@ -24,10 +25,9 @@ pub struct StackFrameList {
thread_id: ThreadId, thread_id: ThreadId,
focus_handle: FocusHandle, focus_handle: FocusHandle,
_subscription: Subscription, _subscription: Subscription,
session: Entity<DebugSession>, session: Entity<Session>,
entries: Vec<StackFrameEntry>, entries: Vec<StackFrameEntry>,
workspace: WeakEntity<Workspace>, workspace: WeakEntity<Workspace>,
client_id: DebugAdapterClientId,
current_stack_frame_id: StackFrameId, current_stack_frame_id: StackFrameId,
_fetch_stack_frames_task: Option<Task<Result<()>>>, _fetch_stack_frames_task: Option<Task<Result<()>>>,
} }
@@ -41,8 +41,7 @@ pub enum StackFrameEntry {
impl StackFrameList { impl StackFrameList {
pub fn new( pub fn new(
workspace: WeakEntity<Workspace>, workspace: WeakEntity<Workspace>,
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId,
thread_id: ThreadId, thread_id: ThreadId,
_window: &Window, _window: &Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -64,9 +63,7 @@ impl StackFrameList {
}, },
); );
let client_state = session.read(cx).client_state(client_id).unwrap(); let _subscription = cx.observe(&session, |stack_frame_list, state, cx| {
let _subscription = cx.observe(&client_state, |stack_frame_list, state, cx| {
let _frame_len = state.update(cx, |state, cx| { let _frame_len = state.update(cx, |state, cx| {
state.stack_frames(stack_frame_list.thread_id, cx).len() state.stack_frames(stack_frame_list.thread_id, cx).len()
}); });
@@ -79,7 +76,7 @@ impl StackFrameList {
session, session,
workspace, workspace,
thread_id, thread_id,
client_id,
focus_handle, focus_handle,
_subscription, _subscription,
entries: Default::default(), entries: Default::default(),
@@ -99,10 +96,7 @@ impl StackFrameList {
pub fn stack_frames(&self, cx: &mut App) -> Vec<StackFrame> { pub fn stack_frames(&self, cx: &mut App) -> Vec<StackFrame> {
self.session self.session
.read(cx) .update(cx, |this, cx| this.stack_frames(self.thread_id, cx))
.client_state(self.client_id)
.map(|state| state.update(cx, |client, cx| client.stack_frames(self.thread_id, cx)))
.unwrap_or_default()
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
@@ -267,11 +261,9 @@ impl StackFrameList {
} }
pub fn restart_stack_frame(&mut self, stack_frame_id: u64, cx: &mut Context<Self>) { pub fn restart_stack_frame(&mut self, stack_frame_id: u64, cx: &mut Context<Self>) {
if let Some(client_state) = self.session.read(cx).client_state(self.client_id) { self.session.update(cx, |state, cx| {
client_state.update(cx, |state, cx| { state.restart_stack_frame(stack_frame_id, cx)
state.restart_stack_frame(stack_frame_id, cx) });
});
}
} }
fn render_normal_entry( fn render_normal_entry(
@@ -291,8 +283,8 @@ impl StackFrameList {
let supports_frame_restart = self let supports_frame_restart = self
.session .session
.read(cx) .read(cx)
.client_state(self.client_id) .capabilities()
.and_then(|client| client.read(cx).capabilities().supports_restart_frame) .supports_restart_frame
.unwrap_or_default(); .unwrap_or_default();
let origin = stack_frame let origin = stack_frame

View File

@@ -1,8 +1,7 @@
use crate::stack_frame_list::{StackFrameId, StackFrameList, StackFrameListEvent}; use super::stack_frame_list::{StackFrameId, StackFrameList, StackFrameListEvent};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use dap::{ use dap::{
client::DebugAdapterClientId, proto_conversions::ProtoConversion, Scope, ScopePresentationHint, client::SessionId, proto_conversions::ProtoConversion, Scope, ScopePresentationHint, Variable,
Variable,
}; };
use editor::{actions::SelectAll, Editor, EditorEvent}; use editor::{actions::SelectAll, Editor, EditorEvent};
use gpui::{ use gpui::{
@@ -10,7 +9,7 @@ use gpui::{
FocusHandle, Focusable, Hsla, ListOffset, ListState, MouseDownEvent, Point, Subscription, Task, FocusHandle, Focusable, Hsla, ListOffset, ListState, MouseDownEvent, Point, Subscription, Task,
}; };
use menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev}; use menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev};
use project::debugger::dap_session::DebugSession; use project::debugger::session::Session;
use rpc::proto::{ use rpc::proto::{
self, DebuggerScopeVariableIndex, DebuggerVariableContainer, VariableListScopes, self, DebuggerScopeVariableIndex, DebuggerVariableContainer, VariableListScopes,
VariableListVariables, VariableListVariables,
@@ -330,8 +329,8 @@ pub struct VariableList {
list: ListState, list: ListState,
focus_handle: FocusHandle, focus_handle: FocusHandle,
open_entries: Vec<OpenEntry>, open_entries: Vec<OpenEntry>,
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
set_variable_editor: Entity<Editor>, set_variable_editor: Entity<Editor>,
selection: Option<VariableListEntry>, selection: Option<VariableListEntry>,
@@ -346,8 +345,8 @@ pub struct VariableList {
impl VariableList { impl VariableList {
pub fn new( pub fn new(
session: Entity<DebugSession>, session: Entity<Session>,
client_id: DebugAdapterClientId, client_id: SessionId,
stack_frame_list: Entity<StackFrameList>, stack_frame_list: Entity<StackFrameList>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@@ -842,20 +841,11 @@ impl VariableList {
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
let Some((support_set_variable, support_clipboard_context)) = self let caps = self.session.read(cx).capabilities();
.session let (support_set_variable, support_clipboard_context) = (
.read(cx) caps.supports_set_variable.unwrap_or_default(),
.client_state(self.client_id) caps.supports_clipboard_context.unwrap_or_default(),
.map(|state| state.read(cx).capabilities()) );
.map(|caps| {
(
caps.supports_set_variable.unwrap_or_default(),
caps.supports_clipboard_context.unwrap_or_default(),
)
})
else {
return;
};
let this = cx.entity(); let this = cx.entity();
@@ -874,12 +864,7 @@ impl VariableList {
window.handler_for(&this.clone(), move |this, _window, cx| { window.handler_for(&this.clone(), move |this, _window, cx| {
if support_clipboard_context { if support_clipboard_context {
let Some(client_state) = this.session.read(cx).client_state(this.client_id) this.session.update(cx, |state, cx| {
else {
return;
};
client_state.update(cx, |state, cx| {
state.evaluate( state.evaluate(
evaluate_name.clone().unwrap_or(variable_name.clone()), evaluate_name.clone().unwrap_or(variable_name.clone()),
Some(dap::EvaluateArgumentsContext::Clipboard), Some(dap::EvaluateArgumentsContext::Clipboard),
@@ -984,11 +969,7 @@ impl VariableList {
return cx.notify(); return cx.notify();
} }
let Some(client_state) = self.session.read(cx).client_state(self.client_id) else { self.session.update(cx, |state, cx| {
return;
};
client_state.update(cx, |state, cx| {
state.set_variable_value( state.set_variable_value(
set_variable_state.parent_variables_reference, set_variable_state.parent_variables_reference,
set_variable_state.name, set_variable_state.name,

View File

@@ -0,0 +1,22 @@
use gpui::{FocusHandle, Focusable};
use ui::{div, Element, ParentElement, Render, Styled};
pub(super) struct StartingState {
focus_handle: FocusHandle,
}
impl Focusable for StartingState {
fn focus_handle(&self, cx: &ui::App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl Render for StartingState {
fn render(
&mut self,
window: &mut ui::Window,
cx: &mut ui::Context<'_, Self>,
) -> impl ui::IntoElement {
div().size_full().child("Starting a debug adapter")
}
}

View File

@@ -4,7 +4,7 @@ use settings::SettingsStore;
use terminal_view::terminal_panel::TerminalPanel; use terminal_view::terminal_panel::TerminalPanel;
use workspace::Workspace; use workspace::Workspace;
use crate::{debugger_panel::DebugPanel, debugger_panel_item::DebugPanelItem}; use crate::{debugger_panel::DebugPanel, session::DebugSession};
mod attach_modal; mod attach_modal;
mod console; mod console;
@@ -62,7 +62,7 @@ pub async fn init_test_workspace(
pub fn active_debug_panel_item( pub fn active_debug_panel_item(
workspace: WindowHandle<Workspace>, workspace: WindowHandle<Workspace>,
cx: &mut TestAppContext, cx: &mut TestAppContext,
) -> Entity<DebugPanelItem> { ) -> Entity<DebugSession> {
workspace workspace
.update(cx, |workspace, _window, cx| { .update(cx, |workspace, _window, cx| {
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();

View File

@@ -1,6 +1,6 @@
use crate::*; use crate::*;
use dap::{ use dap::{
client::DebugAdapterClientId, client::SessionId,
requests::{ requests::{
Continue, Disconnect, Initialize, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace, Continue, Disconnect, Initialize, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace,
StartDebugging, StepBack, StepIn, StepOut, StartDebugging, StepBack, StepIn, StepOut,
@@ -759,7 +759,7 @@ async fn test_handle_start_debugging_reverse_request(
let second_client = project.update(cx, |_, cx| { let second_client = project.update(cx, |_, cx| {
session session
.read(cx) .read(cx)
.client_state(DebugAdapterClientId(1)) .client_state(SessionId(1))
.unwrap() .unwrap()
.read(cx) .read(cx)
.adapter_client() .adapter_client()

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
debugger_panel_item::ThreadItem, session::ThreadItem,
tests::{active_debug_panel_item, init_test, init_test_workspace}, tests::{active_debug_panel_item, init_test, init_test_workspace},
}; };
use dap::{ use dap::{

View File

@@ -13,5 +13,5 @@
pub mod breakpoint_store; pub mod breakpoint_store;
pub mod dap_command; pub mod dap_command;
pub mod dap_session;
pub mod dap_store; pub mod dap_store;
pub mod session;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,28 @@
use crate::project_settings::ProjectSettings;
use super::breakpoint_store::BreakpointStore;
use super::dap_command::{ use super::dap_command::{
self, ContinueCommand, DapCommand, DisconnectCommand, EvaluateCommand, NextCommand, self, ContinueCommand, DapCommand, DisconnectCommand, EvaluateCommand, Initialize,
PauseCommand, RestartCommand, RestartStackFrameCommand, ScopesCommand, SetVariableValueCommand, LocalDapCommand, NextCommand, PauseCommand, RestartCommand, RestartStackFrameCommand,
StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand, ScopesCommand, SetVariableValueCommand, StepBackCommand, StepCommand, StepInCommand,
TerminateThreadsCommand, VariablesCommand, StepOutCommand, TerminateCommand, TerminateThreadsCommand, VariablesCommand,
}; };
use super::dap_store::DapAdapterDelegate;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::{BTreeMap, HashMap, IndexMap}; use collections::{HashMap, IndexMap};
use dap::client::{DebugAdapterClient, DebugAdapterClientId}; use dap::adapters::{DapDelegate, DapStatus, DebugAdapterName};
use dap::client::{DebugAdapterClient, SessionId};
use dap::{ use dap::{
Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, SteppingGranularity, messages::Message, Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source,
SteppingGranularity,
}; };
use dap_adapters::build_adapter;
use futures::{future::Shared, FutureExt}; use futures::{future::Shared, FutureExt};
use gpui::{App, AppContext, Context, Entity, Task}; use gpui::{App, AppContext, AsyncApp, BackgroundExecutor, Context, Entity, Task};
use rpc::AnyProtoClient; use rpc::AnyProtoClient;
use serde_json::Value; use serde_json::Value;
use std::borrow::Borrow; use settings::Settings;
use std::path::PathBuf;
use std::u64; use std::u64;
use std::{ use std::{
any::Any, any::Any,
@@ -26,20 +34,6 @@ use task::DebugAdapterConfig;
use text::{PointUtf16, ToPointUtf16}; use text::{PointUtf16, ToPointUtf16};
use util::ResultExt; use util::ResultExt;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct DebugSessionId(pub usize);
impl DebugSessionId {
pub fn from_proto(session_id: u64) -> Self {
Self(session_id as usize)
}
pub fn to_proto(&self) -> u64 {
self.0 as u64
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)] #[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)]
#[repr(transparent)] #[repr(transparent)]
pub struct ThreadId(pub u64); pub struct ThreadId(pub u64);
@@ -123,7 +117,7 @@ impl From<dap::Thread> for Thread {
type UpstreamProjectId = u64; type UpstreamProjectId = u64;
pub struct RemoteConnection { struct RemoteConnection {
client: AnyProtoClient, client: AnyProtoClient,
upstream_project_id: UpstreamProjectId, upstream_project_id: UpstreamProjectId,
} }
@@ -132,52 +126,109 @@ impl RemoteConnection {
fn send_proto_client_request<R: DapCommand>( fn send_proto_client_request<R: DapCommand>(
&self, &self,
request: R, request: R,
client_id: DebugAdapterClientId, session_id: SessionId,
cx: &mut App, cx: &mut App,
) -> Task<Result<R::Response>> { ) -> Task<Result<R::Response>> {
let message = request.to_proto(client_id, self.upstream_project_id); let message = request.to_proto(session_id, self.upstream_project_id);
let upstream_client = self.client.clone(); let upstream_client = self.client.clone();
cx.background_executor().spawn(async move { cx.background_executor().spawn(async move {
let response = upstream_client.request(message).await?; let response = upstream_client.request(message).await?;
request.response_from_proto(response) request.response_from_proto(response)
}) })
} }
fn request_remote<R: DapCommand>( fn request<R: DapCommand>(
&self, &self,
request: R, request: R,
client_id: DebugAdapterClientId, session_id: SessionId,
cx: &mut App, cx: &mut App,
) -> Task<Result<R::Response>> ) -> Task<Result<R::Response>>
where where
<R::DapRequest as dap::requests::Request>::Response: 'static, <R::DapRequest as dap::requests::Request>::Response: 'static,
<R::DapRequest as dap::requests::Request>::Arguments: 'static + Send, <R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
{ {
return self.send_proto_client_request::<R>(request, client_id, cx); return self.send_proto_client_request::<R>(request, session_id, cx);
} }
} }
pub enum Mode { enum Mode {
Local(Arc<DebugAdapterClient>), Local(LocalMode),
Remote(RemoteConnection), Remote(RemoteConnection),
} }
impl From<RemoteConnection> for Mode { struct LocalMode {
fn from(value: RemoteConnection) -> Self { client: Arc<DebugAdapterClient>,
Self::Remote(value)
}
} }
impl From<Arc<DebugAdapterClient>> for Mode { impl LocalMode {
fn from(client: Arc<DebugAdapterClient>) -> Self { fn new<F>(
Mode::Local(client) session_id: SessionId,
} breakpoint_store: Entity<BreakpointStore>,
} disposition: DebugAdapterConfig,
delegate: DapAdapterDelegate,
message_handler: F,
cx: AsyncApp,
) -> Task<Result<(Self, Capabilities)>>
where
F: FnMut(Message, &mut App) + 'static + Send + Sync + Clone,
{
cx.spawn(move |mut cx| async move {
let adapter = build_adapter(&disposition.kind).await?;
impl Mode { let binary = cx.update(|cx| {
fn request_local<R: DapCommand>( let name = DebugAdapterName::from(adapter.name().as_ref());
connection: &Arc<DebugAdapterClient>,
ProjectSettings::get_global(cx)
.dap
.get(&name)
.and_then(|s| s.binary.as_ref().map(PathBuf::from))
})?;
let binary = match adapter
.get_binary(&delegate, &disposition, binary, &mut cx)
.await
{
Err(error) => {
delegate.update_status(
adapter.name(),
DapStatus::Failed {
error: error.to_string(),
},
);
return Err(error);
}
Ok(mut binary) => {
delegate.update_status(adapter.name(), DapStatus::None);
let shell_env = delegate.shell_env().await;
let mut envs = binary.envs.unwrap_or_default();
envs.extend(shell_env);
binary.envs = Some(envs);
binary
}
};
let client = Arc::new(
DebugAdapterClient::start(session_id, binary, message_handler, cx.clone()).await?,
);
let this = Self { client };
let capabilities = this
.request(
Initialize {
adapter_id: "zed-dap-this-value-needs-changing".to_owned(),
},
cx.background_executor().clone(),
)
.await?;
Ok((this, capabilities))
})
}
fn request<R: LocalDapCommand>(
&self,
request: R, request: R,
cx: &mut Context<Client>, executor: BackgroundExecutor,
) -> Task<Result<R::Response>> ) -> Task<Result<R::Response>>
where where
<R::DapRequest as dap::requests::Request>::Response: 'static, <R::DapRequest as dap::requests::Request>::Response: 'static,
@@ -186,23 +237,30 @@ impl Mode {
let request = Arc::new(request); let request = Arc::new(request);
let request_clone = request.clone(); let request_clone = request.clone();
let connection = connection.clone(); let connection = self.client.clone();
let request_task = cx.background_executor().spawn(async move { let request_task = executor.spawn(async move {
let args = request_clone.to_dap(); let args = request_clone.to_dap();
connection.request::<R::DapRequest>(args).await connection.request::<R::DapRequest>(args).await
}); });
cx.background_executor().spawn(async move { executor.spawn(async move {
let response = request.response_from_dap(request_task.await?); let response = request.response_from_dap(request_task.await?);
response response
}) })
} }
}
impl From<RemoteConnection> for Mode {
fn from(value: RemoteConnection) -> Self {
Self::Remote(value)
}
}
impl Mode {
fn request_dap<R: DapCommand>( fn request_dap<R: DapCommand>(
&self, &self,
client_id: DebugAdapterClientId, session_id: SessionId,
request: R, request: R,
cx: &mut Context<Client>, cx: &mut Context<Session>,
) -> Task<Result<R::Response>> ) -> Task<Result<R::Response>>
where where
<R::DapRequest as dap::requests::Request>::Response: 'static, <R::DapRequest as dap::requests::Request>::Response: 'static,
@@ -210,21 +268,20 @@ impl Mode {
{ {
match self { match self {
Mode::Local(debug_adapter_client) => { Mode::Local(debug_adapter_client) => {
Self::request_local(&debug_adapter_client, request, cx) debug_adapter_client.request(request, cx.background_executor().clone())
}
Mode::Remote(remote_connection) => {
remote_connection.request_remote(request, client_id, cx)
} }
Mode::Remote(remote_connection) => remote_connection.request(request, session_id, cx),
} }
} }
} }
/// Represents a current state of a single debug adapter and provides ways to mutate it. /// Represents a current state of a single debug adapter and provides ways to mutate it.
pub struct Client { pub struct Session {
mode: Mode, mode: Mode,
config: DebugAdapterConfig,
pub(super) capabilities: Capabilities, pub(super) capabilities: Capabilities,
client_id: DebugAdapterClientId, id: SessionId,
ignore_breakpoints: bool,
modules: Vec<dap::Module>, modules: Vec<dap::Module>,
loaded_sources: Vec<dap::Source>, loaded_sources: Vec<dap::Source>,
threads: IndexMap<ThreadId, Thread>, threads: IndexMap<ThreadId, Thread>,
@@ -306,10 +363,66 @@ impl CompletionsQuery {
} }
} }
impl Client { impl Session {
pub(crate) fn local(
breakpoints: Entity<BreakpointStore>,
session_id: SessionId,
delegate: DapAdapterDelegate,
config: DebugAdapterConfig,
cx: &mut App,
) -> Task<Result<Entity<Self>>> {
cx.spawn(move |mut cx| async move {
let (mode, capabilities) = LocalMode::new(
session_id,
breakpoints,
config.clone(),
delegate,
|_, _| {},
cx.clone(),
)
.await?;
cx.new(|_| Self {
mode: Mode::Local(mode),
id: session_id,
config,
capabilities,
ignore_breakpoints: false,
requests: HashMap::default(),
modules: Vec::default(),
loaded_sources: Vec::default(),
threads: IndexMap::default(),
})
})
}
pub(crate) fn remote(
session_id: SessionId,
client: AnyProtoClient,
upstream_project_id: u64,
ignore_breakpoints: bool,
) -> Self {
Self {
mode: Mode::Remote(RemoteConnection {
client,
upstream_project_id,
}),
id: session_id,
capabilities: Capabilities::default(),
ignore_breakpoints,
requests: HashMap::default(),
modules: Vec::default(),
loaded_sources: Vec::default(),
threads: IndexMap::default(),
config: todo!(),
}
}
pub fn capabilities(&self) -> &Capabilities { pub fn capabilities(&self) -> &Capabilities {
&self.capabilities &self.capabilities
} }
pub fn configuration(&self) -> DebugAdapterConfig {
self.config.clone()
}
pub(crate) fn _wait_for_request<R: DapCommand + PartialEq + Eq + Hash>( pub(crate) fn _wait_for_request<R: DapCommand + PartialEq + Eq + Hash>(
&self, &self,
@@ -331,7 +444,7 @@ impl Client {
let task = Self::request_inner::<Arc<T>>( let task = Self::request_inner::<Arc<T>>(
&self.capabilities, &self.capabilities,
self.client_id, self.id,
&self.mode, &self.mode,
command, command,
process_result, process_result,
@@ -351,7 +464,7 @@ impl Client {
fn request_inner<T: DapCommand + PartialEq + Eq + Hash>( fn request_inner<T: DapCommand + PartialEq + Eq + Hash>(
capabilities: &Capabilities, capabilities: &Capabilities,
client_id: DebugAdapterClientId, session_id: SessionId,
mode: &Mode, mode: &Mode,
request: T, request: T,
process_result: impl FnOnce(&mut Self, &T::Response, &mut Context<Self>) + 'static, process_result: impl FnOnce(&mut Self, &T::Response, &mut Context<Self>) + 'static,
@@ -360,7 +473,7 @@ impl Client {
if !T::is_supported(&capabilities) { if !T::is_supported(&capabilities) {
return Task::ready(None); return Task::ready(None);
} }
let request = mode.request_dap(client_id, request, cx); let request = mode.request_dap(session_id, request, cx);
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
let result = request.await.log_err()?; let result = request.await.log_err()?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
@@ -379,7 +492,7 @@ impl Client {
) -> Task<Option<T::Response>> { ) -> Task<Option<T::Response>> {
Self::request_inner( Self::request_inner(
&self.capabilities, &self.capabilities,
self.client_id, self.id,
&self.mode, &self.mode,
request, request,
process_result, process_result,
@@ -425,6 +538,12 @@ impl Client {
&self.modules &self.modules
} }
pub fn set_ignore_breakpoints(&mut self, ignore: bool) {
self.ignore_breakpoints = ignore;
}
pub fn breakpoints_enabled(&self) -> bool {
self.ignore_breakpoints
}
pub fn handle_module_event(&mut self, event: &dap::ModuleEvent, cx: &mut Context<Self>) { pub fn handle_module_event(&mut self, event: &dap::ModuleEvent, cx: &mut Context<Self>) {
match event.reason { match event.reason {
dap::ModuleEventReason::New => self.modules.push(event.module.clone()), dap::ModuleEventReason::New => self.modules.push(event.module.clone()),
@@ -496,7 +615,7 @@ impl Client {
} }
} }
fn shutdown(&mut self, cx: &mut Context<Self>) { pub(super) fn shutdown(&mut self, cx: &mut Context<Self>) {
if self if self
.capabilities .capabilities
.supports_terminate_request .supports_terminate_request
@@ -556,7 +675,7 @@ impl Client {
pub fn adapter_client(&self) -> Option<Arc<DebugAdapterClient>> { pub fn adapter_client(&self) -> Option<Arc<DebugAdapterClient>> {
match self.mode { match self.mode {
Mode::Local(ref adapter_client) => Some(adapter_client.clone()), Mode::Local(ref adapter_client) => Some(adapter_client.client.clone()),
Mode::Remote(_) => None, Mode::Remote(_) => None,
} }
} }
@@ -776,13 +895,11 @@ impl Client {
&mut self, &mut self,
thread_id: ThreadId, thread_id: ThreadId,
stack_frame_id: u64, stack_frame_id: u64,
session_id: DebugSessionId,
variables_reference: u64, variables_reference: u64,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Vec<Variable> { ) -> Vec<Variable> {
let command = VariablesCommand { let command = VariablesCommand {
stack_frame_id, stack_frame_id,
session_id,
thread_id: thread_id.0, thread_id: thread_id.0,
variables_reference, variables_reference,
filter: None, filter: None,
@@ -884,153 +1001,3 @@ impl Client {
} }
} }
} }
pub struct DebugSession {
id: DebugSessionId,
mode: DebugSessionMode,
pub(super) states: BTreeMap<DebugAdapterClientId, Entity<Client>>,
ignore_breakpoints: bool,
}
pub enum DebugSessionMode {
Local(LocalDebugSession),
Remote(RemoteDebugSession),
}
pub struct LocalDebugSession {
configuration: DebugAdapterConfig,
}
impl LocalDebugSession {
pub fn configuration(&self) -> &DebugAdapterConfig {
&self.configuration
}
pub fn update_configuration(
&mut self,
f: impl FnOnce(&mut DebugAdapterConfig),
cx: &mut Context<DebugSession>,
) {
f(&mut self.configuration);
cx.notify();
}
}
pub struct RemoteDebugSession {
label: String,
}
impl DebugSession {
pub fn new_local(id: DebugSessionId, configuration: DebugAdapterConfig) -> Self {
Self {
id,
ignore_breakpoints: false,
states: BTreeMap::default(),
mode: DebugSessionMode::Local(LocalDebugSession { configuration }),
}
}
pub fn as_local(&self) -> Option<&LocalDebugSession> {
match &self.mode {
DebugSessionMode::Local(local) => Some(local),
_ => None,
}
}
pub fn as_local_mut(&mut self) -> Option<&mut LocalDebugSession> {
match &mut self.mode {
DebugSessionMode::Local(local) => Some(local),
_ => None,
}
}
pub fn new_remote(id: DebugSessionId, label: String, ignore_breakpoints: bool) -> Self {
Self {
id,
ignore_breakpoints,
states: BTreeMap::default(),
mode: DebugSessionMode::Remote(RemoteDebugSession { label }),
}
}
pub fn id(&self) -> DebugSessionId {
self.id
}
pub fn name(&self) -> String {
match &self.mode {
DebugSessionMode::Local(local) => local.configuration.label.clone(),
DebugSessionMode::Remote(remote) => remote.label.clone(),
}
}
pub fn ignore_breakpoints(&self) -> bool {
self.ignore_breakpoints
}
pub fn set_ignore_breakpoints(&mut self, ignore: bool, cx: &mut Context<Self>) {
self.ignore_breakpoints = ignore;
cx.notify();
}
pub fn client_state(&self, client_id: DebugAdapterClientId) -> Option<Entity<Client>> {
self.states.get(&client_id).cloned()
}
pub(super) fn client_ids(&self) -> impl Iterator<Item = DebugAdapterClientId> + '_ {
self.states.keys().copied()
}
pub fn clients(&self, cx: &App) -> Vec<Arc<DebugAdapterClient>> {
self.states
.values()
.filter_map(|state| state.read(cx).adapter_client())
.collect()
}
pub fn add_client(
&mut self,
client: impl Into<Mode>,
client_id: DebugAdapterClientId,
cx: &mut Context<DebugSession>,
) {
if !self.states.contains_key(&client_id) {
let mode = client.into();
let state = cx.new(|_cx| Client {
client_id,
modules: Vec::default(),
loaded_sources: Vec::default(),
threads: IndexMap::default(),
requests: HashMap::default(),
capabilities: Default::default(),
mode,
});
self.states.insert(client_id, state);
}
}
pub(crate) fn client_by_id(
&self,
client_id: impl Borrow<DebugAdapterClientId>,
) -> Option<Entity<Client>> {
self.states.get(client_id.borrow()).cloned()
}
pub(crate) fn shutdown_client(
&mut self,
client_id: DebugAdapterClientId,
cx: &mut Context<Self>,
) {
if let Some(client) = self.states.remove(&client_id) {
client.update(cx, |this, cx| {
this.shutdown(cx);
})
}
}
#[cfg(any(test, feature = "test-support"))]
pub fn clients_len(&self) -> usize {
self.states.len()
}
}

View File

@@ -29,10 +29,7 @@ use git::Repository;
pub mod search_history; pub mod search_history;
mod yarn; mod yarn;
use crate::{ use crate::git::GitStore;
debugger::dap_session::{DebugSession, DebugSessionId},
git::GitStore,
};
use anyhow::{anyhow, Context as _, Result}; use anyhow::{anyhow, Context as _, Result};
use buffer_store::{BufferStore, BufferStoreEvent}; use buffer_store::{BufferStore, BufferStoreEvent};
@@ -42,7 +39,7 @@ use client::{
use clock::ReplicaId; use clock::ReplicaId;
use dap::{ use dap::{
client::{DebugAdapterClient, DebugAdapterClientId}, client::{DebugAdapterClient, SessionId},
debugger_settings::DebuggerSettings, debugger_settings::DebuggerSettings,
messages::Message, messages::Message,
DebugAdapterConfig, DebugAdapterConfig,
@@ -90,9 +87,7 @@ pub use prettier_store::PrettierStore;
use project_settings::{ProjectSettings, SettingsObserver, SettingsObserverEvent}; use project_settings::{ProjectSettings, SettingsObserver, SettingsObserverEvent};
use remote::{SshConnectionOptions, SshRemoteClient}; use remote::{SshConnectionOptions, SshRemoteClient};
use rpc::{ use rpc::{
proto::{ proto::{FromProto, LanguageServerPromptResponse, ToProto, SSH_PROJECT_ID},
FromProto, LanguageServerPromptResponse, SetDebuggerPanelItem, ToProto, SSH_PROJECT_ID,
},
AnyProtoClient, ErrorCode, AnyProtoClient, ErrorCode,
}; };
use search::{SearchInputKind, SearchQuery, SearchResult}; use search::{SearchInputKind, SearchQuery, SearchResult};
@@ -275,16 +270,14 @@ pub enum Event {
notification_id: SharedString, notification_id: SharedString,
}, },
LanguageServerPrompt(LanguageServerPromptRequest), LanguageServerPrompt(LanguageServerPromptRequest),
DebugClientStarted((DebugSessionId, DebugAdapterClientId)), DebugClientStarted(SessionId),
DebugClientShutdown(DebugAdapterClientId), DebugClientShutdown(SessionId),
SetDebugClient(SetDebuggerPanelItem),
ActiveDebugLineChanged, ActiveDebugLineChanged,
DebugClientEvent { DebugClientEvent {
session_id: DebugSessionId, session_id: SessionId,
client_id: DebugAdapterClientId,
message: Message, message: Message,
}, },
DebugClientLog(DebugAdapterClientId, String), DebugClientLog(SessionId, String),
LanguageNotFound(Entity<Buffer>), LanguageNotFound(Entity<Buffer>),
ActiveEntryChanged(Option<ProjectEntryId>), ActiveEntryChanged(Option<ProjectEntryId>),
ActivateProjectPanel, ActivateProjectPanel,
@@ -1090,7 +1083,7 @@ impl Project {
let breakpoint_store = cx.new(|cx| { let breakpoint_store = cx.new(|cx| {
let mut bp_store = { let mut bp_store = {
BreakpointStore::remote( BreakpointStore::remote(
SSH_PROJECT_ID, remote_id,
client.clone().into(), client.clone().into(),
buffer_store.clone(), buffer_store.clone(),
worktree_store.clone(), worktree_store.clone(),
@@ -1106,7 +1099,7 @@ impl Project {
let mut dap_store = let mut dap_store =
DapStore::new_remote(remote_id, client.clone().into(), breakpoint_store.clone()); DapStore::new_remote(remote_id, client.clone().into(), breakpoint_store.clone());
dap_store.request_active_debug_sessions(cx); unimplemented!("dap_store.request_active_debug_sessions(cx)");
dap_store dap_store
})?; })?;
@@ -1313,8 +1306,7 @@ impl Project {
pub fn initial_send_breakpoints( pub fn initial_send_breakpoints(
&self, &self,
session_id: &DebugSessionId, session_id: SessionId,
client_id: DebugAdapterClientId,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<()> { ) -> Task<()> {
let mut tasks = Vec::new(); let mut tasks = Vec::new();
@@ -1332,10 +1324,10 @@ impl Project {
tasks.push(self.dap_store.update(cx, |store, cx| { tasks.push(self.dap_store.update(cx, |store, cx| {
store.send_breakpoints( store.send_breakpoints(
client_id, session_id,
abs_path, abs_path,
source_breakpoints, source_breakpoints,
store.ignore_breakpoints(session_id, cx), store.ignore_breakpoints(&session_id, cx),
false, false,
cx, cx,
) )
@@ -1351,7 +1343,7 @@ impl Project {
&mut self, &mut self,
config: DebugAdapterConfig, config: DebugAdapterConfig,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<Result<(Entity<DebugSession>, Arc<DebugAdapterClient>)>> { ) -> Task<Result<Arc<DebugAdapterClient>>> {
let worktree = maybe!({ let worktree = maybe!({
if let Some(cwd) = &config.cwd { if let Some(cwd) = &config.cwd {
Some(self.find_worktree(cwd.as_path(), cx)?.0) Some(self.find_worktree(cwd.as_path(), cx)?.0)
@@ -1387,8 +1379,7 @@ impl Project {
if let Some((_, _)) = project.dap_store.read(cx).downstream_client() { if let Some((_, _)) = project.dap_store.read(cx).downstream_client() {
project project
.toggle_ignore_breakpoints( .toggle_ignore_breakpoints(
&DebugSessionId::from_proto(envelope.payload.session_id), SessionId::from_proto(envelope.payload.client_id),
DebugAdapterClientId::from_proto(envelope.payload.client_id),
cx, cx,
) )
.detach_and_log_err(cx); .detach_and_log_err(cx);
@@ -1398,16 +1389,14 @@ impl Project {
pub fn toggle_ignore_breakpoints( pub fn toggle_ignore_breakpoints(
&self, &self,
session_id: &DebugSessionId, session_id: SessionId,
client_id: DebugAdapterClientId,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<Result<()>> { ) -> Task<Result<()>> {
let tasks = self.dap_store.update(cx, |store, cx| { let tasks = self.dap_store.update(cx, |store, cx| {
if let Some((upstream_client, project_id)) = store.upstream_client() { if let Some((upstream_client, project_id)) = store.upstream_client() {
upstream_client upstream_client
.send(proto::ToggleIgnoreBreakpoints { .send(proto::ToggleIgnoreBreakpoints {
session_id: session_id.to_proto(), client_id: session_id.to_proto(),
client_id: client_id.to_proto(),
project_id, project_id,
}) })
.log_err(); .log_err();
@@ -1415,14 +1404,14 @@ impl Project {
return Vec::new(); return Vec::new();
} }
store.toggle_ignore_breakpoints(session_id, cx); store.toggle_ignore_breakpoints(&session_id, cx);
if let Some((downstream_client, project_id)) = store.downstream_client() { if let Some((downstream_client, project_id)) = store.downstream_client() {
downstream_client downstream_client
.send(proto::IgnoreBreakpointState { .send(proto::IgnoreBreakpointState {
session_id: session_id.to_proto(), session_id: session_id.to_proto(),
project_id: *project_id, project_id: *project_id,
ignore: store.ignore_breakpoints(session_id, cx), ignore: store.ignore_breakpoints(&session_id, cx),
}) })
.log_err(); .log_err();
} }
@@ -1448,13 +1437,13 @@ impl Project {
tasks.push( tasks.push(
store.send_breakpoints( store.send_breakpoints(
client_id, session_id,
Arc::from(buffer_path), Arc::from(buffer_path),
breakpoints breakpoints
.into_iter() .into_iter()
.map(|breakpoint| breakpoint.to_source_breakpoint(buffer)) .map(|breakpoint| breakpoint.to_source_breakpoint(buffer))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
store.ignore_breakpoints(session_id, cx), store.ignore_breakpoints(&session_id, cx),
false, false,
cx, cx,
), ),
@@ -2666,20 +2655,18 @@ impl Project {
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
match event { match event {
DapStoreEvent::DebugClientStarted(client_id) => { DapStoreEvent::DebugClientStarted(session_id) => {
cx.emit(Event::DebugClientStarted(*client_id)); cx.emit(Event::DebugClientStarted(*session_id));
} }
DapStoreEvent::DebugClientShutdown(client_id) => { DapStoreEvent::DebugClientShutdown(session_id) => {
cx.emit(Event::DebugClientShutdown(*client_id)); cx.emit(Event::DebugClientShutdown(*session_id));
} }
DapStoreEvent::DebugClientEvent { DapStoreEvent::DebugClientEvent {
session_id, session_id,
client_id,
message, message,
} => { } => {
cx.emit(Event::DebugClientEvent { cx.emit(Event::DebugClientEvent {
session_id: *session_id, session_id: *session_id,
client_id: *client_id,
message: message.clone(), message: message.clone(),
}); });
} }

View File

@@ -327,48 +327,42 @@ message Envelope {
SynchronizeBreakpoints synchronize_breakpoints = 304; SynchronizeBreakpoints synchronize_breakpoints = 304;
SetActiveDebugLine set_active_debug_line = 305; SetActiveDebugLine set_active_debug_line = 305;
RemoveActiveDebugLine remove_active_debug_line = 306; RemoveActiveDebugLine remove_active_debug_line = 306;
SetDebuggerPanelItem set_debugger_panel_item = 307; UpdateDebugAdapter update_debug_adapter = 307;
UpdateDebugAdapter update_debug_adapter = 308; ShutdownDebugClient shutdown_debug_client = 308;
ShutdownDebugClient shutdown_debug_client = 309; SetDebugClientCapabilities set_debug_client_capabilities = 309;
SetDebugClientCapabilities set_debug_client_capabilities = 310; DapNextRequest dap_next_request = 310;
DapStepInRequest dap_step_in_request = 311;
DapNextRequest dap_next_request = 311; DapStepOutRequest dap_step_out_request = 312;
DapStepInRequest dap_step_in_request = 312; DapStepBackRequest dap_step_back_request = 313;
DapStepOutRequest dap_step_out_request = 313; DapContinueRequest dap_continue_request = 314;
DapStepBackRequest dap_step_back_request = 314; DapContinueResponse dap_continue_response = 315;
DapContinueRequest dap_continue_request = 315; DapPauseRequest dap_pause_request = 316;
DapContinueResponse dap_continue_response = 316; DapDisconnectRequest dap_disconnect_request = 317;
DapPauseRequest dap_pause_request = 317; DapTerminateThreadsRequest dap_terminate_threads_request = 318;
DapDisconnectRequest dap_disconnect_request = 318; DapTerminateRequest dap_terminate_request = 319;
DapTerminateThreadsRequest dap_terminate_threads_request = 319; DapRestartRequest dap_restart_request = 320;
DapTerminateRequest dap_terminate_request = 320; UpdateThreadStatus update_thread_status = 321;
DapRestartRequest dap_restart_request = 321; VariablesRequest variables_request = 322;
DapShutdownSession dap_shutdown_session = 322; DapVariables dap_variables = 323;
UpdateThreadStatus update_thread_status = 323; DapRestartStackFrameRequest dap_restart_stack_frame_request = 324;
VariablesRequest variables_request = 324; IgnoreBreakpointState ignore_breakpoint_state = 325;
DapVariables dap_variables = 325; ToggleIgnoreBreakpoints toggle_ignore_breakpoints = 326;
DapRestartStackFrameRequest dap_restart_stack_frame_request = 326; DapModulesRequest dap_modules_request = 327;
IgnoreBreakpointState ignore_breakpoint_state = 327; DapModulesResponse dap_modules_response = 328;
ToggleIgnoreBreakpoints toggle_ignore_breakpoints = 328; DapLoadedSourcesRequest dap_loaded_sources_request = 329;
DebuggerSessionEnded debugger_session_ended = 329; DapLoadedSourcesResponse dap_loaded_sources_response = 330;
DapModulesRequest dap_modules_request = 330; DapStackTraceRequest dap_stack_trace_request = 331;
DapModulesResponse dap_modules_response = 331; DapStackTraceResponse dap_stack_trace_response = 332;
DapLoadedSourcesRequest dap_loaded_sources_request = 332; DapScopesRequest dap_scopes_request = 333;
DapLoadedSourcesResponse dap_loaded_sources_response = 333; DapScopesResponse dap_scopes_response = 334;
ActiveDebugSessionsRequest active_debug_sessions_request = 334; DapSetVariableValueRequest dap_set_variable_value_request = 335;
ActiveDebugSessionsResponse active_debug_sessions_response = 335; DapSetVariableValueResponse dap_set_variable_value_response = 336;
DapStackTraceRequest dap_stack_trace_request = 336; DapEvaluateRequest dap_evaluate_request = 337;
DapStackTraceResponse dap_stack_trace_response = 337; DapEvaluateResponse dap_evaluate_response = 338;
DapScopesRequest dap_scopes_request = 338; DapCompletionRequest dap_completion_request = 339;
DapScopesResponse dap_scopes_response = 339; DapCompletionResponse dap_completion_response = 340;
DapSetVariableValueRequest dap_set_variable_value_request = 340; DapThreadsRequest dap_threads_request = 341;
DapSetVariableValueResponse dap_set_variable_value_response = 341; DapThreadsResponse dap_threads_response = 342;// current max
DapEvaluateRequest dap_evaluate_request = 342;
DapEvaluateResponse dap_evaluate_response = 343;
DapCompletionRequest dap_completion_request = 344;
DapCompletionResponse dap_completion_response = 345;
DapThreadsRequest dap_threads_request = 346;
DapThreadsResponse dap_threads_response = 347; // current max
} }
reserved 87 to 88; reserved 87 to 88;
@@ -2561,51 +2555,35 @@ enum BreakpointKind {
Log = 1; Log = 1;
} }
message DebuggerSessionEnded {
uint64 project_id = 1;
uint64 session_id = 2;
}
message ActiveDebugSessionsRequest { message ActiveDebugClientsResponse {
uint64 project_id = 1; repeated DebugClient clients = 1;
}
message ActiveDebugSessionsResponse {
repeated DebuggerSession sessions = 1;
}
message DebuggerSession {
uint64 session_id = 1;
bool ignore_breakpoints = 2;
repeated DebugClient clients = 3;
} }
message DebugClient { message DebugClient {
uint64 client_id = 1; uint64 client_id = 1;
SetDebugClientCapabilities capabilities = 2; SetDebugClientCapabilities capabilities = 2;
repeated SetDebuggerPanelItem debug_panel_items = 3; bool ignore_breakpoints = 3;
} }
message ShutdownDebugClient { message ShutdownDebugClient {
uint64 session_id = 1; uint64 project_id = 1;
uint64 client_id = 2; uint64 session_id = 2;
uint64 project_id = 3;
} }
message SetDebugClientCapabilities { message SetDebugClientCapabilities {
uint64 session_id = 1; uint64 session_id = 1;
uint64 client_id = 2; uint64 project_id = 2;
uint64 project_id = 3; bool supports_loaded_sources_request = 3;
bool supports_loaded_sources_request = 4; bool supports_modules_request = 4;
bool supports_modules_request = 5; bool supports_restart_request = 5;
bool supports_restart_request = 6; bool supports_set_expression = 6;
bool supports_set_expression = 7; bool supports_single_thread_execution_requests = 7;
bool supports_single_thread_execution_requests = 8; bool supports_step_back = 8;
bool supports_step_back = 9; bool supports_stepping_granularity = 9;
bool supports_stepping_granularity = 10; bool supports_terminate_threads_request = 10;
bool supports_terminate_threads_request = 11; bool supports_restart_frame_request = 11;
bool supports_restart_frame_request = 12; bool supports_clipboard_context = 12;
bool supports_clipboard_context = 13;
} }
message Breakpoint { message Breakpoint {
@@ -2624,7 +2602,7 @@ message SynchronizeBreakpoints {
message SetActiveDebugLine { message SetActiveDebugLine {
uint64 project_id = 1; uint64 project_id = 1;
ProjectPath project_path = 2; ProjectPath project_path = 2;
uint64 client_id = 3; uint64 session_id = 3;
uint32 row = 4; uint32 row = 4;
} }
@@ -2737,13 +2715,12 @@ message VariablesRequest {
uint64 project_id = 1; uint64 project_id = 1;
uint64 client_id = 2; uint64 client_id = 2;
uint64 thread_id = 3; uint64 thread_id = 3;
uint64 session_id = 4; uint64 stack_frame_id = 4;
uint64 stack_frame_id = 5; uint64 variables_reference = 5;
uint64 variables_reference = 6; optional VariablesArgumentsFilter filter = 6;
optional VariablesArgumentsFilter filter = 7; optional uint64 start = 7;
optional uint64 start = 8; optional uint64 count = 8;
optional uint64 count = 9; optional ValueFormat format = 9;
optional ValueFormat format = 10;
} }
@@ -2911,15 +2888,9 @@ message DapRestartStackFrameRequest {
uint64 stack_frame_id = 3; uint64 stack_frame_id = 3;
} }
message DapShutdownSession {
uint64 project_id = 1;
optional uint64 session_id = 2; // Shutdown all sessions if this is None
}
message ToggleIgnoreBreakpoints { message ToggleIgnoreBreakpoints {
uint64 project_id = 1; uint64 project_id = 1;
uint64 client_id = 2; uint64 client_id = 2;
uint64 session_id = 3;
} }
message IgnoreBreakpointState { message IgnoreBreakpointState {
@@ -3033,26 +3004,10 @@ message DebuggerModuleList {
uint64 client_id = 2; uint64 client_id = 2;
} }
message SetDebuggerPanelItem {
uint64 project_id = 1;
uint64 session_id = 2;
uint64 client_id = 3;
uint64 thread_id = 4;
string session_name = 5;
DebuggerConsole console = 6;
optional DebuggerModuleList module_list = 7; // We only send this when it's supported and once per client
DebuggerThreadItem active_thread_item = 8;
DebuggerThreadState thread_state = 9;
DebuggerVariableList variable_list = 10;
DebuggerStackFrameList stack_frame_list = 11;
DebuggerLoadedSourceList loaded_source_list = 12;
}
message UpdateDebugAdapter { message UpdateDebugAdapter {
uint64 project_id = 1; uint64 project_id = 1;
uint64 client_id = 2; uint64 client_id = 2;
optional uint64 thread_id = 3; optional uint64 thread_id = 3;
uint64 session_id = 4;
oneof variant { oneof variant {
DebuggerThreadState thread_state = 5; DebuggerThreadState thread_state = 5;
DebuggerStackFrameList stack_frame_list = 6; DebuggerStackFrameList stack_frame_list = 6;
@@ -3062,8 +3017,6 @@ message UpdateDebugAdapter {
} }
} }
message DapVariables { message DapVariables {
uint64 client_id = 1; uint64 client_id = 1;
repeated DapVariable variables = 2; repeated DapVariable variables = 2;

View File

@@ -249,11 +249,9 @@ messages!(
(DapPauseRequest, Background), (DapPauseRequest, Background),
(DapRestartRequest, Background), (DapRestartRequest, Background),
(DapRestartStackFrameRequest, Background), (DapRestartStackFrameRequest, Background),
(DapShutdownSession, Background),
(DapStepBackRequest, Background), (DapStepBackRequest, Background),
(DapStepInRequest, Background), (DapStepInRequest, Background),
(DapStepOutRequest, Background), (DapStepOutRequest, Background),
(DapTerminateRequest, Background),
(DapTerminateThreadsRequest, Background), (DapTerminateThreadsRequest, Background),
(DeclineCall, Foreground), (DeclineCall, Foreground),
(DeleteChannel, Foreground), (DeleteChannel, Foreground),
@@ -416,7 +414,6 @@ messages!(
(SetChannelMemberRole, Foreground), (SetChannelMemberRole, Foreground),
(SetChannelVisibility, Foreground), (SetChannelVisibility, Foreground),
(SetDebugClientCapabilities, Background), (SetDebugClientCapabilities, Background),
(SetDebuggerPanelItem, Background),
(SetRoomParticipantRole, Foreground), (SetRoomParticipantRole, Foreground),
(ShareProject, Foreground), (ShareProject, Foreground),
(ShareProjectResponse, Foreground), (ShareProjectResponse, Foreground),
@@ -474,9 +471,6 @@ messages!(
(DapVariables, Background), (DapVariables, Background),
(IgnoreBreakpointState, Background), (IgnoreBreakpointState, Background),
(ToggleIgnoreBreakpoints, Background), (ToggleIgnoreBreakpoints, Background),
(DebuggerSessionEnded, Background),
(ActiveDebugSessionsRequest, Foreground),
(ActiveDebugSessionsResponse, Foreground),
(DapStackTraceRequest, Background), (DapStackTraceRequest, Background),
(DapStackTraceResponse, Background), (DapStackTraceResponse, Background),
(DapScopesRequest, Background), (DapScopesRequest, Background),
@@ -489,6 +483,7 @@ messages!(
(DapCompletionResponse, Background), (DapCompletionResponse, Background),
(DapThreadsRequest, Background), (DapThreadsRequest, Background),
(DapThreadsResponse, Background), (DapThreadsResponse, Background),
(DapTerminateRequest, Background)
); );
request_messages!( request_messages!(
@@ -636,18 +631,17 @@ request_messages!(
(DapPauseRequest, Ack), (DapPauseRequest, Ack),
(DapDisconnectRequest, Ack), (DapDisconnectRequest, Ack),
(DapTerminateThreadsRequest, Ack), (DapTerminateThreadsRequest, Ack),
(DapTerminateRequest, Ack),
(DapRestartRequest, Ack), (DapRestartRequest, Ack),
(DapRestartStackFrameRequest, Ack), (DapRestartStackFrameRequest, Ack),
(DapShutdownSession, Ack),
(VariablesRequest, DapVariables), (VariablesRequest, DapVariables),
(ActiveDebugSessionsRequest, ActiveDebugSessionsResponse),
(DapStackTraceRequest, DapStackTraceResponse), (DapStackTraceRequest, DapStackTraceResponse),
(DapScopesRequest, DapScopesResponse), (DapScopesRequest, DapScopesResponse),
(DapSetVariableValueRequest, DapSetVariableValueResponse), (DapSetVariableValueRequest, DapSetVariableValueResponse),
(DapEvaluateRequest, DapEvaluateResponse), (DapEvaluateRequest, DapEvaluateResponse),
(DapCompletionRequest, DapCompletionResponse), (DapCompletionRequest, DapCompletionResponse),
(DapThreadsRequest, DapThreadsResponse), (DapThreadsRequest, DapThreadsResponse),
(DapTerminateRequest, Ack),
(ShutdownDebugClient, Ack),
); );
entity_messages!( entity_messages!(
@@ -748,7 +742,6 @@ entity_messages!(
SynchronizeBreakpoints, SynchronizeBreakpoints,
SetActiveDebugLine, SetActiveDebugLine,
RemoveActiveDebugLine, RemoveActiveDebugLine,
SetDebuggerPanelItem,
ShutdownDebugClient, ShutdownDebugClient,
SetDebugClientCapabilities, SetDebugClientCapabilities,
DapNextRequest, DapNextRequest,
@@ -759,22 +752,19 @@ entity_messages!(
DapPauseRequest, DapPauseRequest,
DapDisconnectRequest, DapDisconnectRequest,
DapTerminateThreadsRequest, DapTerminateThreadsRequest,
DapTerminateRequest,
DapRestartRequest, DapRestartRequest,
DapRestartStackFrameRequest, DapRestartStackFrameRequest,
DapShutdownSession,
UpdateThreadStatus, UpdateThreadStatus,
VariablesRequest, VariablesRequest,
IgnoreBreakpointState, IgnoreBreakpointState,
ToggleIgnoreBreakpoints, ToggleIgnoreBreakpoints,
DebuggerSessionEnded,
ActiveDebugSessionsRequest,
DapStackTraceRequest, DapStackTraceRequest,
DapScopesRequest, DapScopesRequest,
DapSetVariableValueRequest, DapSetVariableValueRequest,
DapEvaluateRequest, DapEvaluateRequest,
DapCompletionRequest, DapCompletionRequest,
DapThreadsRequest, DapThreadsRequest,
DapTerminateRequest
); );
entity_messages!( entity_messages!(

View File

@@ -131,6 +131,8 @@ pub struct DebugAdapterConfig {
pub cwd: Option<PathBuf>, pub cwd: Option<PathBuf>,
/// Additional initialization arguments to be sent on DAP initialization /// Additional initialization arguments to be sent on DAP initialization
pub initialize_args: Option<serde_json::Value>, pub initialize_args: Option<serde_json::Value>,
/// Whether the debug adapter supports attaching to a running process.
pub supports_attach: bool,
} }
/// Represents the type of the debugger adapter connection /// Represents the type of the debugger adapter connection
@@ -176,6 +178,7 @@ impl DebugTaskDefinition {
program: self.program, program: self.program,
cwd: cwd.clone(), cwd: cwd.clone(),
initialize_args: self.initialize_args, initialize_args: self.initialize_args,
supports_attach: true,
}); });
let args: Vec<String> = Vec::new(); let args: Vec<String> = Vec::new();