Send debug adapter event through project and listen in debug panel
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -3265,6 +3265,7 @@ dependencies = [
|
||||
"editor",
|
||||
"futures 0.3.28",
|
||||
"gpui",
|
||||
"project",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"ui",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
events::{self, Event},
|
||||
requests::{
|
||||
ConfigurationDone, Continue, ContinueArguments, Initialize, InitializeArguments, Launch,
|
||||
LaunchRequestArguments, Next, NextArguments, ScopesResponse, SetBreakpoints,
|
||||
SetBreakpointsArguments, SetBreakpointsResponse, StepIn, StepInArguments, StepOut,
|
||||
StepOutArguments,
|
||||
LaunchRequestArguments, Next, NextArguments, SetBreakpoints, SetBreakpointsArguments,
|
||||
SetBreakpointsResponse, StepIn, StepInArguments, StepOut, StepOutArguments,
|
||||
},
|
||||
transport::{self, Payload, Request, Transport},
|
||||
types::{DebuggerCapabilities, Source, SourceBreakpoint, ThreadId},
|
||||
@@ -13,8 +13,7 @@ use futures::{
|
||||
channel::mpsc::{channel, unbounded, UnboundedReceiver, UnboundedSender},
|
||||
AsyncBufRead, AsyncReadExt, AsyncWrite, SinkExt as _, StreamExt,
|
||||
};
|
||||
use gpui::AsyncAppContext;
|
||||
use serde_json::Value;
|
||||
use gpui::{AppContext, AsyncAppContext};
|
||||
use smol::{
|
||||
io::BufReader,
|
||||
net::TcpStream,
|
||||
@@ -22,6 +21,7 @@ use smol::{
|
||||
};
|
||||
use std::{
|
||||
net::{Ipv4Addr, SocketAddrV4},
|
||||
ops::DerefMut,
|
||||
path::PathBuf,
|
||||
process::Stdio,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
@@ -43,22 +43,25 @@ pub struct DebugAdapterClient {
|
||||
server_tx: UnboundedSender<Payload>,
|
||||
request_count: AtomicU64,
|
||||
thread_id: Option<ThreadId>,
|
||||
client_rx: UnboundedReceiver<Payload>,
|
||||
capabilities: Option<DebuggerCapabilities>,
|
||||
}
|
||||
|
||||
impl DebugAdapterClient {
|
||||
pub async fn new(
|
||||
pub async fn new<F>(
|
||||
transport_type: TransportType,
|
||||
command: &str,
|
||||
args: Vec<&str>,
|
||||
port: u16,
|
||||
project_path: PathBuf,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Self> {
|
||||
event_handler: F,
|
||||
) -> Result<Self>
|
||||
where
|
||||
F: FnMut(events::Event, &mut AppContext) + 'static + Send + Sync + Clone,
|
||||
{
|
||||
match transport_type {
|
||||
TransportType::TCP => {
|
||||
Self::create_tcp_client(command, args, port, project_path, cx).await
|
||||
Self::create_tcp_client(command, args, port, project_path, cx, event_handler).await
|
||||
}
|
||||
TransportType::STDIO => {
|
||||
Self::create_stdio_client(command, args, port, project_path, cx).await
|
||||
@@ -66,13 +69,17 @@ impl DebugAdapterClient {
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_tcp_client(
|
||||
async fn create_tcp_client<F>(
|
||||
command: &str,
|
||||
args: Vec<&str>,
|
||||
port: u16,
|
||||
project_path: PathBuf,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Self> {
|
||||
event_handler: F,
|
||||
) -> Result<Self>
|
||||
where
|
||||
F: FnMut(events::Event, &mut AppContext) + 'static + Send + Sync + Clone,
|
||||
{
|
||||
let mut command = process::Command::new(command);
|
||||
command
|
||||
.current_dir(project_path)
|
||||
@@ -101,6 +108,7 @@ impl DebugAdapterClient {
|
||||
None,
|
||||
Some(process),
|
||||
cx,
|
||||
event_handler,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -114,13 +122,17 @@ impl DebugAdapterClient {
|
||||
todo!("not implemented")
|
||||
}
|
||||
|
||||
pub fn handle_transport(
|
||||
pub fn handle_transport<F>(
|
||||
rx: Box<dyn AsyncBufRead + Unpin + Send>,
|
||||
tx: Box<dyn AsyncWrite + Unpin + Send>,
|
||||
err: Option<Box<dyn AsyncBufRead + Unpin + Send>>,
|
||||
process: Option<Child>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Self> {
|
||||
event_handler: F,
|
||||
) -> Result<Self>
|
||||
where
|
||||
F: FnMut(events::Event, &mut AppContext) + 'static + Send + Sync + Clone,
|
||||
{
|
||||
let (server_rx, server_tx) = Transport::start(rx, tx, err, cx);
|
||||
let (client_tx, client_rx) = unbounded::<Payload>();
|
||||
|
||||
@@ -129,17 +141,37 @@ impl DebugAdapterClient {
|
||||
_process: process,
|
||||
request_count: AtomicU64::new(0),
|
||||
thread_id: Some(ThreadId(1)),
|
||||
client_rx, // TODO: remove this here
|
||||
capabilities: None,
|
||||
};
|
||||
|
||||
cx.spawn(move |_| Self::recv(server_rx, server_tx, client_tx))
|
||||
cx.spawn(move |cx| Self::handle_events(client_rx, event_handler, cx))
|
||||
.detach();
|
||||
|
||||
cx.spawn(move |_| Self::handle_recv(server_rx, server_tx, client_tx))
|
||||
.detach();
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
async fn recv(
|
||||
async fn handle_events<F>(
|
||||
mut client_rx: UnboundedReceiver<Payload>,
|
||||
mut event_handler: F,
|
||||
cx: AsyncAppContext,
|
||||
) -> Result<()>
|
||||
where
|
||||
F: FnMut(events::Event, &mut AppContext) + 'static + Send + Sync + Clone,
|
||||
{
|
||||
while let Some(payload) = client_rx.next().await {
|
||||
cx.update(|cx| match payload {
|
||||
Payload::Event(event) => event_handler(*event, cx),
|
||||
_ => unreachable!(),
|
||||
})?;
|
||||
}
|
||||
|
||||
anyhow::Ok(())
|
||||
}
|
||||
|
||||
async fn handle_recv(
|
||||
mut server_rx: UnboundedReceiver<Payload>,
|
||||
mut server_tx: UnboundedSender<Payload>,
|
||||
mut client_tx: UnboundedSender<Payload>,
|
||||
@@ -185,6 +217,10 @@ impl DebugAdapterClient {
|
||||
self.request_count.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn update_thread_id(&mut self, thread_id: ThreadId) {
|
||||
self.thread_id = Some(thread_id);
|
||||
}
|
||||
|
||||
pub async fn initialize(&mut self) -> Result<DebuggerCapabilities> {
|
||||
let args = InitializeArguments {
|
||||
client_id: Some("zed".to_owned()),
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::types::{DebuggerCapabilities, Source, ThreadId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "event", content = "body")]
|
||||
// seq is omitted as unused and is not sent by some implementations
|
||||
|
||||
@@ -15,6 +15,7 @@ db.workspace = true
|
||||
editor.workspace = true
|
||||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
project.workspace = true
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
ui.workspace = true
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use dap::{
|
||||
client::{DebugAdapterClient, DebugAdapterClientId, TransportType},
|
||||
transport::Payload,
|
||||
};
|
||||
use futures::channel::mpsc::UnboundedReceiver;
|
||||
use anyhow::Result;
|
||||
use dap::client::{DebugAdapterClient, DebugAdapterClientId};
|
||||
use gpui::{
|
||||
actions, Action, AppContext, AsyncWindowContext, EventEmitter, FocusHandle, FocusableView,
|
||||
View, ViewContext, WeakView,
|
||||
Subscription, View, ViewContext, WeakView,
|
||||
};
|
||||
use ui::{
|
||||
div, h_flex,
|
||||
@@ -30,6 +26,7 @@ pub struct DebugPanel {
|
||||
pub focus_handle: FocusHandle,
|
||||
pub size: Pixels,
|
||||
pub workspace: WeakView<Workspace>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
impl DebugPanel {
|
||||
@@ -38,6 +35,35 @@ impl DebugPanel {
|
||||
workspace: WeakView<Workspace>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Self {
|
||||
let project = workspace
|
||||
.update(cx, |workspace, cx| workspace.project().clone())
|
||||
.unwrap();
|
||||
|
||||
let _subscriptions = vec![cx.subscribe(&project, {
|
||||
move |this, event, cx| {
|
||||
if let project::Event::DebugClientStarted(client_id) = event {
|
||||
dbg!(&event, &client_id);
|
||||
}
|
||||
if let project::Event::DebugClientEvent { client_id, event } = event {
|
||||
match event {
|
||||
dap::events::Event::Initialized(_) => todo!(),
|
||||
dap::events::Event::Stopped(_) => todo!(),
|
||||
dap::events::Event::Continued(_) => todo!(),
|
||||
dap::events::Event::Exited(_) => todo!(),
|
||||
dap::events::Event::Terminated(_) => todo!(),
|
||||
dap::events::Event::Thread(_) => todo!(),
|
||||
dap::events::Event::Output(_) => todo!(),
|
||||
dap::events::Event::Breakpoint(_) => todo!(),
|
||||
dap::events::Event::Module(_) => todo!(),
|
||||
dap::events::Event::LoadedSource(_) => todo!(),
|
||||
dap::events::Event::Process(_) => todo!(),
|
||||
dap::events::Event::Capabilities(_) => todo!(),
|
||||
dap::events::Event::Memory(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
})];
|
||||
|
||||
Self {
|
||||
position,
|
||||
zoomed: false,
|
||||
@@ -45,6 +71,7 @@ impl DebugPanel {
|
||||
focus_handle: cx.focus_handle(),
|
||||
size: px(300.),
|
||||
workspace,
|
||||
_subscriptions,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ use workspace::notifications::{DetachAndPromptErr, NotificationId};
|
||||
use workspace::{
|
||||
searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
|
||||
};
|
||||
use workspace::{OpenInTerminal, OpenTerminal, TabBarSettings, Toast,ToggleBreakpoint};
|
||||
use workspace::{OpenInTerminal, OpenTerminal, TabBarSettings, Toast, ToggleBreakpoint};
|
||||
|
||||
use crate::hover_links::find_url;
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ use client::{
|
||||
TypedEnvelope, UserStore,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use dap::client::{DebugAdapterClient, DebugAdapterClientId, TransportType};
|
||||
use collections::{btree_map, hash_map, BTreeMap, HashMap, HashSet, VecDeque};
|
||||
use dap::client::{DebugAdapterClient, DebugAdapterClientId, TransportType};
|
||||
use debounced_delay::DebouncedDelay;
|
||||
use futures::{
|
||||
channel::{
|
||||
@@ -86,7 +86,7 @@ use smol::channel::{Receiver, Sender};
|
||||
use smol::lock::Semaphore;
|
||||
use snippet::Snippet;
|
||||
use std::{
|
||||
borrow::{BorrowMut, Cow},
|
||||
borrow::Cow,
|
||||
cmp::{self, Ordering},
|
||||
convert::TryInto,
|
||||
env,
|
||||
@@ -333,6 +333,11 @@ pub enum Event {
|
||||
Notification(String),
|
||||
LanguageServerPrompt(LanguageServerPromptRequest),
|
||||
LanguageNotFound(Model<Buffer>),
|
||||
DebugClientStarted(DebugAdapterClientId),
|
||||
DebugClientEvent {
|
||||
client_id: DebugAdapterClientId,
|
||||
event: dap::events::Event,
|
||||
},
|
||||
ActiveEntryChanged(Option<ProjectEntryId>),
|
||||
ActivateProjectPanel,
|
||||
WorktreeAdded,
|
||||
@@ -1042,22 +1047,41 @@ impl Project {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn debug_adapter_by_id(
|
||||
&self,
|
||||
id: DebugAdapterClientId,
|
||||
) -> Option<&Arc<DebugAdapterClient>> {
|
||||
self.debug_adapters.get(&id).and_then(|state| match state {
|
||||
DebugAdapterClientState::Starting(_) => None,
|
||||
DebugAdapterClientState::Running(client) => Some(client),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn start_debug_adapter_client(
|
||||
&mut self,
|
||||
id: DebugAdapterClientId,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
let task = cx.spawn(|this, mut cx| async move {
|
||||
let this2 = this.clone();
|
||||
let mut client = DebugAdapterClient::new(
|
||||
TransportType::TCP,
|
||||
"bun",
|
||||
vec![
|
||||
"/Users/remcosmits/Documents/code/vscode-php-debug/out/phpDebug.js",
|
||||
"--server=8130",
|
||||
"--server=8131",
|
||||
],
|
||||
8130,
|
||||
8131,
|
||||
"/Users/remcosmits/Documents/code/symfony_demo".into(),
|
||||
&mut cx,
|
||||
move |event, cx| {
|
||||
this2.update(cx, |_, cx| {
|
||||
cx.emit(Event::DebugClientEvent {
|
||||
client_id: id,
|
||||
event,
|
||||
})
|
||||
});
|
||||
},
|
||||
)
|
||||
.await
|
||||
.log_err()?;
|
||||
@@ -1071,7 +1095,8 @@ impl Project {
|
||||
"/Users/remcosmits/Documents/code/symfony_demo/src/Kernel.php".into(),
|
||||
14,
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
.log_err();
|
||||
|
||||
// configuration done
|
||||
client.configuration_done().await.log_err()?;
|
||||
@@ -1081,12 +1106,15 @@ impl Project {
|
||||
|
||||
let client = Arc::new(client);
|
||||
|
||||
this.update(&mut cx, |this, _| {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
let handle = this
|
||||
.debug_adapters
|
||||
.get_mut(&id)
|
||||
.with_context(|| "Failed to find debug adapter with given id")?;
|
||||
*handle = DebugAdapterClientState::Running(client.clone());
|
||||
|
||||
cx.emit(Event::DebugClientStarted(id));
|
||||
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.log_err();
|
||||
|
||||
Reference in New Issue
Block a user