Merge pull request #115 from zed-industries/remove-dap-session
Remove dap session
This commit is contained in:
@@ -429,7 +429,6 @@ impl Server {
|
||||
.add_message_handler(
|
||||
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::SetDebugClientCapabilities>,
|
||||
|
||||
@@ -5,7 +5,7 @@ use dap::{
|
||||
SourceBreakpoint, StackFrame,
|
||||
};
|
||||
use debugger_ui::debugger_panel::DebugPanel;
|
||||
use debugger_ui::debugger_panel_item::DebugPanelItem;
|
||||
use debugger_ui::session::DebugSession;
|
||||
use editor::Editor;
|
||||
use gpui::{Entity, TestAppContext, VisualTestContext};
|
||||
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(
|
||||
workspace: Entity<Workspace>,
|
||||
cx: &mut VisualTestContext,
|
||||
) -> Entity<DebugPanelItem> {
|
||||
) -> Entity<DebugSession> {
|
||||
workspace.update_in(cx, |workspace, _window, cx| {
|
||||
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
|
||||
debug_panel
|
||||
@@ -1251,9 +1251,7 @@ async fn test_module_list(
|
||||
debug_panel_item.update(cx, |item, cx| {
|
||||
assert_eq!(
|
||||
true,
|
||||
item.capabilities(cx)
|
||||
.and_then(|caps| caps.supports_modules_request)
|
||||
.unwrap(),
|
||||
item.capabilities(cx).supports_modules_request.unwrap(),
|
||||
"Local supports modules request should be true"
|
||||
);
|
||||
|
||||
@@ -1281,9 +1279,7 @@ async fn test_module_list(
|
||||
debug_panel_item.update(cx, |item, cx| {
|
||||
assert_eq!(
|
||||
true,
|
||||
item.capabilities(cx)
|
||||
.and_then(|caps| caps.supports_modules_request)
|
||||
.unwrap(),
|
||||
item.capabilities(cx).supports_modules_request.unwrap(),
|
||||
"Remote capabilities supports modules request should be true"
|
||||
);
|
||||
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| {
|
||||
assert_eq!(
|
||||
true,
|
||||
item.capabilities(cx)
|
||||
.and_then(|caps| caps.supports_modules_request)
|
||||
.unwrap(),
|
||||
item.capabilities(cx).supports_modules_request.unwrap(),
|
||||
"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));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use crate::transport::FakeTransport;
|
||||
use crate::transport::Transport;
|
||||
use ::fs::Fs;
|
||||
use anyhow::{anyhow, Context as _, Ok, Result};
|
||||
use async_compression::futures::bufread::GzipDecoder;
|
||||
@@ -19,9 +18,11 @@ use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
ffi::{OsStr, OsString},
|
||||
fmt::Debug,
|
||||
net::Ipv4Addr,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use sysinfo::{Pid, Process};
|
||||
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)]
|
||||
pub struct DebugAdapterBinary {
|
||||
pub command: String,
|
||||
pub arguments: Option<Vec<OsString>>,
|
||||
pub envs: Option<HashMap<String, String>>,
|
||||
pub cwd: Option<PathBuf>,
|
||||
pub connection: Option<TcpArguments>,
|
||||
}
|
||||
|
||||
pub struct AdapterVersion {
|
||||
@@ -261,8 +269,6 @@ pub trait DebugAdapter: 'static + Send + Sync {
|
||||
.await
|
||||
}
|
||||
|
||||
fn transport(&self) -> Arc<dyn Transport>;
|
||||
|
||||
async fn fetch_latest_adapter_version(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
@@ -288,12 +294,6 @@ pub trait DebugAdapter: 'static + Send + Sync {
|
||||
/// Should return base configuration to make the debug adapter work
|
||||
fn request_args(&self, config: &DebugAdapterConfig) -> Value;
|
||||
|
||||
/// Whether the adapter supports `attach` request,
|
||||
/// if not support and the request is selected we will show an error message
|
||||
fn supports_attach(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Filters out the processes that the adapter can attach to for debugging
|
||||
fn attach_processes<'a>(
|
||||
&self,
|
||||
@@ -322,10 +322,6 @@ impl DebugAdapter for FakeAdapter {
|
||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||
}
|
||||
|
||||
fn transport(&self) -> Arc<dyn Transport> {
|
||||
Arc::new(FakeTransport::new())
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
@@ -336,6 +332,11 @@ impl DebugAdapter for FakeAdapter {
|
||||
Ok(DebugAdapterBinary {
|
||||
command: "command".into(),
|
||||
arguments: None,
|
||||
connection: Some(TcpArguments {
|
||||
host: Ipv4Addr::LOCALHOST,
|
||||
port: None,
|
||||
timeout: None,
|
||||
}),
|
||||
envs: None,
|
||||
cwd: None,
|
||||
})
|
||||
@@ -383,10 +384,6 @@ impl DebugAdapter for FakeAdapter {
|
||||
})
|
||||
}
|
||||
|
||||
fn supports_attach(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn attach_processes<'a>(
|
||||
&self,
|
||||
processes: &'a HashMap<Pid, Process>,
|
||||
|
||||
@@ -27,9 +27,9 @@ const DAP_REQUEST_TIMEOUT: Duration = Duration::from_secs(12);
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct DebugAdapterClientId(pub u32);
|
||||
pub struct SessionId(pub u32);
|
||||
|
||||
impl DebugAdapterClientId {
|
||||
impl SessionId {
|
||||
pub fn from_proto(client_id: u64) -> Self {
|
||||
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.
|
||||
pub struct DebugAdapterClient {
|
||||
id: DebugAdapterClientId,
|
||||
id: SessionId,
|
||||
sequence_count: AtomicU64,
|
||||
binary: DebugAdapterBinary,
|
||||
executor: BackgroundExecutor,
|
||||
adapter: Arc<dyn DebugAdapter>,
|
||||
transport_delegate: TransportDelegate,
|
||||
}
|
||||
|
||||
impl DebugAdapterClient {
|
||||
pub fn new(
|
||||
id: DebugAdapterClientId,
|
||||
adapter: Arc<dyn DebugAdapter>,
|
||||
pub async fn start<F>(
|
||||
id: SessionId,
|
||||
binary: DebugAdapterBinary,
|
||||
cx: &AsyncApp,
|
||||
) -> Self {
|
||||
let transport_delegate = TransportDelegate::new(adapter.transport());
|
||||
|
||||
Self {
|
||||
message_handler: F,
|
||||
cx: AsyncApp,
|
||||
) -> Result<Self>
|
||||
where
|
||||
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,
|
||||
binary,
|
||||
adapter,
|
||||
transport_delegate,
|
||||
sequence_count: AtomicU64::new(1),
|
||||
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");
|
||||
|
||||
let client_id = self.id;
|
||||
let client_id = this.id;
|
||||
|
||||
// start handling events/reverse requests
|
||||
cx.update(|cx| {
|
||||
@@ -121,11 +87,13 @@ impl DebugAdapterClient {
|
||||
}
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
|
||||
this
|
||||
})
|
||||
}
|
||||
|
||||
async fn handle_receive_messages<F>(
|
||||
client_id: DebugAdapterClientId,
|
||||
client_id: SessionId,
|
||||
server_rx: Receiver<Message>,
|
||||
client_tx: Sender<Message>,
|
||||
mut event_handler: F,
|
||||
@@ -225,22 +193,14 @@ impl DebugAdapterClient {
|
||||
self.transport_delegate.send_message(message).await
|
||||
}
|
||||
|
||||
pub fn id(&self) -> DebugAdapterClientId {
|
||||
pub fn id(&self) -> SessionId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn adapter(&self) -> &Arc<dyn DebugAdapter> {
|
||||
&self.adapter
|
||||
}
|
||||
|
||||
pub fn binary(&self) -> &DebugAdapterBinary {
|
||||
&self.binary
|
||||
}
|
||||
|
||||
pub fn adapter_id(&self) -> String {
|
||||
self.adapter.name().to_string()
|
||||
}
|
||||
|
||||
/// Get the next sequence id to be used in a request
|
||||
pub fn next_sequence_id(&self) -> u64 {
|
||||
self.sequence_count.fetch_add(1, Ordering::Relaxed)
|
||||
@@ -335,15 +295,17 @@ mod tests {
|
||||
pub async fn test_initialize_client(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let adapter = Arc::new(FakeAdapter::new());
|
||||
|
||||
let mut client = DebugAdapterClient::new(
|
||||
crate::client::DebugAdapterClientId(1),
|
||||
adapter,
|
||||
crate::client::SessionId(1),
|
||||
DebugAdapterBinary {
|
||||
command: "command".into(),
|
||||
arguments: Default::default(),
|
||||
envs: Default::default(),
|
||||
connection: Some(TcpArguments {
|
||||
host: Ipv4Addr::LOCALHOST,
|
||||
port: None,
|
||||
timeout: None,
|
||||
}),
|
||||
cwd: None,
|
||||
},
|
||||
&mut cx.to_async(),
|
||||
@@ -411,12 +373,16 @@ mod tests {
|
||||
let called_event_handler = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let mut client = DebugAdapterClient::new(
|
||||
crate::client::DebugAdapterClientId(1),
|
||||
adapter,
|
||||
crate::client::SessionId(1),
|
||||
DebugAdapterBinary {
|
||||
command: "command".into(),
|
||||
arguments: Default::default(),
|
||||
envs: Default::default(),
|
||||
connection: Some(TCPArguments {
|
||||
host: Ipv4Addr::LOCALHOST,
|
||||
port: None,
|
||||
path: None,
|
||||
}),
|
||||
cwd: None,
|
||||
},
|
||||
&mut cx.to_async(),
|
||||
@@ -466,12 +432,17 @@ mod tests {
|
||||
let called_event_handler = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let mut client = DebugAdapterClient::new(
|
||||
crate::client::DebugAdapterClientId(1),
|
||||
adapter,
|
||||
crate::client::SessionId(1),
|
||||
DebugAdapterBinary {
|
||||
command: "command".into(),
|
||||
arguments: Default::default(),
|
||||
envs: Default::default(),
|
||||
|
||||
connection: Some(TCPArguments {
|
||||
host: Ipv4Addr::LOCALHOST,
|
||||
port: None,
|
||||
path: None,
|
||||
}),
|
||||
cwd: None,
|
||||
},
|
||||
&mut cx.to_async(),
|
||||
|
||||
@@ -357,11 +357,9 @@ pub fn capabilities_to_proto(
|
||||
capabilities: &Capabilities,
|
||||
project_id: u64,
|
||||
session_id: u64,
|
||||
client_id: u64,
|
||||
) -> SetDebugClientCapabilities {
|
||||
SetDebugClientCapabilities {
|
||||
session_id,
|
||||
client_id,
|
||||
project_id,
|
||||
supports_loaded_sources_request: capabilities
|
||||
.supports_loaded_sources_request
|
||||
|
||||
@@ -23,7 +23,7 @@ use std::{
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use task::TCPHost;
|
||||
use task::{DebugAdapterKind, TCPHost};
|
||||
use util::ResultExt as _;
|
||||
|
||||
use crate::{adapters::DebugAdapterBinary, debugger_settings::DebuggerSettings};
|
||||
@@ -68,18 +68,80 @@ impl TransportPipe {
|
||||
type Requests = Arc<Mutex<HashMap<u64, oneshot::Sender<Result<Response>>>>>;
|
||||
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 {
|
||||
log_handlers: LogHandlers,
|
||||
current_requests: Requests,
|
||||
pending_requests: Requests,
|
||||
transport: Arc<dyn Transport>,
|
||||
transport: Transport,
|
||||
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 {
|
||||
pub fn new(transport: Arc<dyn Transport>) -> Self {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn fake(args: DebugAdapterBinary) -> Self {
|
||||
Self {
|
||||
transport,
|
||||
transport: Transport::fake(args),
|
||||
server_tx: Default::default(),
|
||||
log_handlers: 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(
|
||||
&mut self,
|
||||
binary: &DebugAdapterBinary,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<(Receiver<Message>, Sender<Message>)> {
|
||||
self.start_handlers(self.transport.start(binary, cx).await?, cx)
|
||||
.await
|
||||
cx: AsyncApp,
|
||||
) -> Result<((Receiver<Message>, Sender<Message>), Self)> {
|
||||
let (transport_pipes, transport) = Transport::start(binary, cx.clone()).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(
|
||||
&mut self,
|
||||
mut params: TransportPipe,
|
||||
cx: &mut AsyncApp,
|
||||
cx: AsyncApp,
|
||||
) -> Result<(Receiver<Message>, Sender<Message>)> {
|
||||
let (client_tx, server_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 {
|
||||
port: u16,
|
||||
host: Ipv4Addr,
|
||||
timeout: Option<u64>,
|
||||
process: Arc<Mutex<Option<Child>>>,
|
||||
timeout: u64,
|
||||
process: Mutex<Child>,
|
||||
}
|
||||
|
||||
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
|
||||
pub async fn port(host: &TCPHost) -> Result<u16> {
|
||||
if let Some(port) = host.port {
|
||||
@@ -521,49 +555,33 @@ impl TcpTransport {
|
||||
.port())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl Transport for TcpTransport {
|
||||
async fn reconnect(&self, cx: &mut AsyncApp) -> Result<TransportPipe> {
|
||||
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 port_for_host(host: Ipv4Addr) -> Result<u16> {
|
||||
Ok(TcpListener::bind(SocketAddrV4::new(host, 0))
|
||||
.await?
|
||||
.local_addr()?
|
||||
.port())
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if let Some(cwd) = &binary.cwd {
|
||||
@@ -588,16 +606,16 @@ impl Transport for TcpTransport {
|
||||
.spawn()
|
||||
.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)
|
||||
.unwrap_or(2000u64)
|
||||
});
|
||||
|
||||
let (rx, tx) = select! {
|
||||
_ = 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 {
|
||||
loop {
|
||||
@@ -612,23 +630,27 @@ impl Transport for TcpTransport {
|
||||
};
|
||||
log::info!(
|
||||
"Debug adapter has connected to TCP server {}:{}",
|
||||
self.host,
|
||||
self.port
|
||||
host,
|
||||
port
|
||||
);
|
||||
|
||||
let stdout = process.stdout.take();
|
||||
let stderr = process.stderr.take();
|
||||
|
||||
{
|
||||
*self.process.lock().await = Some(process);
|
||||
}
|
||||
let this = Self {
|
||||
port,
|
||||
host,
|
||||
process: Mutex::new(process),
|
||||
timeout,
|
||||
};
|
||||
|
||||
Ok(TransportPipe::new(
|
||||
let pipe = TransportPipe::new(
|
||||
Box::new(tx),
|
||||
Box::new(BufReader::new(rx)),
|
||||
stdout.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 {
|
||||
@@ -636,29 +658,18 @@ impl Transport for TcpTransport {
|
||||
}
|
||||
|
||||
async fn kill(&self) -> Result<()> {
|
||||
if let Some(mut process) = self.process.lock().await.take() {
|
||||
process.kill()?;
|
||||
}
|
||||
self.process.lock().await.kill()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StdioTransport {
|
||||
process: Arc<Mutex<Option<Child>>>,
|
||||
process: Mutex<Child>,
|
||||
}
|
||||
|
||||
impl StdioTransport {
|
||||
pub fn new() -> 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> {
|
||||
async fn start(binary: &DebugAdapterBinary, _: AsyncApp) -> Result<(TransportPipe, Self)> {
|
||||
let mut command = util::command::new_smol_command(&binary.command);
|
||||
|
||||
if let Some(cwd) = &binary.cwd {
|
||||
@@ -705,15 +716,16 @@ impl Transport for StdioTransport {
|
||||
|
||||
log::info!("Debug adapter has connected to stdio adapter");
|
||||
|
||||
{
|
||||
*self.process.lock().await = Some(process);
|
||||
}
|
||||
let process = Mutex::new(process);
|
||||
|
||||
Ok(TransportPipe::new(
|
||||
Box::new(stdin),
|
||||
Box::new(BufReader::new(stdout)),
|
||||
None,
|
||||
stderr,
|
||||
Ok((
|
||||
TransportPipe::new(
|
||||
Box::new(stdin),
|
||||
Box::new(BufReader::new(stdout)),
|
||||
None,
|
||||
stderr,
|
||||
),
|
||||
Self { process },
|
||||
))
|
||||
}
|
||||
|
||||
@@ -721,11 +733,12 @@ impl Transport for StdioTransport {
|
||||
false
|
||||
}
|
||||
|
||||
async fn kill(&self) -> Result<()> {
|
||||
if let Some(mut process) = self.process.lock().await.take() {
|
||||
process.kill()?;
|
||||
}
|
||||
async fn reconnect(&self, _: AsyncApp) -> Result<TransportPipe> {
|
||||
bail!("Cannot reconnect to adapter")
|
||||
}
|
||||
|
||||
async fn kill(&self) -> Result<()> {
|
||||
self.process.lock().await.kill()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -753,13 +766,6 @@ pub struct FakeTransport {
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
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)
|
||||
where
|
||||
F: 'static + Send + FnMut(u64, R::Arguments) -> Result<R::Response, ErrorResponse>,
|
||||
@@ -803,37 +809,34 @@ impl FakeTransport {
|
||||
.await
|
||||
.insert(R::COMMAND, Box::new(handler));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
#[async_trait(?Send)]
|
||||
impl Transport for FakeTransport {
|
||||
async fn reconnect(&self, cx: &mut AsyncApp) -> Result<TransportPipe> {
|
||||
async fn reconnect(&self, cx: AsyncApp) -> Result<TransportPipe> {
|
||||
self.start(
|
||||
&DebugAdapterBinary {
|
||||
command: "command".into(),
|
||||
arguments: None,
|
||||
envs: None,
|
||||
cwd: None,
|
||||
connection: TcpTransport::new(None, None),
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn start(
|
||||
&self,
|
||||
_binary: &DebugAdapterBinary,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<TransportPipe> {
|
||||
async fn start(cx: AsyncApp) -> Result<TransportPipe> {
|
||||
let this = Self {
|
||||
request_handlers: Arc::new(Mutex::new(HashMap::default())),
|
||||
response_handlers: Arc::new(Mutex::new(HashMap::default())),
|
||||
};
|
||||
use dap_types::requests::{Request, RunInTerminal, StartDebugging};
|
||||
use serde_json::json;
|
||||
|
||||
let (stdin_writer, stdin_reader) = async_pipe::pipe();
|
||||
let (stdout_writer, stdout_reader) = async_pipe::pipe();
|
||||
|
||||
let request_handlers = self.request_handlers.clone();
|
||||
let response_handlers = self.response_handlers.clone();
|
||||
let request_handlers = this.request_handlers.clone();
|
||||
let response_handlers = this.response_handlers.clone();
|
||||
let stdout_writer = Arc::new(Mutex::new(stdout_writer));
|
||||
|
||||
cx.background_executor()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{ffi::OsString, path::PathBuf, sync::Arc};
|
||||
|
||||
use dap::transport::{StdioTransport, TcpTransport, Transport};
|
||||
use dap::transport::{StdioTransport, TcpTransport};
|
||||
use gpui::AsyncApp;
|
||||
use serde_json::Value;
|
||||
use task::DebugAdapterConfig;
|
||||
@@ -9,24 +9,13 @@ use crate::*;
|
||||
|
||||
pub(crate) struct CustomDebugAdapter {
|
||||
custom_args: CustomArgs,
|
||||
transport: Arc<dyn Transport>,
|
||||
}
|
||||
|
||||
impl CustomDebugAdapter {
|
||||
const ADAPTER_NAME: &'static str = "custom_dap";
|
||||
|
||||
pub(crate) async fn new(custom_args: CustomArgs) -> Result<Self> {
|
||||
Ok(CustomDebugAdapter {
|
||||
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,
|
||||
})
|
||||
Ok(CustomDebugAdapter { custom_args })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +25,6 @@ impl DebugAdapter for CustomDebugAdapter {
|
||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||
}
|
||||
|
||||
fn transport(&self) -> Arc<dyn Transport> {
|
||||
self.transport.clone()
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
@@ -47,7 +32,17 @@ impl DebugAdapter for CustomDebugAdapter {
|
||||
_: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> 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(),
|
||||
arguments: self
|
||||
.custom_args
|
||||
@@ -56,7 +51,9 @@ impl DebugAdapter for CustomDebugAdapter {
|
||||
.map(|args| args.iter().map(OsString::from).collect()),
|
||||
cwd: config.cwd.clone(),
|
||||
envs: self.custom_args.envs.clone(),
|
||||
})
|
||||
connection,
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use dap::transport::{TcpTransport, Transport};
|
||||
use dap::transport::TcpTransport;
|
||||
use gpui::AsyncApp;
|
||||
use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc};
|
||||
|
||||
@@ -28,10 +28,6 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
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(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
@@ -86,6 +82,7 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
]),
|
||||
cwd: config.cwd.clone(),
|
||||
envs: None,
|
||||
connection: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use adapters::latest_github_release;
|
||||
use dap::transport::{TcpTransport, Transport};
|
||||
use dap::transport::TcpTransport;
|
||||
use gpui::AsyncApp;
|
||||
use regex::Regex;
|
||||
use std::{collections::HashMap, net::Ipv4Addr, path::PathBuf, sync::Arc};
|
||||
@@ -33,10 +33,6 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
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(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
@@ -98,6 +94,11 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
]),
|
||||
cwd: config.cwd.clone(),
|
||||
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>(
|
||||
&self,
|
||||
processes: &'a HashMap<Pid, Process>,
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{collections::HashMap, ffi::OsStr, path::PathBuf, sync::Arc};
|
||||
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use dap::transport::{StdioTransport, Transport};
|
||||
use dap::transport::StdioTransport;
|
||||
use gpui::AsyncApp;
|
||||
use sysinfo::{Pid, Process};
|
||||
use task::{DebugAdapterConfig, DebugRequestType};
|
||||
@@ -25,10 +25,6 @@ impl DebugAdapter for LldbDebugAdapter {
|
||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||
}
|
||||
|
||||
fn transport(&self) -> Arc<dyn Transport> {
|
||||
Arc::new(StdioTransport::new())
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
@@ -59,6 +55,7 @@ impl DebugAdapter for LldbDebugAdapter {
|
||||
arguments: None,
|
||||
envs: None,
|
||||
cwd: config.cwd.clone(),
|
||||
connection: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -102,10 +99,6 @@ impl DebugAdapter for LldbDebugAdapter {
|
||||
})
|
||||
}
|
||||
|
||||
fn supports_attach(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn attach_processes<'a>(
|
||||
&self,
|
||||
processes: &'a HashMap<Pid, Process>,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use adapters::latest_github_release;
|
||||
use dap::transport::{TcpTransport, Transport};
|
||||
use dap::{adapters::TcpArguments, transport::TcpTransport};
|
||||
use gpui::AsyncApp;
|
||||
use std::{net::Ipv4Addr, path::PathBuf, sync::Arc};
|
||||
|
||||
@@ -30,10 +30,6 @@ impl DebugAdapter for PhpDebugAdapter {
|
||||
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(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
@@ -92,6 +88,11 @@ impl DebugAdapter for PhpDebugAdapter {
|
||||
adapter_path.join(Self::ADAPTER_PATH).into(),
|
||||
format!("--server={}", self.port).into(),
|
||||
]),
|
||||
connection: Some(TcpArguments {
|
||||
port: Some(self.port),
|
||||
host: Ipv4Addr::LOCALHOST,
|
||||
timeout: None,
|
||||
}),
|
||||
cwd: config.cwd.clone(),
|
||||
envs: None,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::*;
|
||||
use dap::transport::{TcpTransport, Transport};
|
||||
use dap::transport::TcpTransport;
|
||||
use gpui::AsyncApp;
|
||||
use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc};
|
||||
|
||||
@@ -29,10 +29,6 @@ impl DebugAdapter for PythonDebugAdapter {
|
||||
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(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
@@ -125,6 +121,11 @@ impl DebugAdapter for PythonDebugAdapter {
|
||||
format!("--port={}", self.port).into(),
|
||||
format!("--host={}", self.host).into(),
|
||||
]),
|
||||
connection: Some(adapters::TcpArguments {
|
||||
host: self.host,
|
||||
port: Some(self.port),
|
||||
timeout: self.timeout,
|
||||
}),
|
||||
cwd: config.cwd.clone(),
|
||||
envs: None,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use dap::{
|
||||
client::{DebugAdapterClient, DebugAdapterClientId},
|
||||
client::{DebugAdapterClient, SessionId},
|
||||
debugger_settings::DebuggerSettings,
|
||||
transport::{IoKind, LogKind},
|
||||
};
|
||||
@@ -12,11 +12,7 @@ use gpui::{
|
||||
actions, div, App, AppContext, Context, Empty, Entity, EventEmitter, FocusHandle, Focusable,
|
||||
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, WeakEntity, Window,
|
||||
};
|
||||
use project::{
|
||||
debugger::dap_session::{DebugSession, DebugSessionId},
|
||||
search::SearchQuery,
|
||||
Project,
|
||||
};
|
||||
use project::{debugger::session::Session, search::SearchQuery, Project};
|
||||
use settings::Settings as _;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@@ -36,16 +32,16 @@ struct DapLogView {
|
||||
focus_handle: FocusHandle,
|
||||
log_store: Entity<LogStore>,
|
||||
editor_subscriptions: Vec<Subscription>,
|
||||
current_view: Option<(DebugAdapterClientId, LogKind)>,
|
||||
current_view: Option<(SessionId, LogKind)>,
|
||||
project: Entity<Project>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
struct LogStore {
|
||||
projects: HashMap<WeakEntity<Project>, ProjectState>,
|
||||
debug_clients: HashMap<DebugAdapterClientId, DebugAdapterState>,
|
||||
rpc_tx: UnboundedSender<(DebugAdapterClientId, IoKind, String)>,
|
||||
adapter_log_tx: UnboundedSender<(DebugAdapterClientId, IoKind, String)>,
|
||||
debug_clients: HashMap<SessionId, DebugAdapterState>,
|
||||
rpc_tx: UnboundedSender<(SessionId, IoKind, String)>,
|
||||
adapter_log_tx: UnboundedSender<(SessionId, IoKind, String)>,
|
||||
}
|
||||
|
||||
struct ProjectState {
|
||||
@@ -102,7 +98,7 @@ impl DebugAdapterState {
|
||||
|
||||
impl LogStore {
|
||||
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 {
|
||||
while let Some((client_id, io_kind, message)) = rpc_rx.next().await {
|
||||
if let Some(this) = this.upgrade() {
|
||||
@@ -117,8 +113,7 @@ impl LogStore {
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
|
||||
let (adapter_log_tx, mut adapter_log_rx) =
|
||||
unbounded::<(DebugAdapterClientId, IoKind, String)>();
|
||||
let (adapter_log_tx, mut adapter_log_rx) = unbounded::<(SessionId, IoKind, String)>();
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
while let Some((client_id, io_kind, message)) = adapter_log_rx.next().await {
|
||||
if let Some(this) = this.upgrade() {
|
||||
@@ -142,7 +137,7 @@ impl LogStore {
|
||||
|
||||
fn on_rpc_log(
|
||||
&mut self,
|
||||
client_id: DebugAdapterClientId,
|
||||
client_id: SessionId,
|
||||
io_kind: IoKind,
|
||||
message: &str,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -152,7 +147,7 @@ impl LogStore {
|
||||
|
||||
fn on_adapter_log(
|
||||
&mut self,
|
||||
client_id: DebugAdapterClientId,
|
||||
client_id: SessionId,
|
||||
io_kind: IoKind,
|
||||
message: &str,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -170,19 +165,17 @@ impl LogStore {
|
||||
this.projects.remove(&weak_project);
|
||||
}),
|
||||
cx.subscribe(project, |this, project, event, cx| match event {
|
||||
project::Event::DebugClientStarted((_, client_id)) => {
|
||||
this.add_debug_client(
|
||||
*client_id,
|
||||
project.update(cx, |project, cx| {
|
||||
project.dap_store().update(cx, |store, cx| {
|
||||
store.client_by_id(client_id, cx).and_then(
|
||||
|(session, client)| {
|
||||
Some((session, client.read(cx).adapter_client()?))
|
||||
},
|
||||
)
|
||||
})
|
||||
}),
|
||||
);
|
||||
project::Event::DebugClientStarted(client_id) => {
|
||||
let client = project.update(cx, |project, cx| {
|
||||
project.dap_store().update(cx, |store, cx| {
|
||||
store
|
||||
.session_by_id(client_id)
|
||||
.and_then(|client| Some(client))
|
||||
})
|
||||
});
|
||||
if let Some(client) = client {
|
||||
this.add_debug_client(*client_id, client, cx);
|
||||
}
|
||||
}
|
||||
project::Event::DebugClientShutdown(client_id) => {
|
||||
this.remove_debug_client(*client_id, cx);
|
||||
@@ -195,16 +188,13 @@ impl LogStore {
|
||||
);
|
||||
}
|
||||
|
||||
fn get_debug_adapter_state(
|
||||
&mut self,
|
||||
id: DebugAdapterClientId,
|
||||
) -> Option<&mut DebugAdapterState> {
|
||||
fn get_debug_adapter_state(&mut self, id: SessionId) -> Option<&mut DebugAdapterState> {
|
||||
self.debug_clients.get_mut(&id)
|
||||
}
|
||||
|
||||
fn add_debug_client_message(
|
||||
&mut self,
|
||||
id: DebugAdapterClientId,
|
||||
id: SessionId,
|
||||
io_kind: IoKind,
|
||||
message: String,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -236,7 +226,7 @@ impl LogStore {
|
||||
|
||||
fn add_debug_client_log(
|
||||
&mut self,
|
||||
id: DebugAdapterClientId,
|
||||
id: SessionId,
|
||||
io_kind: IoKind,
|
||||
message: String,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -266,7 +256,7 @@ impl LogStore {
|
||||
|
||||
fn add_debug_client_entry(
|
||||
log_lines: &mut VecDeque<String>,
|
||||
id: DebugAdapterClientId,
|
||||
id: SessionId,
|
||||
message: String,
|
||||
kind: LogKind,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -295,56 +285,50 @@ impl LogStore {
|
||||
|
||||
fn add_debug_client(
|
||||
&mut self,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_and_client: Option<(Entity<DebugSession>, Arc<DebugAdapterClient>)>,
|
||||
client_id: SessionId,
|
||||
client: Entity<Session>,
|
||||
cx: &App,
|
||||
) -> Option<&mut DebugAdapterState> {
|
||||
let client_state = self
|
||||
.debug_clients
|
||||
.entry(client_id)
|
||||
.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(
|
||||
move |io_kind, message| {
|
||||
io_tx
|
||||
.unbounded_send((client_id, io_kind, message.to_string()))
|
||||
.ok();
|
||||
},
|
||||
LogKind::Rpc,
|
||||
);
|
||||
let client = client.read(cx).adapter_client()?;
|
||||
client.add_log_handler(
|
||||
move |io_kind, message| {
|
||||
io_tx
|
||||
.unbounded_send((client_id, io_kind, message.to_string()))
|
||||
.ok();
|
||||
},
|
||||
LogKind::Rpc,
|
||||
);
|
||||
|
||||
let log_io_tx = self.adapter_log_tx.clone();
|
||||
client.add_log_handler(
|
||||
move |io_kind, message| {
|
||||
log_io_tx
|
||||
.unbounded_send((client_id, io_kind, message.to_string()))
|
||||
.ok();
|
||||
},
|
||||
LogKind::Adapter,
|
||||
);
|
||||
}
|
||||
let log_io_tx = self.adapter_log_tx.clone();
|
||||
client.add_log_handler(
|
||||
move |io_kind, message| {
|
||||
log_io_tx
|
||||
.unbounded_send((client_id, io_kind, message.to_string()))
|
||||
.ok();
|
||||
},
|
||||
LogKind::Adapter,
|
||||
);
|
||||
|
||||
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);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn log_messages_for_client(
|
||||
&mut self,
|
||||
client_id: DebugAdapterClientId,
|
||||
) -> Option<&mut VecDeque<String>> {
|
||||
fn log_messages_for_client(&mut self, client_id: SessionId) -> Option<&mut VecDeque<String>> {
|
||||
Some(&mut self.debug_clients.get_mut(&client_id)?.log_messages)
|
||||
}
|
||||
|
||||
fn rpc_messages_for_client(
|
||||
&mut self,
|
||||
client_id: DebugAdapterClientId,
|
||||
) -> Option<&mut VecDeque<String>> {
|
||||
fn rpc_messages_for_client(&mut self, client_id: SessionId) -> Option<&mut VecDeque<String>> {
|
||||
Some(
|
||||
&mut self
|
||||
.debug_clients
|
||||
@@ -379,11 +363,9 @@ impl Render for DapLogToolbarItemView {
|
||||
});
|
||||
|
||||
let current_client = current_client_id.and_then(|current_client_id| {
|
||||
menu_rows.iter().find_map(|row| {
|
||||
row.clients
|
||||
.iter()
|
||||
.find(|sub_item| sub_item.client_id == current_client_id)
|
||||
})
|
||||
menu_rows
|
||||
.iter()
|
||||
.find(|row| row.client_id == current_client_id)
|
||||
});
|
||||
|
||||
let dap_menu: PopoverMenu<_> = PopoverMenu::new("DapLogView")
|
||||
@@ -409,56 +391,48 @@ impl Render for DapLogToolbarItemView {
|
||||
let menu_rows = menu_rows.clone();
|
||||
ContextMenu::build(&mut window, cx, move |mut menu, window, _cx| {
|
||||
for row in menu_rows.into_iter() {
|
||||
menu = menu.header(format!("{}. {}", row.session_id.0, row.session_name));
|
||||
|
||||
for sub_item in row.clients.into_iter() {
|
||||
menu = menu.custom_row(move |_window, _cx| {
|
||||
div()
|
||||
.w_full()
|
||||
.pl_2()
|
||||
.child(
|
||||
Label::new(format!(
|
||||
"{}. {}",
|
||||
sub_item.client_id.0, sub_item.client_name,
|
||||
))
|
||||
.color(workspace::ui::Color::Muted),
|
||||
menu = menu.custom_row(move |_window, _cx| {
|
||||
div()
|
||||
.w_full()
|
||||
.pl_2()
|
||||
.child(
|
||||
Label::new(
|
||||
format!("{}. {}", row.client_id.0, row.client_name,),
|
||||
)
|
||||
.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,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
.color(workspace::ui::Color::Muted),
|
||||
)
|
||||
.into_any_element()
|
||||
});
|
||||
|
||||
if row.has_adapter_logs {
|
||||
menu = menu.custom_entry(
|
||||
move |_window, _cx| {
|
||||
div()
|
||||
.w_full()
|
||||
.pl_4()
|
||||
.child(Label::new(RPC_MESSAGES))
|
||||
.child(Label::new(ADAPTER_LOGS))
|
||||
.into_any_element()
|
||||
},
|
||||
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
|
||||
})
|
||||
.into()
|
||||
@@ -585,36 +559,23 @@ impl DapLogView {
|
||||
.dap_store()
|
||||
.read(cx)
|
||||
.sessions()
|
||||
.filter_map(|session| {
|
||||
.filter_map(|client| {
|
||||
let client = client.read(cx).adapter_client()?;
|
||||
Some(DapMenuItem {
|
||||
session_id: session.read(cx).id(),
|
||||
session_name: session.read(cx).name(),
|
||||
clients: {
|
||||
let mut clients = session
|
||||
.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
|
||||
},
|
||||
client_id: client.id(),
|
||||
client_name: unimplemented!(),
|
||||
has_adapter_logs: client.has_adapter_logs(),
|
||||
selected_entry: self.current_view.map_or(LogKind::Adapter, |(_, kind)| kind),
|
||||
})
|
||||
})
|
||||
.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)
|
||||
}
|
||||
|
||||
fn show_rpc_trace_for_server(
|
||||
&mut self,
|
||||
client_id: DebugAdapterClientId,
|
||||
client_id: SessionId,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -656,7 +617,7 @@ impl DapLogView {
|
||||
|
||||
fn show_log_messages_for_adapter(
|
||||
&mut self,
|
||||
client_id: DebugAdapterClientId,
|
||||
client_id: SessionId,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -697,14 +658,7 @@ fn log_contents(lines: &VecDeque<String>) -> String {
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub(crate) struct DapMenuItem {
|
||||
pub session_id: DebugSessionId,
|
||||
pub session_name: String,
|
||||
pub clients: Vec<DapMenuSubItem>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub(crate) struct DapMenuSubItem {
|
||||
pub client_id: DebugAdapterClientId,
|
||||
pub client_id: SessionId,
|
||||
pub client_name: String,
|
||||
pub has_adapter_logs: bool,
|
||||
pub selected_entry: LogKind,
|
||||
@@ -870,7 +824,7 @@ impl Focusable for DapLogView {
|
||||
|
||||
pub enum Event {
|
||||
NewLogEntry {
|
||||
id: DebugAdapterClientId,
|
||||
id: SessionId,
|
||||
entry: String,
|
||||
kind: LogKind,
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use dap::client::DebugAdapterClientId;
|
||||
use dap::client::SessionId;
|
||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use gpui::Subscription;
|
||||
use gpui::{DismissEvent, Entity, EventEmitter, Focusable, Render};
|
||||
use picker::{Picker, PickerDelegate};
|
||||
use project::debugger::{dap_session::DebugSessionId, dap_store::DapStore};
|
||||
use project::debugger::dap_store::DapStore;
|
||||
use std::sync::Arc;
|
||||
use sysinfo::System;
|
||||
use ui::{prelude::*, Context, Tooltip};
|
||||
@@ -20,19 +20,15 @@ struct Candidate {
|
||||
pub(crate) struct AttachModalDelegate {
|
||||
selected_index: usize,
|
||||
matches: Vec<StringMatch>,
|
||||
session_id: DebugSessionId,
|
||||
session_id: SessionId,
|
||||
placeholder_text: Arc<str>,
|
||||
dap_store: Entity<DapStore>,
|
||||
client_id: DebugAdapterClientId,
|
||||
client_id: SessionId,
|
||||
candidates: Option<Vec<Candidate>>,
|
||||
}
|
||||
|
||||
impl AttachModalDelegate {
|
||||
pub fn new(
|
||||
session_id: DebugSessionId,
|
||||
client_id: DebugAdapterClientId,
|
||||
dap_store: Entity<DapStore>,
|
||||
) -> Self {
|
||||
pub fn new(session_id: SessionId, client_id: SessionId, dap_store: Entity<DapStore>) -> Self {
|
||||
Self {
|
||||
client_id,
|
||||
dap_store,
|
||||
@@ -52,8 +48,8 @@ pub(crate) struct AttachModal {
|
||||
|
||||
impl AttachModal {
|
||||
pub fn new(
|
||||
session_id: &DebugSessionId,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: &SessionId,
|
||||
client_id: SessionId,
|
||||
dap_store: Entity<DapStore>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -132,18 +128,15 @@ impl PickerDelegate for AttachModalDelegate {
|
||||
} else {
|
||||
let Some(client) = this.delegate.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.client_by_id(&this.delegate.client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
.session_by_id(&this.delegate.client_id)
|
||||
.and_then(|client| client.read(cx).adapter_client())
|
||||
}) else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
let system = System::new_all();
|
||||
let Some(processes) =
|
||||
client.adapter().attach_processes(&system.processes())
|
||||
else {
|
||||
return Vec::new();
|
||||
};
|
||||
todo!("client.adapter().attach_processes(&system.processes())");
|
||||
let processes: Vec<(&sysinfo::Pid, &sysinfo::Process)> = vec![];
|
||||
|
||||
let processes = processes
|
||||
.into_iter()
|
||||
@@ -156,7 +149,7 @@ impl PickerDelegate for AttachModalDelegate {
|
||||
.map(|s| s.to_string_lossy().to_string())
|
||||
.collect::<Vec<_>>(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.collect::<Vec<Candidate>>();
|
||||
|
||||
let _ = this.delegate.candidates.insert(processes.clone());
|
||||
|
||||
@@ -224,7 +217,7 @@ impl PickerDelegate for AttachModalDelegate {
|
||||
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.attach(&self.session_id, self.client_id, candidate.pid, cx)
|
||||
.attach(self.client_id, candidate.pid, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
use dap::debugger_settings::DebuggerSettings;
|
||||
use debugger_panel::{DebugPanel, ToggleFocus};
|
||||
use debugger_panel_item::DebugPanelItem;
|
||||
use gpui::App;
|
||||
use session::DebugSession;
|
||||
use settings::Settings;
|
||||
use workspace::{
|
||||
Continue, Pause, Restart, ShutdownDebugAdapters, Start, StepBack, StepInto, StepOut, StepOver,
|
||||
@@ -9,20 +9,15 @@ use workspace::{
|
||||
};
|
||||
|
||||
pub mod attach_modal;
|
||||
pub mod console;
|
||||
pub mod debugger_panel;
|
||||
pub mod debugger_panel_item;
|
||||
pub mod loaded_source_list;
|
||||
pub mod module_list;
|
||||
pub mod stack_frame_list;
|
||||
pub mod variable_list;
|
||||
pub mod session;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub fn init(cx: &mut App) {
|
||||
DebuggerSettings::register(cx);
|
||||
workspace::FollowableViewRegistry::register::<DebugPanelItem>(cx);
|
||||
workspace::FollowableViewRegistry::register::<DebugSession>(cx);
|
||||
|
||||
cx.observe_new(|workspace: &mut Workspace, window, _cx| {
|
||||
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();
|
||||
}
|
||||
|
||||
190
crates/debugger_ui/src/session.rs
Normal file
190
crates/debugger_ui/src/session.rs
Normal 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
crates/debugger_ui/src/session/inert.rs
Normal file
51
crates/debugger_ui/src/session/inert.rs
Normal 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)),
|
||||
)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
use super::{
|
||||
stack_frame_list::{StackFrameList, StackFrameListEvent},
|
||||
variable_list::VariableList,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use dap::{client::DebugAdapterClientId, OutputEvent, OutputEventGroup};
|
||||
use dap::{client::SessionId, OutputEvent, OutputEventGroup};
|
||||
use editor::{
|
||||
display_map::{Crease, CreaseId},
|
||||
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 menu::Confirm;
|
||||
use project::{
|
||||
debugger::dap_session::{CompletionsQuery, DebugSession},
|
||||
debugger::session::{CompletionsQuery, Session},
|
||||
Completion,
|
||||
};
|
||||
use settings::Settings;
|
||||
@@ -33,8 +33,8 @@ pub struct Console {
|
||||
groups: Vec<OutputGroup>,
|
||||
console: Entity<Editor>,
|
||||
query_bar: Entity<Editor>,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
variable_list: Entity<VariableList>,
|
||||
stack_frame_list: Entity<StackFrameList>,
|
||||
@@ -42,8 +42,8 @@ pub struct Console {
|
||||
|
||||
impl Console {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
stack_frame_list: Entity<StackFrameList>,
|
||||
variable_list: Entity<VariableList>,
|
||||
window: &mut Window,
|
||||
@@ -234,11 +234,7 @@ impl Console {
|
||||
expression
|
||||
});
|
||||
|
||||
let Some(client_state) = self.session.read(cx).client_state(self.client_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
client_state.update(cx, |state, cx| {
|
||||
self.session.update(cx, |state, cx| {
|
||||
state.evaluate(
|
||||
expression,
|
||||
Some(dap::EvaluateArgumentsContext::Variables),
|
||||
@@ -369,10 +365,8 @@ impl CompletionProvider for ConsoleQueryBarCompletionProvider {
|
||||
.read(cx)
|
||||
.session
|
||||
.read(cx)
|
||||
.client_state(console.read(cx).client_id)
|
||||
.map(|state| state.read(cx).capabilities())
|
||||
.map(|caps| caps.supports_completions_request)
|
||||
.flatten()
|
||||
.capabilities()
|
||||
.supports_completions_request
|
||||
.unwrap_or_default();
|
||||
|
||||
if support_completions {
|
||||
@@ -498,21 +492,15 @@ impl ConsoleQueryBarCompletionProvider {
|
||||
buffer_position: language::Anchor,
|
||||
cx: &mut Context<Editor>,
|
||||
) -> gpui::Task<gpui::Result<Vec<project::Completion>>> {
|
||||
let client_id = console.read(cx).client_id;
|
||||
|
||||
let completion_task = console.update(cx, |console, cx| {
|
||||
if let Some(client_state) = console.session.read(cx).client_state(client_id) {
|
||||
client_state.update(cx, |state, cx| {
|
||||
let frame_id = Some(console.stack_frame_list.read(cx).current_stack_frame_id());
|
||||
console.session.update(cx, |state, cx| {
|
||||
let frame_id = Some(console.stack_frame_list.read(cx).current_stack_frame_id());
|
||||
|
||||
state.completions(
|
||||
CompletionsQuery::new(buffer.read(cx), buffer_position, frame_id),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
Task::ready(Err(anyhow!("failed to fetch completions")))
|
||||
}
|
||||
state.completions(
|
||||
CompletionsQuery::new(buffer.read(cx), buffer_position, frame_id),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
@@ -1,6 +1,6 @@
|
||||
use dap::client::DebugAdapterClientId;
|
||||
use dap::client::SessionId;
|
||||
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 util::maybe;
|
||||
|
||||
@@ -8,14 +8,14 @@ pub struct LoadedSourceList {
|
||||
list: ListState,
|
||||
focus_handle: FocusHandle,
|
||||
_subscription: Subscription,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
}
|
||||
|
||||
impl LoadedSourceList {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
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(&client_state, |loaded_source_list, state, cx| {
|
||||
let _subscription = cx.observe(&session, |loaded_source_list, state, cx| {
|
||||
let len = state.update(cx, |state, cx| state.loaded_sources(cx).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 {
|
||||
let Some(source) = maybe!({
|
||||
self.session
|
||||
.read(cx)
|
||||
.client_state(self.client_id)?
|
||||
.update(cx, |state, cx| state.loaded_sources(cx).get(ix).cloned())
|
||||
}) else {
|
||||
return Empty.into_any();
|
||||
@@ -92,11 +89,9 @@ impl Focusable for LoadedSourceList {
|
||||
|
||||
impl Render for LoadedSourceList {
|
||||
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) {
|
||||
state.update(cx, |state, cx| {
|
||||
state.loaded_sources(cx);
|
||||
});
|
||||
}
|
||||
self.session.update(cx, |state, cx| {
|
||||
state.loaded_sources(cx);
|
||||
});
|
||||
|
||||
div()
|
||||
.track_focus(&self.focus_handle)
|
||||
@@ -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 project::debugger::dap_session::DebugSession;
|
||||
use project::debugger::session::Session;
|
||||
use ui::prelude::*;
|
||||
|
||||
pub struct ModuleList {
|
||||
list: ListState,
|
||||
focus_handle: FocusHandle,
|
||||
_subscription: Subscription,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
}
|
||||
|
||||
impl ModuleList {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
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(&client_state, |module_list, state, cx| {
|
||||
let _subscription = cx.observe(&session, |module_list, state, cx| {
|
||||
let modules_len = state.update(cx, |state, cx| state.modules(cx).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>) {
|
||||
if let Some(state) = self.session.read(cx).client_state(self.client_id) {
|
||||
state.update(cx, |state, cx| state.handle_module_event(event, cx));
|
||||
}
|
||||
self.session
|
||||
.update(cx, |state, cx| state.handle_module_event(event, cx));
|
||||
}
|
||||
|
||||
fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
|
||||
let Some(module) = maybe!({
|
||||
self.session
|
||||
.read(cx)
|
||||
.client_state(self.client_id)?
|
||||
.update(cx, |state, cx| state.modules(cx).get(ix).cloned())
|
||||
}) else {
|
||||
return Empty.into_any();
|
||||
@@ -91,11 +86,9 @@ impl Focusable for ModuleList {
|
||||
|
||||
impl Render for ModuleList {
|
||||
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) {
|
||||
state.update(cx, |state, cx| {
|
||||
state.modules(cx);
|
||||
});
|
||||
}
|
||||
self.session.update(cx, |state, cx| {
|
||||
state.modules(cx);
|
||||
});
|
||||
|
||||
div()
|
||||
.track_focus(&self.focus_handle)
|
||||
@@ -1,12 +1,13 @@
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use dap::client::DebugAdapterClientId;
|
||||
use dap::client::SessionId;
|
||||
use gpui::{
|
||||
list, AnyElement, Entity, EventEmitter, FocusHandle, Focusable, ListState, Subscription, Task,
|
||||
WeakEntity,
|
||||
};
|
||||
use project::debugger::dap_session::{DebugSession, StackFrame, ThreadId};
|
||||
|
||||
use project::debugger::session::{Session, StackFrame, ThreadId};
|
||||
use project::ProjectPath;
|
||||
use ui::{prelude::*, Tooltip};
|
||||
use workspace::Workspace;
|
||||
@@ -24,10 +25,9 @@ pub struct StackFrameList {
|
||||
thread_id: ThreadId,
|
||||
focus_handle: FocusHandle,
|
||||
_subscription: Subscription,
|
||||
session: Entity<DebugSession>,
|
||||
session: Entity<Session>,
|
||||
entries: Vec<StackFrameEntry>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
client_id: DebugAdapterClientId,
|
||||
current_stack_frame_id: StackFrameId,
|
||||
_fetch_stack_frames_task: Option<Task<Result<()>>>,
|
||||
}
|
||||
@@ -41,8 +41,7 @@ pub enum StackFrameEntry {
|
||||
impl StackFrameList {
|
||||
pub fn new(
|
||||
workspace: WeakEntity<Workspace>,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
thread_id: ThreadId,
|
||||
_window: &Window,
|
||||
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(&client_state, |stack_frame_list, state, cx| {
|
||||
let _subscription = cx.observe(&session, |stack_frame_list, state, cx| {
|
||||
let _frame_len = state.update(cx, |state, cx| {
|
||||
state.stack_frames(stack_frame_list.thread_id, cx).len()
|
||||
});
|
||||
@@ -79,7 +76,7 @@ impl StackFrameList {
|
||||
session,
|
||||
workspace,
|
||||
thread_id,
|
||||
client_id,
|
||||
|
||||
focus_handle,
|
||||
_subscription,
|
||||
entries: Default::default(),
|
||||
@@ -99,10 +96,7 @@ impl StackFrameList {
|
||||
|
||||
pub fn stack_frames(&self, cx: &mut App) -> Vec<StackFrame> {
|
||||
self.session
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|state| state.update(cx, |client, cx| client.stack_frames(self.thread_id, cx)))
|
||||
.unwrap_or_default()
|
||||
.update(cx, |this, cx| this.stack_frames(self.thread_id, cx))
|
||||
}
|
||||
|
||||
#[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>) {
|
||||
if let Some(client_state) = self.session.read(cx).client_state(self.client_id) {
|
||||
client_state.update(cx, |state, cx| {
|
||||
state.restart_stack_frame(stack_frame_id, cx)
|
||||
});
|
||||
}
|
||||
self.session.update(cx, |state, cx| {
|
||||
state.restart_stack_frame(stack_frame_id, cx)
|
||||
});
|
||||
}
|
||||
|
||||
fn render_normal_entry(
|
||||
@@ -291,8 +283,8 @@ impl StackFrameList {
|
||||
let supports_frame_restart = self
|
||||
.session
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.and_then(|client| client.read(cx).capabilities().supports_restart_frame)
|
||||
.capabilities()
|
||||
.supports_restart_frame
|
||||
.unwrap_or_default();
|
||||
|
||||
let origin = stack_frame
|
||||
@@ -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 dap::{
|
||||
client::DebugAdapterClientId, proto_conversions::ProtoConversion, Scope, ScopePresentationHint,
|
||||
Variable,
|
||||
client::SessionId, proto_conversions::ProtoConversion, Scope, ScopePresentationHint, Variable,
|
||||
};
|
||||
use editor::{actions::SelectAll, Editor, EditorEvent};
|
||||
use gpui::{
|
||||
@@ -10,7 +9,7 @@ use gpui::{
|
||||
FocusHandle, Focusable, Hsla, ListOffset, ListState, MouseDownEvent, Point, Subscription, Task,
|
||||
};
|
||||
use menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev};
|
||||
use project::debugger::dap_session::DebugSession;
|
||||
use project::debugger::session::Session;
|
||||
use rpc::proto::{
|
||||
self, DebuggerScopeVariableIndex, DebuggerVariableContainer, VariableListScopes,
|
||||
VariableListVariables,
|
||||
@@ -330,8 +329,8 @@ pub struct VariableList {
|
||||
list: ListState,
|
||||
focus_handle: FocusHandle,
|
||||
open_entries: Vec<OpenEntry>,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
set_variable_editor: Entity<Editor>,
|
||||
selection: Option<VariableListEntry>,
|
||||
@@ -346,8 +345,8 @@ pub struct VariableList {
|
||||
|
||||
impl VariableList {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
session: Entity<Session>,
|
||||
client_id: SessionId,
|
||||
stack_frame_list: Entity<StackFrameList>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -842,20 +841,11 @@ impl VariableList {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some((support_set_variable, support_clipboard_context)) = self
|
||||
.session
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.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 caps = self.session.read(cx).capabilities();
|
||||
let (support_set_variable, support_clipboard_context) = (
|
||||
caps.supports_set_variable.unwrap_or_default(),
|
||||
caps.supports_clipboard_context.unwrap_or_default(),
|
||||
);
|
||||
|
||||
let this = cx.entity();
|
||||
|
||||
@@ -874,12 +864,7 @@ impl VariableList {
|
||||
|
||||
window.handler_for(&this.clone(), move |this, _window, cx| {
|
||||
if support_clipboard_context {
|
||||
let Some(client_state) = this.session.read(cx).client_state(this.client_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
client_state.update(cx, |state, cx| {
|
||||
this.session.update(cx, |state, cx| {
|
||||
state.evaluate(
|
||||
evaluate_name.clone().unwrap_or(variable_name.clone()),
|
||||
Some(dap::EvaluateArgumentsContext::Clipboard),
|
||||
@@ -984,11 +969,7 @@ impl VariableList {
|
||||
return cx.notify();
|
||||
}
|
||||
|
||||
let Some(client_state) = self.session.read(cx).client_state(self.client_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
client_state.update(cx, |state, cx| {
|
||||
self.session.update(cx, |state, cx| {
|
||||
state.set_variable_value(
|
||||
set_variable_state.parent_variables_reference,
|
||||
set_variable_state.name,
|
||||
22
crates/debugger_ui/src/session/starting.rs
Normal file
22
crates/debugger_ui/src/session/starting.rs
Normal 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")
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ use settings::SettingsStore;
|
||||
use terminal_view::terminal_panel::TerminalPanel;
|
||||
use workspace::Workspace;
|
||||
|
||||
use crate::{debugger_panel::DebugPanel, debugger_panel_item::DebugPanelItem};
|
||||
use crate::{debugger_panel::DebugPanel, session::DebugSession};
|
||||
|
||||
mod attach_modal;
|
||||
mod console;
|
||||
@@ -62,7 +62,7 @@ pub async fn init_test_workspace(
|
||||
pub fn active_debug_panel_item(
|
||||
workspace: WindowHandle<Workspace>,
|
||||
cx: &mut TestAppContext,
|
||||
) -> Entity<DebugPanelItem> {
|
||||
) -> Entity<DebugSession> {
|
||||
workspace
|
||||
.update(cx, |workspace, _window, cx| {
|
||||
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::*;
|
||||
use dap::{
|
||||
client::DebugAdapterClientId,
|
||||
client::SessionId,
|
||||
requests::{
|
||||
Continue, Disconnect, Initialize, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace,
|
||||
StartDebugging, StepBack, StepIn, StepOut,
|
||||
@@ -759,7 +759,7 @@ async fn test_handle_start_debugging_reverse_request(
|
||||
let second_client = project.update(cx, |_, cx| {
|
||||
session
|
||||
.read(cx)
|
||||
.client_state(DebugAdapterClientId(1))
|
||||
.client_state(SessionId(1))
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.adapter_client()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
debugger_panel_item::ThreadItem,
|
||||
session::ThreadItem,
|
||||
tests::{active_debug_panel_item, init_test, init_test_workspace},
|
||||
};
|
||||
use dap::{
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
|
||||
pub mod breakpoint_store;
|
||||
pub mod dap_command;
|
||||
pub mod dap_session;
|
||||
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
@@ -1,20 +1,28 @@
|
||||
use crate::project_settings::ProjectSettings;
|
||||
|
||||
use super::breakpoint_store::BreakpointStore;
|
||||
use super::dap_command::{
|
||||
self, ContinueCommand, DapCommand, DisconnectCommand, EvaluateCommand, NextCommand,
|
||||
PauseCommand, RestartCommand, RestartStackFrameCommand, ScopesCommand, SetVariableValueCommand,
|
||||
StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand,
|
||||
TerminateThreadsCommand, VariablesCommand,
|
||||
self, ContinueCommand, DapCommand, DisconnectCommand, EvaluateCommand, Initialize,
|
||||
LocalDapCommand, NextCommand, PauseCommand, RestartCommand, RestartStackFrameCommand,
|
||||
ScopesCommand, SetVariableValueCommand, StepBackCommand, StepCommand, StepInCommand,
|
||||
StepOutCommand, TerminateCommand, TerminateThreadsCommand, VariablesCommand,
|
||||
};
|
||||
use super::dap_store::DapAdapterDelegate;
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::{BTreeMap, HashMap, IndexMap};
|
||||
use dap::client::{DebugAdapterClient, DebugAdapterClientId};
|
||||
use collections::{HashMap, IndexMap};
|
||||
use dap::adapters::{DapDelegate, DapStatus, DebugAdapterName};
|
||||
use dap::client::{DebugAdapterClient, SessionId};
|
||||
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 gpui::{App, AppContext, Context, Entity, Task};
|
||||
use gpui::{App, AppContext, AsyncApp, BackgroundExecutor, Context, Entity, Task};
|
||||
use rpc::AnyProtoClient;
|
||||
use serde_json::Value;
|
||||
use std::borrow::Borrow;
|
||||
use settings::Settings;
|
||||
use std::path::PathBuf;
|
||||
use std::u64;
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -26,20 +34,6 @@ use task::DebugAdapterConfig;
|
||||
use text::{PointUtf16, ToPointUtf16};
|
||||
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)]
|
||||
#[repr(transparent)]
|
||||
pub struct ThreadId(pub u64);
|
||||
@@ -123,7 +117,7 @@ impl From<dap::Thread> for Thread {
|
||||
|
||||
type UpstreamProjectId = u64;
|
||||
|
||||
pub struct RemoteConnection {
|
||||
struct RemoteConnection {
|
||||
client: AnyProtoClient,
|
||||
upstream_project_id: UpstreamProjectId,
|
||||
}
|
||||
@@ -132,52 +126,109 @@ impl RemoteConnection {
|
||||
fn send_proto_client_request<R: DapCommand>(
|
||||
&self,
|
||||
request: R,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: SessionId,
|
||||
cx: &mut App,
|
||||
) -> 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();
|
||||
cx.background_executor().spawn(async move {
|
||||
let response = upstream_client.request(message).await?;
|
||||
request.response_from_proto(response)
|
||||
})
|
||||
}
|
||||
fn request_remote<R: DapCommand>(
|
||||
fn request<R: DapCommand>(
|
||||
&self,
|
||||
request: R,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: SessionId,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<R::Response>>
|
||||
where
|
||||
<R::DapRequest as dap::requests::Request>::Response: 'static,
|
||||
<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 {
|
||||
Local(Arc<DebugAdapterClient>),
|
||||
enum Mode {
|
||||
Local(LocalMode),
|
||||
Remote(RemoteConnection),
|
||||
}
|
||||
|
||||
impl From<RemoteConnection> for Mode {
|
||||
fn from(value: RemoteConnection) -> Self {
|
||||
Self::Remote(value)
|
||||
}
|
||||
struct LocalMode {
|
||||
client: Arc<DebugAdapterClient>,
|
||||
}
|
||||
|
||||
impl From<Arc<DebugAdapterClient>> for Mode {
|
||||
fn from(client: Arc<DebugAdapterClient>) -> Self {
|
||||
Mode::Local(client)
|
||||
}
|
||||
}
|
||||
impl LocalMode {
|
||||
fn new<F>(
|
||||
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 {
|
||||
fn request_local<R: DapCommand>(
|
||||
connection: &Arc<DebugAdapterClient>,
|
||||
let binary = cx.update(|cx| {
|
||||
let name = DebugAdapterName::from(adapter.name().as_ref());
|
||||
|
||||
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,
|
||||
cx: &mut Context<Client>,
|
||||
executor: BackgroundExecutor,
|
||||
) -> Task<Result<R::Response>>
|
||||
where
|
||||
<R::DapRequest as dap::requests::Request>::Response: 'static,
|
||||
@@ -186,23 +237,30 @@ impl Mode {
|
||||
let request = Arc::new(request);
|
||||
|
||||
let request_clone = request.clone();
|
||||
let connection = connection.clone();
|
||||
let request_task = cx.background_executor().spawn(async move {
|
||||
let connection = self.client.clone();
|
||||
let request_task = executor.spawn(async move {
|
||||
let args = request_clone.to_dap();
|
||||
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?);
|
||||
response
|
||||
})
|
||||
}
|
||||
}
|
||||
impl From<RemoteConnection> for Mode {
|
||||
fn from(value: RemoteConnection) -> Self {
|
||||
Self::Remote(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
fn request_dap<R: DapCommand>(
|
||||
&self,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: SessionId,
|
||||
request: R,
|
||||
cx: &mut Context<Client>,
|
||||
cx: &mut Context<Session>,
|
||||
) -> Task<Result<R::Response>>
|
||||
where
|
||||
<R::DapRequest as dap::requests::Request>::Response: 'static,
|
||||
@@ -210,21 +268,20 @@ impl Mode {
|
||||
{
|
||||
match self {
|
||||
Mode::Local(debug_adapter_client) => {
|
||||
Self::request_local(&debug_adapter_client, request, cx)
|
||||
}
|
||||
Mode::Remote(remote_connection) => {
|
||||
remote_connection.request_remote(request, client_id, cx)
|
||||
debug_adapter_client.request(request, cx.background_executor().clone())
|
||||
}
|
||||
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.
|
||||
pub struct Client {
|
||||
pub struct Session {
|
||||
mode: Mode,
|
||||
|
||||
config: DebugAdapterConfig,
|
||||
pub(super) capabilities: Capabilities,
|
||||
client_id: DebugAdapterClientId,
|
||||
id: SessionId,
|
||||
ignore_breakpoints: bool,
|
||||
modules: Vec<dap::Module>,
|
||||
loaded_sources: Vec<dap::Source>,
|
||||
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 {
|
||||
&self.capabilities
|
||||
}
|
||||
pub fn configuration(&self) -> DebugAdapterConfig {
|
||||
self.config.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn _wait_for_request<R: DapCommand + PartialEq + Eq + Hash>(
|
||||
&self,
|
||||
@@ -331,7 +444,7 @@ impl Client {
|
||||
|
||||
let task = Self::request_inner::<Arc<T>>(
|
||||
&self.capabilities,
|
||||
self.client_id,
|
||||
self.id,
|
||||
&self.mode,
|
||||
command,
|
||||
process_result,
|
||||
@@ -351,7 +464,7 @@ impl Client {
|
||||
|
||||
fn request_inner<T: DapCommand + PartialEq + Eq + Hash>(
|
||||
capabilities: &Capabilities,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: SessionId,
|
||||
mode: &Mode,
|
||||
request: T,
|
||||
process_result: impl FnOnce(&mut Self, &T::Response, &mut Context<Self>) + 'static,
|
||||
@@ -360,7 +473,7 @@ impl Client {
|
||||
if !T::is_supported(&capabilities) {
|
||||
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 {
|
||||
let result = request.await.log_err()?;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
@@ -379,7 +492,7 @@ impl Client {
|
||||
) -> Task<Option<T::Response>> {
|
||||
Self::request_inner(
|
||||
&self.capabilities,
|
||||
self.client_id,
|
||||
self.id,
|
||||
&self.mode,
|
||||
request,
|
||||
process_result,
|
||||
@@ -425,6 +538,12 @@ impl Client {
|
||||
&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>) {
|
||||
match event.reason {
|
||||
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
|
||||
.capabilities
|
||||
.supports_terminate_request
|
||||
@@ -556,7 +675,7 @@ impl Client {
|
||||
|
||||
pub fn adapter_client(&self) -> Option<Arc<DebugAdapterClient>> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
@@ -776,13 +895,11 @@ impl Client {
|
||||
&mut self,
|
||||
thread_id: ThreadId,
|
||||
stack_frame_id: u64,
|
||||
session_id: DebugSessionId,
|
||||
variables_reference: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Vec<Variable> {
|
||||
let command = VariablesCommand {
|
||||
stack_frame_id,
|
||||
session_id,
|
||||
thread_id: thread_id.0,
|
||||
variables_reference,
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,7 @@ use git::Repository;
|
||||
pub mod search_history;
|
||||
mod yarn;
|
||||
|
||||
use crate::{
|
||||
debugger::dap_session::{DebugSession, DebugSessionId},
|
||||
git::GitStore,
|
||||
};
|
||||
use crate::git::GitStore;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use buffer_store::{BufferStore, BufferStoreEvent};
|
||||
@@ -42,7 +39,7 @@ use client::{
|
||||
use clock::ReplicaId;
|
||||
|
||||
use dap::{
|
||||
client::{DebugAdapterClient, DebugAdapterClientId},
|
||||
client::{DebugAdapterClient, SessionId},
|
||||
debugger_settings::DebuggerSettings,
|
||||
messages::Message,
|
||||
DebugAdapterConfig,
|
||||
@@ -90,9 +87,7 @@ pub use prettier_store::PrettierStore;
|
||||
use project_settings::{ProjectSettings, SettingsObserver, SettingsObserverEvent};
|
||||
use remote::{SshConnectionOptions, SshRemoteClient};
|
||||
use rpc::{
|
||||
proto::{
|
||||
FromProto, LanguageServerPromptResponse, SetDebuggerPanelItem, ToProto, SSH_PROJECT_ID,
|
||||
},
|
||||
proto::{FromProto, LanguageServerPromptResponse, ToProto, SSH_PROJECT_ID},
|
||||
AnyProtoClient, ErrorCode,
|
||||
};
|
||||
use search::{SearchInputKind, SearchQuery, SearchResult};
|
||||
@@ -275,16 +270,14 @@ pub enum Event {
|
||||
notification_id: SharedString,
|
||||
},
|
||||
LanguageServerPrompt(LanguageServerPromptRequest),
|
||||
DebugClientStarted((DebugSessionId, DebugAdapterClientId)),
|
||||
DebugClientShutdown(DebugAdapterClientId),
|
||||
SetDebugClient(SetDebuggerPanelItem),
|
||||
DebugClientStarted(SessionId),
|
||||
DebugClientShutdown(SessionId),
|
||||
ActiveDebugLineChanged,
|
||||
DebugClientEvent {
|
||||
session_id: DebugSessionId,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: SessionId,
|
||||
message: Message,
|
||||
},
|
||||
DebugClientLog(DebugAdapterClientId, String),
|
||||
DebugClientLog(SessionId, String),
|
||||
LanguageNotFound(Entity<Buffer>),
|
||||
ActiveEntryChanged(Option<ProjectEntryId>),
|
||||
ActivateProjectPanel,
|
||||
@@ -1090,7 +1083,7 @@ impl Project {
|
||||
let breakpoint_store = cx.new(|cx| {
|
||||
let mut bp_store = {
|
||||
BreakpointStore::remote(
|
||||
SSH_PROJECT_ID,
|
||||
remote_id,
|
||||
client.clone().into(),
|
||||
buffer_store.clone(),
|
||||
worktree_store.clone(),
|
||||
@@ -1106,7 +1099,7 @@ impl Project {
|
||||
let mut dap_store =
|
||||
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
|
||||
})?;
|
||||
|
||||
@@ -1313,8 +1306,7 @@ impl Project {
|
||||
|
||||
pub fn initial_send_breakpoints(
|
||||
&self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: SessionId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<()> {
|
||||
let mut tasks = Vec::new();
|
||||
@@ -1332,10 +1324,10 @@ impl Project {
|
||||
|
||||
tasks.push(self.dap_store.update(cx, |store, cx| {
|
||||
store.send_breakpoints(
|
||||
client_id,
|
||||
session_id,
|
||||
abs_path,
|
||||
source_breakpoints,
|
||||
store.ignore_breakpoints(session_id, cx),
|
||||
store.ignore_breakpoints(&session_id, cx),
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
@@ -1351,7 +1343,7 @@ impl Project {
|
||||
&mut self,
|
||||
config: DebugAdapterConfig,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<(Entity<DebugSession>, Arc<DebugAdapterClient>)>> {
|
||||
) -> Task<Result<Arc<DebugAdapterClient>>> {
|
||||
let worktree = maybe!({
|
||||
if let Some(cwd) = &config.cwd {
|
||||
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() {
|
||||
project
|
||||
.toggle_ignore_breakpoints(
|
||||
&DebugSessionId::from_proto(envelope.payload.session_id),
|
||||
DebugAdapterClientId::from_proto(envelope.payload.client_id),
|
||||
SessionId::from_proto(envelope.payload.client_id),
|
||||
cx,
|
||||
)
|
||||
.detach_and_log_err(cx);
|
||||
@@ -1398,16 +1389,14 @@ impl Project {
|
||||
|
||||
pub fn toggle_ignore_breakpoints(
|
||||
&self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: DebugAdapterClientId,
|
||||
session_id: SessionId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let tasks = self.dap_store.update(cx, |store, cx| {
|
||||
if let Some((upstream_client, project_id)) = store.upstream_client() {
|
||||
upstream_client
|
||||
.send(proto::ToggleIgnoreBreakpoints {
|
||||
session_id: session_id.to_proto(),
|
||||
client_id: client_id.to_proto(),
|
||||
client_id: session_id.to_proto(),
|
||||
project_id,
|
||||
})
|
||||
.log_err();
|
||||
@@ -1415,14 +1404,14 @@ impl Project {
|
||||
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() {
|
||||
downstream_client
|
||||
.send(proto::IgnoreBreakpointState {
|
||||
session_id: session_id.to_proto(),
|
||||
project_id: *project_id,
|
||||
ignore: store.ignore_breakpoints(session_id, cx),
|
||||
ignore: store.ignore_breakpoints(&session_id, cx),
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
@@ -1448,13 +1437,13 @@ impl Project {
|
||||
|
||||
tasks.push(
|
||||
store.send_breakpoints(
|
||||
client_id,
|
||||
session_id,
|
||||
Arc::from(buffer_path),
|
||||
breakpoints
|
||||
.into_iter()
|
||||
.map(|breakpoint| breakpoint.to_source_breakpoint(buffer))
|
||||
.collect::<Vec<_>>(),
|
||||
store.ignore_breakpoints(session_id, cx),
|
||||
store.ignore_breakpoints(&session_id, cx),
|
||||
false,
|
||||
cx,
|
||||
),
|
||||
@@ -2666,20 +2655,18 @@ impl Project {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
match event {
|
||||
DapStoreEvent::DebugClientStarted(client_id) => {
|
||||
cx.emit(Event::DebugClientStarted(*client_id));
|
||||
DapStoreEvent::DebugClientStarted(session_id) => {
|
||||
cx.emit(Event::DebugClientStarted(*session_id));
|
||||
}
|
||||
DapStoreEvent::DebugClientShutdown(client_id) => {
|
||||
cx.emit(Event::DebugClientShutdown(*client_id));
|
||||
DapStoreEvent::DebugClientShutdown(session_id) => {
|
||||
cx.emit(Event::DebugClientShutdown(*session_id));
|
||||
}
|
||||
DapStoreEvent::DebugClientEvent {
|
||||
session_id,
|
||||
client_id,
|
||||
message,
|
||||
} => {
|
||||
cx.emit(Event::DebugClientEvent {
|
||||
session_id: *session_id,
|
||||
client_id: *client_id,
|
||||
message: message.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -327,48 +327,42 @@ message Envelope {
|
||||
SynchronizeBreakpoints synchronize_breakpoints = 304;
|
||||
SetActiveDebugLine set_active_debug_line = 305;
|
||||
RemoveActiveDebugLine remove_active_debug_line = 306;
|
||||
SetDebuggerPanelItem set_debugger_panel_item = 307;
|
||||
UpdateDebugAdapter update_debug_adapter = 308;
|
||||
ShutdownDebugClient shutdown_debug_client = 309;
|
||||
SetDebugClientCapabilities set_debug_client_capabilities = 310;
|
||||
|
||||
DapNextRequest dap_next_request = 311;
|
||||
DapStepInRequest dap_step_in_request = 312;
|
||||
DapStepOutRequest dap_step_out_request = 313;
|
||||
DapStepBackRequest dap_step_back_request = 314;
|
||||
DapContinueRequest dap_continue_request = 315;
|
||||
DapContinueResponse dap_continue_response = 316;
|
||||
DapPauseRequest dap_pause_request = 317;
|
||||
DapDisconnectRequest dap_disconnect_request = 318;
|
||||
DapTerminateThreadsRequest dap_terminate_threads_request = 319;
|
||||
DapTerminateRequest dap_terminate_request = 320;
|
||||
DapRestartRequest dap_restart_request = 321;
|
||||
DapShutdownSession dap_shutdown_session = 322;
|
||||
UpdateThreadStatus update_thread_status = 323;
|
||||
VariablesRequest variables_request = 324;
|
||||
DapVariables dap_variables = 325;
|
||||
DapRestartStackFrameRequest dap_restart_stack_frame_request = 326;
|
||||
IgnoreBreakpointState ignore_breakpoint_state = 327;
|
||||
ToggleIgnoreBreakpoints toggle_ignore_breakpoints = 328;
|
||||
DebuggerSessionEnded debugger_session_ended = 329;
|
||||
DapModulesRequest dap_modules_request = 330;
|
||||
DapModulesResponse dap_modules_response = 331;
|
||||
DapLoadedSourcesRequest dap_loaded_sources_request = 332;
|
||||
DapLoadedSourcesResponse dap_loaded_sources_response = 333;
|
||||
ActiveDebugSessionsRequest active_debug_sessions_request = 334;
|
||||
ActiveDebugSessionsResponse active_debug_sessions_response = 335;
|
||||
DapStackTraceRequest dap_stack_trace_request = 336;
|
||||
DapStackTraceResponse dap_stack_trace_response = 337;
|
||||
DapScopesRequest dap_scopes_request = 338;
|
||||
DapScopesResponse dap_scopes_response = 339;
|
||||
DapSetVariableValueRequest dap_set_variable_value_request = 340;
|
||||
DapSetVariableValueResponse dap_set_variable_value_response = 341;
|
||||
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
|
||||
UpdateDebugAdapter update_debug_adapter = 307;
|
||||
ShutdownDebugClient shutdown_debug_client = 308;
|
||||
SetDebugClientCapabilities set_debug_client_capabilities = 309;
|
||||
DapNextRequest dap_next_request = 310;
|
||||
DapStepInRequest dap_step_in_request = 311;
|
||||
DapStepOutRequest dap_step_out_request = 312;
|
||||
DapStepBackRequest dap_step_back_request = 313;
|
||||
DapContinueRequest dap_continue_request = 314;
|
||||
DapContinueResponse dap_continue_response = 315;
|
||||
DapPauseRequest dap_pause_request = 316;
|
||||
DapDisconnectRequest dap_disconnect_request = 317;
|
||||
DapTerminateThreadsRequest dap_terminate_threads_request = 318;
|
||||
DapTerminateRequest dap_terminate_request = 319;
|
||||
DapRestartRequest dap_restart_request = 320;
|
||||
UpdateThreadStatus update_thread_status = 321;
|
||||
VariablesRequest variables_request = 322;
|
||||
DapVariables dap_variables = 323;
|
||||
DapRestartStackFrameRequest dap_restart_stack_frame_request = 324;
|
||||
IgnoreBreakpointState ignore_breakpoint_state = 325;
|
||||
ToggleIgnoreBreakpoints toggle_ignore_breakpoints = 326;
|
||||
DapModulesRequest dap_modules_request = 327;
|
||||
DapModulesResponse dap_modules_response = 328;
|
||||
DapLoadedSourcesRequest dap_loaded_sources_request = 329;
|
||||
DapLoadedSourcesResponse dap_loaded_sources_response = 330;
|
||||
DapStackTraceRequest dap_stack_trace_request = 331;
|
||||
DapStackTraceResponse dap_stack_trace_response = 332;
|
||||
DapScopesRequest dap_scopes_request = 333;
|
||||
DapScopesResponse dap_scopes_response = 334;
|
||||
DapSetVariableValueRequest dap_set_variable_value_request = 335;
|
||||
DapSetVariableValueResponse dap_set_variable_value_response = 336;
|
||||
DapEvaluateRequest dap_evaluate_request = 337;
|
||||
DapEvaluateResponse dap_evaluate_response = 338;
|
||||
DapCompletionRequest dap_completion_request = 339;
|
||||
DapCompletionResponse dap_completion_response = 340;
|
||||
DapThreadsRequest dap_threads_request = 341;
|
||||
DapThreadsResponse dap_threads_response = 342;// current max
|
||||
}
|
||||
|
||||
reserved 87 to 88;
|
||||
@@ -2561,51 +2555,35 @@ enum BreakpointKind {
|
||||
Log = 1;
|
||||
}
|
||||
|
||||
message DebuggerSessionEnded {
|
||||
uint64 project_id = 1;
|
||||
uint64 session_id = 2;
|
||||
}
|
||||
|
||||
message ActiveDebugSessionsRequest {
|
||||
uint64 project_id = 1;
|
||||
}
|
||||
|
||||
message ActiveDebugSessionsResponse {
|
||||
repeated DebuggerSession sessions = 1;
|
||||
}
|
||||
|
||||
message DebuggerSession {
|
||||
uint64 session_id = 1;
|
||||
bool ignore_breakpoints = 2;
|
||||
repeated DebugClient clients = 3;
|
||||
message ActiveDebugClientsResponse {
|
||||
repeated DebugClient clients = 1;
|
||||
}
|
||||
|
||||
message DebugClient {
|
||||
uint64 client_id = 1;
|
||||
SetDebugClientCapabilities capabilities = 2;
|
||||
repeated SetDebuggerPanelItem debug_panel_items = 3;
|
||||
bool ignore_breakpoints = 3;
|
||||
}
|
||||
|
||||
message ShutdownDebugClient {
|
||||
uint64 session_id = 1;
|
||||
uint64 client_id = 2;
|
||||
uint64 project_id = 3;
|
||||
uint64 project_id = 1;
|
||||
uint64 session_id = 2;
|
||||
}
|
||||
|
||||
message SetDebugClientCapabilities {
|
||||
uint64 session_id = 1;
|
||||
uint64 client_id = 2;
|
||||
uint64 project_id = 3;
|
||||
bool supports_loaded_sources_request = 4;
|
||||
bool supports_modules_request = 5;
|
||||
bool supports_restart_request = 6;
|
||||
bool supports_set_expression = 7;
|
||||
bool supports_single_thread_execution_requests = 8;
|
||||
bool supports_step_back = 9;
|
||||
bool supports_stepping_granularity = 10;
|
||||
bool supports_terminate_threads_request = 11;
|
||||
bool supports_restart_frame_request = 12;
|
||||
bool supports_clipboard_context = 13;
|
||||
uint64 project_id = 2;
|
||||
bool supports_loaded_sources_request = 3;
|
||||
bool supports_modules_request = 4;
|
||||
bool supports_restart_request = 5;
|
||||
bool supports_set_expression = 6;
|
||||
bool supports_single_thread_execution_requests = 7;
|
||||
bool supports_step_back = 8;
|
||||
bool supports_stepping_granularity = 9;
|
||||
bool supports_terminate_threads_request = 10;
|
||||
bool supports_restart_frame_request = 11;
|
||||
bool supports_clipboard_context = 12;
|
||||
}
|
||||
|
||||
message Breakpoint {
|
||||
@@ -2624,7 +2602,7 @@ message SynchronizeBreakpoints {
|
||||
message SetActiveDebugLine {
|
||||
uint64 project_id = 1;
|
||||
ProjectPath project_path = 2;
|
||||
uint64 client_id = 3;
|
||||
uint64 session_id = 3;
|
||||
uint32 row = 4;
|
||||
}
|
||||
|
||||
@@ -2737,13 +2715,12 @@ message VariablesRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
uint64 thread_id = 3;
|
||||
uint64 session_id = 4;
|
||||
uint64 stack_frame_id = 5;
|
||||
uint64 variables_reference = 6;
|
||||
optional VariablesArgumentsFilter filter = 7;
|
||||
optional uint64 start = 8;
|
||||
optional uint64 count = 9;
|
||||
optional ValueFormat format = 10;
|
||||
uint64 stack_frame_id = 4;
|
||||
uint64 variables_reference = 5;
|
||||
optional VariablesArgumentsFilter filter = 6;
|
||||
optional uint64 start = 7;
|
||||
optional uint64 count = 8;
|
||||
optional ValueFormat format = 9;
|
||||
}
|
||||
|
||||
|
||||
@@ -2911,15 +2888,9 @@ message DapRestartStackFrameRequest {
|
||||
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 {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
uint64 session_id = 3;
|
||||
}
|
||||
|
||||
message IgnoreBreakpointState {
|
||||
@@ -3033,26 +3004,10 @@ message DebuggerModuleList {
|
||||
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 {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
optional uint64 thread_id = 3;
|
||||
uint64 session_id = 4;
|
||||
oneof variant {
|
||||
DebuggerThreadState thread_state = 5;
|
||||
DebuggerStackFrameList stack_frame_list = 6;
|
||||
@@ -3062,8 +3017,6 @@ message UpdateDebugAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
message DapVariables {
|
||||
uint64 client_id = 1;
|
||||
repeated DapVariable variables = 2;
|
||||
|
||||
@@ -249,11 +249,9 @@ messages!(
|
||||
(DapPauseRequest, Background),
|
||||
(DapRestartRequest, Background),
|
||||
(DapRestartStackFrameRequest, Background),
|
||||
(DapShutdownSession, Background),
|
||||
(DapStepBackRequest, Background),
|
||||
(DapStepInRequest, Background),
|
||||
(DapStepOutRequest, Background),
|
||||
(DapTerminateRequest, Background),
|
||||
(DapTerminateThreadsRequest, Background),
|
||||
(DeclineCall, Foreground),
|
||||
(DeleteChannel, Foreground),
|
||||
@@ -416,7 +414,6 @@ messages!(
|
||||
(SetChannelMemberRole, Foreground),
|
||||
(SetChannelVisibility, Foreground),
|
||||
(SetDebugClientCapabilities, Background),
|
||||
(SetDebuggerPanelItem, Background),
|
||||
(SetRoomParticipantRole, Foreground),
|
||||
(ShareProject, Foreground),
|
||||
(ShareProjectResponse, Foreground),
|
||||
@@ -474,9 +471,6 @@ messages!(
|
||||
(DapVariables, Background),
|
||||
(IgnoreBreakpointState, Background),
|
||||
(ToggleIgnoreBreakpoints, Background),
|
||||
(DebuggerSessionEnded, Background),
|
||||
(ActiveDebugSessionsRequest, Foreground),
|
||||
(ActiveDebugSessionsResponse, Foreground),
|
||||
(DapStackTraceRequest, Background),
|
||||
(DapStackTraceResponse, Background),
|
||||
(DapScopesRequest, Background),
|
||||
@@ -489,6 +483,7 @@ messages!(
|
||||
(DapCompletionResponse, Background),
|
||||
(DapThreadsRequest, Background),
|
||||
(DapThreadsResponse, Background),
|
||||
(DapTerminateRequest, Background)
|
||||
);
|
||||
|
||||
request_messages!(
|
||||
@@ -636,18 +631,17 @@ request_messages!(
|
||||
(DapPauseRequest, Ack),
|
||||
(DapDisconnectRequest, Ack),
|
||||
(DapTerminateThreadsRequest, Ack),
|
||||
(DapTerminateRequest, Ack),
|
||||
(DapRestartRequest, Ack),
|
||||
(DapRestartStackFrameRequest, Ack),
|
||||
(DapShutdownSession, Ack),
|
||||
(VariablesRequest, DapVariables),
|
||||
(ActiveDebugSessionsRequest, ActiveDebugSessionsResponse),
|
||||
(DapStackTraceRequest, DapStackTraceResponse),
|
||||
(DapScopesRequest, DapScopesResponse),
|
||||
(DapSetVariableValueRequest, DapSetVariableValueResponse),
|
||||
(DapEvaluateRequest, DapEvaluateResponse),
|
||||
(DapCompletionRequest, DapCompletionResponse),
|
||||
(DapThreadsRequest, DapThreadsResponse),
|
||||
(DapTerminateRequest, Ack),
|
||||
(ShutdownDebugClient, Ack),
|
||||
);
|
||||
|
||||
entity_messages!(
|
||||
@@ -748,7 +742,6 @@ entity_messages!(
|
||||
SynchronizeBreakpoints,
|
||||
SetActiveDebugLine,
|
||||
RemoveActiveDebugLine,
|
||||
SetDebuggerPanelItem,
|
||||
ShutdownDebugClient,
|
||||
SetDebugClientCapabilities,
|
||||
DapNextRequest,
|
||||
@@ -759,22 +752,19 @@ entity_messages!(
|
||||
DapPauseRequest,
|
||||
DapDisconnectRequest,
|
||||
DapTerminateThreadsRequest,
|
||||
DapTerminateRequest,
|
||||
DapRestartRequest,
|
||||
DapRestartStackFrameRequest,
|
||||
DapShutdownSession,
|
||||
UpdateThreadStatus,
|
||||
VariablesRequest,
|
||||
IgnoreBreakpointState,
|
||||
ToggleIgnoreBreakpoints,
|
||||
DebuggerSessionEnded,
|
||||
ActiveDebugSessionsRequest,
|
||||
DapStackTraceRequest,
|
||||
DapScopesRequest,
|
||||
DapSetVariableValueRequest,
|
||||
DapEvaluateRequest,
|
||||
DapCompletionRequest,
|
||||
DapThreadsRequest,
|
||||
DapTerminateRequest
|
||||
);
|
||||
|
||||
entity_messages!(
|
||||
|
||||
@@ -131,6 +131,8 @@ pub struct DebugAdapterConfig {
|
||||
pub cwd: Option<PathBuf>,
|
||||
/// Additional initialization arguments to be sent on DAP initialization
|
||||
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
|
||||
@@ -176,6 +178,7 @@ impl DebugTaskDefinition {
|
||||
program: self.program,
|
||||
cwd: cwd.clone(),
|
||||
initialize_args: self.initialize_args,
|
||||
supports_attach: true,
|
||||
});
|
||||
|
||||
let args: Vec<String> = Vec::new();
|
||||
|
||||
Reference in New Issue
Block a user