Move requests into client (#112)
* Move most of the requests into the client state itself. Co-authored-by: Anthony Eid <hello@anthonyeid.me> * WIP * Fix some errors and create new errors * More teardown * Fix detach requests * Move set variable value to dap command * Fix dap command error and add evaluate command * FIx more compiler errors * Fix more compiler errors * Clipppyyyy * FIx more * One more * Fix one more * Use threadId from project instead u64 * Mostly fix stack frame list * More compile errors * More * WIP transfer completions to dap command Co-Authored-By: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com> Co-Authored-By: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> * Finish console completions DapCommand impl * Get Zed to build !! * Fix test compile errors: The debugger tests will still fail * Add threads reqeust to debug session Co-authored-by: Piotr Osiewicz <piotr@zed.dev> --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com> Co-authored-by: Piotr Osiewicz <piotr@zed.dev>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -10228,6 +10228,7 @@ dependencies = [
|
||||
"gpui",
|
||||
"http_client",
|
||||
"image",
|
||||
"indexmap",
|
||||
"itertools 0.14.0",
|
||||
"language",
|
||||
"log",
|
||||
|
||||
@@ -269,7 +269,7 @@ async fn test_debug_panel_item_opens_on_remote(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
});
|
||||
|
||||
let shutdown_client = host_project.update(host_cx, |project, cx| {
|
||||
@@ -368,7 +368,7 @@ async fn test_active_debug_panel_item_set_on_join_project(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
});
|
||||
|
||||
let shutdown_client = host_project.update(host_cx, |project, cx| {
|
||||
@@ -481,7 +481,7 @@ async fn test_debug_panel_remote_button_presses(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
active_debug_panel_item
|
||||
});
|
||||
|
||||
@@ -496,7 +496,7 @@ async fn test_debug_panel_remote_button_presses(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
active_debug_panel_item
|
||||
});
|
||||
|
||||
@@ -1251,7 +1251,9 @@ async fn test_module_list(
|
||||
debug_panel_item.update(cx, |item, cx| {
|
||||
assert_eq!(
|
||||
true,
|
||||
item.capabilities(cx).supports_modules_request.unwrap(),
|
||||
item.capabilities(cx)
|
||||
.and_then(|caps| caps.supports_modules_request)
|
||||
.unwrap(),
|
||||
"Local supports modules request should be true"
|
||||
);
|
||||
|
||||
@@ -1279,7 +1281,9 @@ async fn test_module_list(
|
||||
debug_panel_item.update(cx, |item, cx| {
|
||||
assert_eq!(
|
||||
true,
|
||||
item.capabilities(cx).supports_modules_request.unwrap(),
|
||||
item.capabilities(cx)
|
||||
.and_then(|caps| caps.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));
|
||||
@@ -1310,7 +1314,9 @@ async fn test_module_list(
|
||||
debug_panel_item.update(cx, |item, cx| {
|
||||
assert_eq!(
|
||||
true,
|
||||
item.capabilities(cx).supports_modules_request.unwrap(),
|
||||
item.capabilities(cx)
|
||||
.and_then(|caps| caps.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));
|
||||
@@ -1950,9 +1956,7 @@ async fn test_ignore_breakpoints(
|
||||
let session_id = debug_panel.update(cx, |this, cx| {
|
||||
this.dap_store()
|
||||
.read(cx)
|
||||
.as_remote()
|
||||
.unwrap()
|
||||
.session_by_client_id(&client.id())
|
||||
.session_by_client_id(client.id())
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.id()
|
||||
@@ -1966,7 +1970,7 @@ async fn test_ignore_breakpoints(
|
||||
);
|
||||
assert_eq!(false, breakpoints_ignored);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
active_debug_panel_item
|
||||
});
|
||||
|
||||
@@ -2004,7 +2008,7 @@ async fn test_ignore_breakpoints(
|
||||
active_debug_panel_item.read(cx).are_breakpoints_ignored(cx)
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
|
||||
active_debug_panel_item
|
||||
});
|
||||
@@ -2064,7 +2068,7 @@ async fn test_ignore_breakpoints(
|
||||
|
||||
assert_eq!(true, breakpoints_ignored);
|
||||
assert_eq!(client.id(), debug_panel.client_id());
|
||||
assert_eq!(1, debug_panel.thread_id());
|
||||
assert_eq!(1, debug_panel.thread_id().0);
|
||||
});
|
||||
|
||||
client
|
||||
@@ -2135,7 +2139,7 @@ async fn test_ignore_breakpoints(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
active_debug_panel_item
|
||||
});
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@ const DAP_REQUEST_TIMEOUT: Duration = Duration::from_secs(12);
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct DebugAdapterClientId(pub usize);
|
||||
pub struct DebugAdapterClientId(pub u32);
|
||||
|
||||
impl DebugAdapterClientId {
|
||||
pub fn from_proto(client_id: u64) -> Self {
|
||||
Self(client_id as usize)
|
||||
Self(client_id as u32)
|
||||
}
|
||||
|
||||
pub fn to_proto(&self) -> u64 {
|
||||
@@ -39,6 +39,7 @@ impl DebugAdapterClientId {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a connection to the debug adapter process, either via stdout/stdin or a socket.
|
||||
pub struct DebugAdapterClient {
|
||||
id: DebugAdapterClientId,
|
||||
sequence_count: AtomicU64,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use client::proto::{
|
||||
self, DapChecksum, DapChecksumAlgorithm, DapModule, DapScope, DapScopePresentationHint,
|
||||
DapSource, DapSourcePresentationHint, DapStackFrame, DapVariable, SetDebugClientCapabilities,
|
||||
self, DapChecksum, DapChecksumAlgorithm, DapEvaluateContext, DapModule, DapScope,
|
||||
DapScopePresentationHint, DapSource, DapSourcePresentationHint, DapStackFrame, DapVariable,
|
||||
SetDebugClientCapabilities,
|
||||
};
|
||||
use dap_types::{
|
||||
Capabilities, OutputEventCategory, OutputEventGroup, ScopePresentationHint, Source,
|
||||
@@ -490,3 +491,150 @@ impl ProtoConversion for dap_types::OutputEventGroup {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtoConversion for dap_types::CompletionItem {
|
||||
type ProtoType = proto::DapCompletionItem;
|
||||
type Output = Self;
|
||||
|
||||
fn to_proto(&self) -> Self::ProtoType {
|
||||
proto::DapCompletionItem {
|
||||
label: self.label.clone(),
|
||||
text: self.text.clone(),
|
||||
detail: self.detail.clone(),
|
||||
typ: self
|
||||
.type_
|
||||
.as_ref()
|
||||
.map(ProtoConversion::to_proto)
|
||||
.map(|typ| typ.into()),
|
||||
start: self.start,
|
||||
length: self.length,
|
||||
selection_start: self.selection_start,
|
||||
selection_length: self.selection_length,
|
||||
sort_text: self.sort_text.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(payload: Self::ProtoType) -> Self {
|
||||
let typ = payload.typ(); // todo(debugger): This might be a potential issue/bug because it defaults to a type when it's None
|
||||
|
||||
Self {
|
||||
label: payload.label,
|
||||
detail: payload.detail,
|
||||
sort_text: payload.sort_text,
|
||||
text: payload.text.clone(),
|
||||
type_: Some(dap_types::CompletionItemType::from_proto(typ)),
|
||||
start: payload.start,
|
||||
length: payload.length,
|
||||
selection_start: payload.selection_start,
|
||||
selection_length: payload.selection_length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtoConversion for dap_types::EvaluateArgumentsContext {
|
||||
type ProtoType = DapEvaluateContext;
|
||||
type Output = Self;
|
||||
|
||||
fn to_proto(&self) -> Self::ProtoType {
|
||||
match self {
|
||||
dap_types::EvaluateArgumentsContext::Variables => {
|
||||
proto::DapEvaluateContext::EvaluateVariables
|
||||
}
|
||||
dap_types::EvaluateArgumentsContext::Watch => proto::DapEvaluateContext::Watch,
|
||||
dap_types::EvaluateArgumentsContext::Hover => proto::DapEvaluateContext::Hover,
|
||||
dap_types::EvaluateArgumentsContext::Repl => proto::DapEvaluateContext::Repl,
|
||||
dap_types::EvaluateArgumentsContext::Clipboard => proto::DapEvaluateContext::Clipboard,
|
||||
dap_types::EvaluateArgumentsContext::Unknown => {
|
||||
proto::DapEvaluateContext::EvaluateUnknown
|
||||
}
|
||||
_ => proto::DapEvaluateContext::EvaluateUnknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(payload: Self::ProtoType) -> Self {
|
||||
match payload {
|
||||
proto::DapEvaluateContext::EvaluateVariables => {
|
||||
dap_types::EvaluateArgumentsContext::Variables
|
||||
}
|
||||
proto::DapEvaluateContext::Watch => dap_types::EvaluateArgumentsContext::Watch,
|
||||
proto::DapEvaluateContext::Hover => dap_types::EvaluateArgumentsContext::Hover,
|
||||
proto::DapEvaluateContext::Repl => dap_types::EvaluateArgumentsContext::Repl,
|
||||
proto::DapEvaluateContext::Clipboard => dap_types::EvaluateArgumentsContext::Clipboard,
|
||||
proto::DapEvaluateContext::EvaluateUnknown => {
|
||||
dap_types::EvaluateArgumentsContext::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtoConversion for dap_types::CompletionItemType {
|
||||
type ProtoType = proto::DapCompletionItemType;
|
||||
type Output = Self;
|
||||
|
||||
fn to_proto(&self) -> Self::ProtoType {
|
||||
match self {
|
||||
dap_types::CompletionItemType::Class => proto::DapCompletionItemType::Class,
|
||||
dap_types::CompletionItemType::Color => proto::DapCompletionItemType::Color,
|
||||
dap_types::CompletionItemType::Constructor => proto::DapCompletionItemType::Constructor,
|
||||
dap_types::CompletionItemType::Customcolor => proto::DapCompletionItemType::Customcolor,
|
||||
dap_types::CompletionItemType::Enum => proto::DapCompletionItemType::Enum,
|
||||
dap_types::CompletionItemType::Field => proto::DapCompletionItemType::Field,
|
||||
dap_types::CompletionItemType::File => proto::DapCompletionItemType::CompletionItemFile,
|
||||
dap_types::CompletionItemType::Function => proto::DapCompletionItemType::Function,
|
||||
dap_types::CompletionItemType::Interface => proto::DapCompletionItemType::Interface,
|
||||
dap_types::CompletionItemType::Keyword => proto::DapCompletionItemType::Keyword,
|
||||
dap_types::CompletionItemType::Method => proto::DapCompletionItemType::Method,
|
||||
dap_types::CompletionItemType::Module => proto::DapCompletionItemType::Module,
|
||||
dap_types::CompletionItemType::Property => proto::DapCompletionItemType::Property,
|
||||
dap_types::CompletionItemType::Reference => proto::DapCompletionItemType::Reference,
|
||||
dap_types::CompletionItemType::Snippet => proto::DapCompletionItemType::Snippet,
|
||||
dap_types::CompletionItemType::Text => proto::DapCompletionItemType::Text,
|
||||
dap_types::CompletionItemType::Unit => proto::DapCompletionItemType::Unit,
|
||||
dap_types::CompletionItemType::Value => proto::DapCompletionItemType::Value,
|
||||
dap_types::CompletionItemType::Variable => proto::DapCompletionItemType::Variable,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(payload: Self::ProtoType) -> Self {
|
||||
match payload {
|
||||
proto::DapCompletionItemType::Class => dap_types::CompletionItemType::Class,
|
||||
proto::DapCompletionItemType::Color => dap_types::CompletionItemType::Color,
|
||||
proto::DapCompletionItemType::CompletionItemFile => dap_types::CompletionItemType::File,
|
||||
proto::DapCompletionItemType::Constructor => dap_types::CompletionItemType::Constructor,
|
||||
proto::DapCompletionItemType::Customcolor => dap_types::CompletionItemType::Customcolor,
|
||||
proto::DapCompletionItemType::Enum => dap_types::CompletionItemType::Enum,
|
||||
proto::DapCompletionItemType::Field => dap_types::CompletionItemType::Field,
|
||||
proto::DapCompletionItemType::Function => dap_types::CompletionItemType::Function,
|
||||
proto::DapCompletionItemType::Interface => dap_types::CompletionItemType::Interface,
|
||||
proto::DapCompletionItemType::Keyword => dap_types::CompletionItemType::Keyword,
|
||||
proto::DapCompletionItemType::Method => dap_types::CompletionItemType::Method,
|
||||
proto::DapCompletionItemType::Module => dap_types::CompletionItemType::Module,
|
||||
proto::DapCompletionItemType::Property => dap_types::CompletionItemType::Property,
|
||||
proto::DapCompletionItemType::Reference => dap_types::CompletionItemType::Reference,
|
||||
proto::DapCompletionItemType::Snippet => dap_types::CompletionItemType::Snippet,
|
||||
proto::DapCompletionItemType::Text => dap_types::CompletionItemType::Text,
|
||||
proto::DapCompletionItemType::Unit => dap_types::CompletionItemType::Unit,
|
||||
proto::DapCompletionItemType::Value => dap_types::CompletionItemType::Value,
|
||||
proto::DapCompletionItemType::Variable => dap_types::CompletionItemType::Variable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtoConversion for dap_types::Thread {
|
||||
type ProtoType = proto::DapThread;
|
||||
type Output = Self;
|
||||
|
||||
fn to_proto(&self) -> Self::ProtoType {
|
||||
proto::DapThread {
|
||||
id: self.id,
|
||||
name: self.name.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(payload: Self::ProtoType) -> Self {
|
||||
Self {
|
||||
id: payload.id,
|
||||
name: payload.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,9 +174,13 @@ impl LogStore {
|
||||
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))
|
||||
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()?))
|
||||
},
|
||||
)
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -587,9 +591,8 @@ impl DapLogView {
|
||||
session_name: session.read(cx).name(),
|
||||
clients: {
|
||||
let mut clients = session
|
||||
.read(cx)
|
||||
.as_local()?
|
||||
.clients()
|
||||
.read_with(cx, |session, cx| session.clients(cx))
|
||||
.iter()
|
||||
.map(|client| DapMenuSubItem {
|
||||
client_id: client.id(),
|
||||
client_name: client.adapter_id(),
|
||||
|
||||
@@ -53,14 +53,14 @@ pub(crate) struct AttachModal {
|
||||
impl AttachModal {
|
||||
pub fn new(
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
dap_store: Entity<DapStore>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let picker = cx.new(|cx| {
|
||||
Picker::uniform_list(
|
||||
AttachModalDelegate::new(*session_id, *client_id, dap_store),
|
||||
AttachModalDelegate::new(*session_id, client_id, dap_store),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
@@ -130,8 +130,10 @@ impl PickerDelegate for AttachModalDelegate {
|
||||
if let Some(processes) = this.delegate.candidates.clone() {
|
||||
processes
|
||||
} else {
|
||||
let Some((_, client)) = this.delegate.dap_store.update(cx, |store, cx| {
|
||||
store.client_by_id(&this.delegate.client_id, cx)
|
||||
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())
|
||||
}) else {
|
||||
return Vec::new();
|
||||
};
|
||||
@@ -222,7 +224,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.session_id, self.client_id, candidate.pid, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
|
||||
|
||||
@@ -2,27 +2,24 @@ use crate::{
|
||||
stack_frame_list::{StackFrameList, StackFrameListEvent},
|
||||
variable_list::VariableList,
|
||||
};
|
||||
use dap::{
|
||||
client::DebugAdapterClientId, proto_conversions::ProtoConversion, OutputEvent, OutputEventGroup,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use dap::{client::DebugAdapterClientId, OutputEvent, OutputEventGroup};
|
||||
use editor::{
|
||||
display_map::{Crease, CreaseId},
|
||||
Anchor, CompletionProvider, Editor, EditorElement, EditorStyle, FoldPlaceholder,
|
||||
};
|
||||
use fuzzy::StringMatchCandidate;
|
||||
use gpui::{Context, Entity, Render, Subscription, Task, TextStyle, WeakEntity};
|
||||
use language::{Buffer, CodeLabel, LanguageServerId, ToOffsetUtf16};
|
||||
use language::{Buffer, CodeLabel, LanguageServerId};
|
||||
use menu::Confirm;
|
||||
use project::{
|
||||
debugger::{dap_session::DebugSession, dap_store::DapStore},
|
||||
debugger::dap_session::{CompletionsQuery, DebugSession},
|
||||
Completion,
|
||||
};
|
||||
use rpc::proto;
|
||||
use settings::Settings;
|
||||
use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};
|
||||
use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc, usize};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{prelude::*, ButtonLike, Disclosure, ElevationIndex};
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct OutputGroup {
|
||||
pub start: Anchor,
|
||||
@@ -36,7 +33,6 @@ pub struct Console {
|
||||
groups: Vec<OutputGroup>,
|
||||
console: Entity<Editor>,
|
||||
query_bar: Entity<Editor>,
|
||||
dap_store: Entity<DapStore>,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
@@ -47,8 +43,7 @@ pub struct Console {
|
||||
impl Console {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
dap_store: Entity<DapStore>,
|
||||
client_id: DebugAdapterClientId,
|
||||
stack_frame_list: Entity<StackFrameList>,
|
||||
variable_list: Entity<VariableList>,
|
||||
window: &mut Window,
|
||||
@@ -91,12 +86,11 @@ impl Console {
|
||||
Self {
|
||||
session,
|
||||
console,
|
||||
dap_store,
|
||||
query_bar,
|
||||
variable_list,
|
||||
_subscriptions,
|
||||
stack_frame_list,
|
||||
client_id: *client_id,
|
||||
client_id,
|
||||
groups: Vec::default(),
|
||||
}
|
||||
}
|
||||
@@ -111,8 +105,9 @@ impl Console {
|
||||
&self.query_bar
|
||||
}
|
||||
|
||||
fn is_local(&self, cx: &Context<Self>) -> bool {
|
||||
self.dap_store.read(cx).as_local().is_some()
|
||||
fn is_local(&self, _cx: &Context<Self>) -> bool {
|
||||
// todo(debugger): Fix this function
|
||||
true
|
||||
}
|
||||
|
||||
fn handle_stack_frame_list_events(
|
||||
@@ -128,21 +123,6 @@ impl Console {
|
||||
}
|
||||
|
||||
pub fn add_message(&mut self, event: OutputEvent, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if let Some((client, project_id)) = self.dap_store.read(cx).downstream_client() {
|
||||
client
|
||||
.send(proto::UpdateDebugAdapter {
|
||||
project_id: *project_id,
|
||||
client_id: self.client_id.to_proto(),
|
||||
thread_id: None,
|
||||
session_id: self.session.read(cx).id().to_proto(),
|
||||
variant: Some(proto::update_debug_adapter::Variant::OutputEvent(
|
||||
event.to_proto(),
|
||||
)),
|
||||
})
|
||||
.log_err();
|
||||
return;
|
||||
}
|
||||
|
||||
self.console.update(cx, |console, cx| {
|
||||
let output = event.output.trim_end().to_string();
|
||||
|
||||
@@ -254,45 +234,49 @@ impl Console {
|
||||
expression
|
||||
});
|
||||
|
||||
let evaluate_task = self.dap_store.update(cx, |store, cx| {
|
||||
store.evaluate(
|
||||
&self.client_id,
|
||||
self.stack_frame_list.read(cx).current_stack_frame_id(),
|
||||
let Some(client_state) = self.session.read(cx).client_state(self.client_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
client_state.update(cx, |state, cx| {
|
||||
state.evaluate(
|
||||
expression,
|
||||
dap::EvaluateArgumentsContext::Variables,
|
||||
Some(dap::EvaluateArgumentsContext::Variables),
|
||||
Some(self.stack_frame_list.read(cx).current_stack_frame_id()),
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
let weak_console = cx.weak_entity();
|
||||
// TODO(debugger): make this work again
|
||||
// let weak_console = cx.weak_entity();
|
||||
|
||||
window
|
||||
.spawn(cx, |mut cx| async move {
|
||||
let response = evaluate_task.await?;
|
||||
// window
|
||||
// .spawn(cx, |mut cx| async move {
|
||||
// let response = evaluate_task.await?;
|
||||
|
||||
weak_console.update_in(&mut cx, |console, window, cx| {
|
||||
console.add_message(
|
||||
OutputEvent {
|
||||
category: None,
|
||||
output: response.result,
|
||||
group: None,
|
||||
variables_reference: Some(response.variables_reference),
|
||||
source: None,
|
||||
line: None,
|
||||
column: None,
|
||||
data: None,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
// weak_console.update_in(&mut cx, |console, window, cx| {
|
||||
// console.add_message(
|
||||
// OutputEvent {
|
||||
// category: None,
|
||||
// output: response.result,
|
||||
// group: None,
|
||||
// variables_reference: Some(response.variables_reference),
|
||||
// source: None,
|
||||
// line: None,
|
||||
// column: None,
|
||||
// data: None,
|
||||
// },
|
||||
// window,
|
||||
// cx,
|
||||
// );
|
||||
|
||||
console.variable_list.update(cx, |variable_list, cx| {
|
||||
variable_list.invalidate(window, cx);
|
||||
})
|
||||
})
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
// console.variable_list.update(cx, |variable_list, cx| {
|
||||
// variable_list.invalidate(window, cx);
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// .detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
fn render_console(&self, cx: &Context<Self>) -> impl IntoElement {
|
||||
@@ -383,9 +367,10 @@ impl CompletionProvider for ConsoleQueryBarCompletionProvider {
|
||||
|
||||
let support_completions = console
|
||||
.read(cx)
|
||||
.dap_store
|
||||
.session
|
||||
.read(cx)
|
||||
.capabilities_by_id(&console.read(cx).client_id, cx)
|
||||
.client_state(console.read(cx).client_id)
|
||||
.map(|state| state.read(cx).capabilities())
|
||||
.map(|caps| caps.supports_completions_request)
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
@@ -470,7 +455,6 @@ impl ConsoleQueryBarCompletionProvider {
|
||||
});
|
||||
|
||||
let query = buffer.read(cx).text();
|
||||
let start_position = buffer.read(cx).anchor_before(0);
|
||||
|
||||
cx.spawn(|_, cx| async move {
|
||||
let matches = fuzzy::match_strings(
|
||||
@@ -489,14 +473,14 @@ impl ConsoleQueryBarCompletionProvider {
|
||||
let variable_value = variables.get(&string_match.string)?;
|
||||
|
||||
Some(project::Completion {
|
||||
old_range: start_position..buffer_position,
|
||||
old_range: buffer_position..buffer_position,
|
||||
new_text: string_match.string.clone(),
|
||||
label: CodeLabel {
|
||||
filter_range: 0..string_match.string.len(),
|
||||
text: format!("{} {}", string_match.string.clone(), variable_value),
|
||||
runs: Vec::new(),
|
||||
},
|
||||
server_id: LanguageServerId(0), // TODO debugger: read from client
|
||||
server_id: LanguageServerId(usize::MAX),
|
||||
documentation: None,
|
||||
lsp_completion: Default::default(),
|
||||
confirm: None,
|
||||
@@ -514,20 +498,21 @@ impl ConsoleQueryBarCompletionProvider {
|
||||
buffer_position: language::Anchor,
|
||||
cx: &mut Context<Editor>,
|
||||
) -> gpui::Task<gpui::Result<Vec<project::Completion>>> {
|
||||
let text = buffer.read(cx).text();
|
||||
let start_position = buffer.read(cx).anchor_before(0);
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let client_id = console.read(cx).client_id;
|
||||
|
||||
let completion_task = console.update(cx, |console, cx| {
|
||||
console.dap_store.update(cx, |store, cx| {
|
||||
store.completions(
|
||||
&console.client_id,
|
||||
console.stack_frame_list.read(cx).current_stack_frame_id(),
|
||||
text,
|
||||
buffer_position.to_offset_utf16(&snapshot).0 as u64,
|
||||
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());
|
||||
|
||||
state.completions(
|
||||
CompletionsQuery::new(buffer.read(cx), buffer_position, frame_id),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
Task::ready(Err(anyhow!("failed to fetch completions")))
|
||||
}
|
||||
});
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
@@ -535,14 +520,14 @@ impl ConsoleQueryBarCompletionProvider {
|
||||
.await?
|
||||
.iter()
|
||||
.map(|completion| project::Completion {
|
||||
old_range: start_position..buffer_position,
|
||||
old_range: buffer_position..buffer_position, // TODO(debugger): change this
|
||||
new_text: completion.text.clone().unwrap_or(completion.label.clone()),
|
||||
label: CodeLabel {
|
||||
filter_range: 0..completion.label.len(),
|
||||
text: completion.label.clone(),
|
||||
runs: Vec::new(),
|
||||
},
|
||||
server_id: LanguageServerId(0), // TODO debugger: read from client
|
||||
server_id: LanguageServerId(usize::MAX),
|
||||
documentation: None,
|
||||
lsp_completion: Default::default(),
|
||||
confirm: None,
|
||||
|
||||
@@ -16,8 +16,10 @@ use gpui::{
|
||||
Focusable, Subscription, Task, WeakEntity,
|
||||
};
|
||||
use project::{
|
||||
debugger::dap_session::DebugSessionId,
|
||||
debugger::dap_store::{DapStore, DapStoreEvent},
|
||||
debugger::{
|
||||
dap_session::{DebugSessionId, ThreadId},
|
||||
dap_store::{DapStore, DapStoreEvent},
|
||||
},
|
||||
terminals::TerminalKind,
|
||||
};
|
||||
use rpc::proto::{self, SetDebuggerPanelItem, UpdateDebugAdapter};
|
||||
@@ -118,7 +120,7 @@ pub struct DebugPanel {
|
||||
workspace: WeakEntity<Workspace>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
message_queue: HashMap<DebugAdapterClientId, VecDeque<OutputEvent>>,
|
||||
thread_states: BTreeMap<(DebugAdapterClientId, u64), Entity<ThreadState>>,
|
||||
thread_states: BTreeMap<(DebugAdapterClientId, ThreadId), Entity<ThreadState>>,
|
||||
}
|
||||
|
||||
impl DebugPanel {
|
||||
@@ -157,7 +159,7 @@ impl DebugPanel {
|
||||
cx.subscribe_in(&project, window, {
|
||||
move |this: &mut Self, _, event, window, cx| match event {
|
||||
project::Event::DebugClientStarted((session_id, client_id)) => {
|
||||
this.handle_debug_client_started(session_id, client_id, window, cx);
|
||||
this.handle_debug_client_started(session_id, *client_id, window, cx);
|
||||
}
|
||||
project::Event::DebugClientEvent {
|
||||
session_id,
|
||||
@@ -166,14 +168,14 @@ impl DebugPanel {
|
||||
} => match message {
|
||||
Message::Event(event) => {
|
||||
this.handle_debug_client_events(
|
||||
session_id, client_id, event, window, cx,
|
||||
session_id, *client_id, event, window, cx,
|
||||
);
|
||||
}
|
||||
Message::Request(request) => {
|
||||
if StartDebugging::COMMAND == request.command {
|
||||
this.handle_start_debugging_request(
|
||||
session_id,
|
||||
client_id,
|
||||
*client_id,
|
||||
request.seq,
|
||||
request.arguments.clone(),
|
||||
cx,
|
||||
@@ -181,7 +183,7 @@ impl DebugPanel {
|
||||
} else if RunInTerminal::COMMAND == request.command {
|
||||
this.handle_run_in_terminal_request(
|
||||
session_id,
|
||||
client_id,
|
||||
*client_id,
|
||||
request.seq,
|
||||
request.arguments.clone(),
|
||||
window,
|
||||
@@ -335,8 +337,8 @@ impl DebugPanel {
|
||||
|
||||
pub fn debug_panel_item_by_client(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
client_id: DebugAdapterClientId,
|
||||
thread_id: ThreadId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<Entity<DebugPanelItem>> {
|
||||
self.pane
|
||||
@@ -346,7 +348,7 @@ impl DebugPanel {
|
||||
.find(|item| {
|
||||
let item = item.read(cx);
|
||||
|
||||
&item.client_id() == client_id && item.thread_id() == thread_id
|
||||
item.client_id() == client_id && item.thread_id() == thread_id
|
||||
})
|
||||
}
|
||||
|
||||
@@ -362,17 +364,23 @@ impl DebugPanel {
|
||||
let thread_panel = item.downcast::<DebugPanelItem>().unwrap();
|
||||
|
||||
let thread_id = thread_panel.read(cx).thread_id();
|
||||
let session_id = thread_panel.read(cx).session().read(cx).id();
|
||||
let client_id = thread_panel.read(cx).client_id();
|
||||
|
||||
self.thread_states.remove(&(client_id, thread_id));
|
||||
|
||||
cx.notify();
|
||||
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.terminate_threads(&session_id, &client_id, Some(vec![thread_id; 1]), cx)
|
||||
.detach()
|
||||
let Some(client_state) = thread_panel
|
||||
.read(cx)
|
||||
.session()
|
||||
.read(cx)
|
||||
.client_state(client_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
client_state.update(cx, |state, cx| {
|
||||
state.terminate_threads(Some(vec![thread_id; 1]), cx);
|
||||
});
|
||||
}
|
||||
pane::Event::Remove { .. } => cx.emit(PanelEvent::Close),
|
||||
@@ -405,7 +413,7 @@ impl DebugPanel {
|
||||
fn handle_start_debugging_request(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
seq: u64,
|
||||
request_args: Option<Value>,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -426,7 +434,7 @@ impl DebugPanel {
|
||||
fn handle_run_in_terminal_request(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
seq: u64,
|
||||
request_args: Option<Value>,
|
||||
window: &mut Window,
|
||||
@@ -519,7 +527,7 @@ impl DebugPanel {
|
||||
});
|
||||
|
||||
let session_id = *session_id;
|
||||
let client_id = *client_id;
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
// Ensure a response is always sent, even in error cases,
|
||||
// to maintain proper communication with the debug adapter
|
||||
@@ -577,14 +585,7 @@ impl DebugPanel {
|
||||
|
||||
let respond_task = this.update(&mut cx, |this, cx| {
|
||||
this.dap_store.update(cx, |store, cx| {
|
||||
store.respond_to_run_in_terminal(
|
||||
&session_id,
|
||||
&client_id,
|
||||
success,
|
||||
seq,
|
||||
body,
|
||||
cx,
|
||||
)
|
||||
store.respond_to_run_in_terminal(&session_id, client_id, success, seq, body, cx)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -596,7 +597,7 @@ impl DebugPanel {
|
||||
fn handle_debug_client_started(
|
||||
&self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -610,14 +611,12 @@ impl DebugPanel {
|
||||
};
|
||||
|
||||
let session_id = *session_id;
|
||||
let client_id = *client_id;
|
||||
let workspace = self.workspace.clone();
|
||||
let request_type = session.configuration().request.clone();
|
||||
cx.spawn_in(window, |this, mut cx| async move {
|
||||
let task = this.update(&mut cx, |this, cx| {
|
||||
this.dap_store.update(cx, |store, cx| {
|
||||
store.initialize(&session_id, &client_id, cx)
|
||||
})
|
||||
this.dap_store
|
||||
.update(cx, |store, cx| store.initialize(&session_id, client_id, cx))
|
||||
})?;
|
||||
|
||||
task.await?;
|
||||
@@ -626,7 +625,7 @@ impl DebugPanel {
|
||||
DebugRequestType::Launch => {
|
||||
let task = this.update(&mut cx, |this, cx| {
|
||||
this.dap_store
|
||||
.update(cx, |store, cx| store.launch(&session_id, &client_id, cx))
|
||||
.update(cx, |store, cx| store.launch(&session_id, client_id, cx))
|
||||
});
|
||||
|
||||
task?.await
|
||||
@@ -635,7 +634,7 @@ impl DebugPanel {
|
||||
if let Some(process_id) = config.process_id {
|
||||
let task = this.update(&mut cx, |this, cx| {
|
||||
this.dap_store.update(cx, |store, cx| {
|
||||
store.attach(&session_id, &client_id, process_id, cx)
|
||||
store.attach(&session_id, client_id, process_id, cx)
|
||||
})
|
||||
})?;
|
||||
|
||||
@@ -646,7 +645,7 @@ impl DebugPanel {
|
||||
workspace.toggle_modal(window, cx, |window, cx| {
|
||||
AttachModal::new(
|
||||
&session_id,
|
||||
&client_id,
|
||||
client_id,
|
||||
this.dap_store.clone(),
|
||||
window,
|
||||
cx,
|
||||
@@ -680,28 +679,28 @@ impl DebugPanel {
|
||||
fn handle_debug_client_events(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &Events,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
match event {
|
||||
Events::Initialized(event) => {
|
||||
self.handle_initialized_event(&session_id, &client_id, event, cx)
|
||||
self.handle_initialized_event(&session_id, client_id, event, cx)
|
||||
}
|
||||
Events::Stopped(event) => {
|
||||
self.handle_stopped_event(&session_id, &client_id, event, window, cx)
|
||||
self.handle_stopped_event(&session_id, client_id, event, window, cx)
|
||||
}
|
||||
Events::Continued(event) => self.handle_continued_event(&client_id, event, cx),
|
||||
Events::Exited(event) => self.handle_exited_event(&client_id, event, cx),
|
||||
Events::Continued(event) => self.handle_continued_event(client_id, event, cx),
|
||||
Events::Exited(event) => self.handle_exited_event(client_id, event, cx),
|
||||
Events::Terminated(event) => {
|
||||
self.handle_terminated_event(&session_id, &client_id, event, cx)
|
||||
self.handle_terminated_event(&session_id, client_id, event, cx)
|
||||
}
|
||||
Events::Thread(event) => self.handle_thread_event(&client_id, event, cx),
|
||||
Events::Output(event) => self.handle_output_event(&client_id, event, cx),
|
||||
Events::Thread(event) => self.handle_thread_event(client_id, event, cx),
|
||||
Events::Output(event) => self.handle_output_event(client_id, event, cx),
|
||||
Events::Breakpoint(_) => {}
|
||||
Events::Module(event) => self.handle_module_event(&client_id, event, cx),
|
||||
Events::LoadedSource(event) => self.handle_loaded_source_event(&client_id, event, cx),
|
||||
Events::Module(event) => self.handle_module_event(client_id, event, cx),
|
||||
Events::LoadedSource(event) => self.handle_loaded_source_event(client_id, event, cx),
|
||||
Events::Capabilities(event) => {
|
||||
self.handle_capabilities_changed_event(session_id, client_id, event, cx);
|
||||
}
|
||||
@@ -718,26 +717,25 @@ impl DebugPanel {
|
||||
fn handle_initialized_event(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
capabilities: &Option<Capabilities>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(capabilities) = capabilities {
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store.update_capabilities_for_client(&session_id, &client_id, capabilities, cx);
|
||||
store.update_capabilities_for_client(&session_id, client_id, capabilities, cx);
|
||||
});
|
||||
|
||||
cx.emit(DebugPanelEvent::CapabilitiesChanged(*client_id));
|
||||
cx.emit(DebugPanelEvent::CapabilitiesChanged(client_id));
|
||||
}
|
||||
|
||||
let session_id = *session_id;
|
||||
let client_id = *client_id;
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
this.update(&mut cx, |debug_panel, cx| {
|
||||
debug_panel.workspace.update(cx, |workspace, cx| {
|
||||
workspace.project().update(cx, |project, cx| {
|
||||
project.initial_send_breakpoints(&session_id, &client_id, cx)
|
||||
project.initial_send_breakpoints(&session_id, client_id, cx)
|
||||
})
|
||||
})
|
||||
})??
|
||||
@@ -746,7 +744,7 @@ impl DebugPanel {
|
||||
this.update(&mut cx, |debug_panel, cx| {
|
||||
debug_panel
|
||||
.dap_store
|
||||
.update(cx, |store, cx| store.configuration_done(&client_id, cx))
|
||||
.update(cx, |store, cx| store.configuration_done(client_id, cx))
|
||||
})?
|
||||
.await
|
||||
})
|
||||
@@ -755,22 +753,22 @@ impl DebugPanel {
|
||||
|
||||
fn handle_continued_event(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &ContinuedEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
cx.emit(DebugPanelEvent::Continued((*client_id, event.clone())));
|
||||
cx.emit(DebugPanelEvent::Continued((client_id, event.clone())));
|
||||
}
|
||||
|
||||
fn handle_stopped_event(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &StoppedEvent,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(thread_id) = event.thread_id else {
|
||||
let Some(thread_id) = event.thread_id.map(|thread_id| ThreadId(thread_id)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -783,8 +781,6 @@ impl DebugPanel {
|
||||
return; // this can/should never happen
|
||||
};
|
||||
|
||||
let client_id = *client_id;
|
||||
|
||||
cx.spawn_in(window, {
|
||||
let event = event.clone();
|
||||
|this, mut cx| async move {
|
||||
@@ -800,17 +796,16 @@ impl DebugPanel {
|
||||
thread_state.status = ThreadStatus::Stopped;
|
||||
});
|
||||
|
||||
let existing_item = this.debug_panel_item_by_client(&client_id, thread_id, cx);
|
||||
let existing_item = this.debug_panel_item_by_client(client_id, thread_id, cx);
|
||||
if existing_item.is_none() {
|
||||
let debug_panel = cx.entity();
|
||||
this.pane.update(cx, |pane, cx| {
|
||||
let tab = cx.new(|cx| {
|
||||
DebugPanelItem::new(
|
||||
session,
|
||||
&client_id,
|
||||
client_id,
|
||||
thread_id,
|
||||
thread_state,
|
||||
this.dap_store.clone(),
|
||||
&debug_panel,
|
||||
this.workspace.clone(),
|
||||
window,
|
||||
@@ -858,13 +853,13 @@ impl DebugPanel {
|
||||
|
||||
fn handle_thread_event(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &ThreadEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let thread_id = event.thread_id;
|
||||
let thread_id = ThreadId(event.thread_id);
|
||||
|
||||
if let Some(thread_state) = self.thread_states.get(&(*client_id, thread_id)) {
|
||||
if let Some(thread_state) = self.thread_states.get(&(client_id, thread_id)) {
|
||||
if !thread_state.read(cx).stopped && event.reason == ThreadEventReason::Exited {
|
||||
const MESSAGE: &'static str = "Debug session exited without hitting breakpoints\n\nTry adding a breakpoint, or define the correct path mapping for your debugger.";
|
||||
|
||||
@@ -876,26 +871,26 @@ impl DebugPanel {
|
||||
|
||||
if event.reason == ThreadEventReason::Started {
|
||||
self.thread_states
|
||||
.insert((*client_id, thread_id), cx.new(|_| ThreadState::default()));
|
||||
.insert((client_id, thread_id), cx.new(|_| ThreadState::default()));
|
||||
}
|
||||
|
||||
cx.emit(DebugPanelEvent::Thread((*client_id, event.clone())));
|
||||
cx.emit(DebugPanelEvent::Thread((client_id, event.clone())));
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn handle_exited_event(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
_: &ExitedEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
cx.emit(DebugPanelEvent::Exited(*client_id));
|
||||
cx.emit(DebugPanelEvent::Exited(client_id));
|
||||
}
|
||||
|
||||
fn handle_terminated_event(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &Option<TerminatedEvent>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -903,7 +898,7 @@ impl DebugPanel {
|
||||
|
||||
for (_, thread_state) in self
|
||||
.thread_states
|
||||
.range_mut(&(*client_id, u64::MIN)..&(*client_id, u64::MAX))
|
||||
.range_mut(&(client_id, ThreadId::MIN)..&(client_id, ThreadId::MAX))
|
||||
{
|
||||
thread_state.update(cx, |thread_state, cx| {
|
||||
thread_state.status = ThreadStatus::Ended;
|
||||
@@ -917,9 +912,17 @@ impl DebugPanel {
|
||||
.as_ref()
|
||||
.is_some_and(|v| v.as_bool().unwrap_or(true))
|
||||
{
|
||||
store
|
||||
.restart(&client_id, restart_args, cx)
|
||||
.detach_and_log_err(cx);
|
||||
let Some(session) = store.session_by_client_id(client_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(client_state) = session.read(cx).client_state(client_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
client_state.update(cx, |state, cx| {
|
||||
state.restart(restart_args, cx);
|
||||
});
|
||||
} else {
|
||||
store
|
||||
.shutdown_session(&session_id, cx)
|
||||
@@ -927,21 +930,21 @@ impl DebugPanel {
|
||||
}
|
||||
});
|
||||
|
||||
cx.emit(DebugPanelEvent::Terminated(*client_id));
|
||||
cx.emit(DebugPanelEvent::Terminated(client_id));
|
||||
}
|
||||
|
||||
fn handle_output_event(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &OutputEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.message_queue
|
||||
.entry(*client_id)
|
||||
.entry(client_id)
|
||||
.or_default()
|
||||
.push_back(event.clone());
|
||||
|
||||
cx.emit(DebugPanelEvent::Output((*client_id, event.clone())));
|
||||
cx.emit(DebugPanelEvent::Output((client_id, event.clone())));
|
||||
}
|
||||
|
||||
fn on_dap_store_event(
|
||||
@@ -973,7 +976,7 @@ impl DebugPanel {
|
||||
) {
|
||||
if let Some(thread_state) = self.thread_states.get_mut(&(
|
||||
DebugAdapterClientId::from_proto(update.client_id),
|
||||
update.thread_id,
|
||||
ThreadId(update.thread_id),
|
||||
)) {
|
||||
thread_state.update(cx, |thread_state, _| {
|
||||
thread_state.status = ThreadStatus::from_proto(update.status());
|
||||
@@ -986,11 +989,11 @@ impl DebugPanel {
|
||||
pub(crate) fn handle_debug_adapter_update(
|
||||
&mut self,
|
||||
update: &UpdateDebugAdapter,
|
||||
window: &mut Window,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let client_id = DebugAdapterClientId::from_proto(update.client_id);
|
||||
let thread_id = update.thread_id;
|
||||
let thread_id = update.thread_id.map(|thread_id| ThreadId(thread_id));
|
||||
|
||||
let active_item = self
|
||||
.pane
|
||||
@@ -998,7 +1001,7 @@ impl DebugPanel {
|
||||
.active_item()
|
||||
.and_then(|item| item.downcast::<DebugPanelItem>());
|
||||
|
||||
let search = self
|
||||
let _search = self
|
||||
.pane
|
||||
.read(cx)
|
||||
.items()
|
||||
@@ -1020,15 +1023,16 @@ impl DebugPanel {
|
||||
}
|
||||
});
|
||||
|
||||
if let Some((debug_panel_item, is_active_item)) = search {
|
||||
debug_panel_item.update(cx, |this, cx| {
|
||||
this.update_adapter(update, window, cx);
|
||||
// if let Some((debug_panel_item, is_active_item)) = search {
|
||||
// TODO(debugger): make this work again
|
||||
// debug_panel_item.update(cx, |this, cx| {
|
||||
// this.update_adapter(update, window, cx);
|
||||
|
||||
if is_active_item {
|
||||
this.go_to_current_stack_frame(window, cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
// if is_active_item {
|
||||
// this.go_to_current_stack_frame(window, cx);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
fn handle_remote_has_initialized(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
@@ -1055,7 +1059,7 @@ impl DebugPanel {
|
||||
};
|
||||
|
||||
let client_id = DebugAdapterClientId::from_proto(payload.client_id);
|
||||
let thread_id = payload.thread_id;
|
||||
let thread_id = ThreadId(payload.thread_id);
|
||||
let thread_state = payload.thread_state.clone().unwrap();
|
||||
let thread_state = cx.new(|_| ThreadState::from_proto(thread_state));
|
||||
|
||||
@@ -1079,10 +1083,9 @@ impl DebugPanel {
|
||||
let debug_panel_item = cx.new(|cx| {
|
||||
DebugPanelItem::new(
|
||||
session,
|
||||
&client_id,
|
||||
client_id,
|
||||
thread_id,
|
||||
thread_state,
|
||||
self.dap_store.clone(),
|
||||
&debug_panel,
|
||||
self.workspace.clone(),
|
||||
window,
|
||||
@@ -1118,26 +1121,26 @@ impl DebugPanel {
|
||||
|
||||
fn handle_module_event(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &ModuleEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
cx.emit(DebugPanelEvent::Module((*client_id, event.clone())));
|
||||
cx.emit(DebugPanelEvent::Module((client_id, event.clone())));
|
||||
}
|
||||
|
||||
fn handle_loaded_source_event(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &LoadedSourceEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
cx.emit(DebugPanelEvent::LoadedSource((*client_id, event.clone())));
|
||||
cx.emit(DebugPanelEvent::LoadedSource((client_id, event.clone())));
|
||||
}
|
||||
|
||||
fn handle_capabilities_changed_event(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
event: &CapabilitiesEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -1145,7 +1148,7 @@ impl DebugPanel {
|
||||
store.update_capabilities_for_client(session_id, client_id, &event.capabilities, cx);
|
||||
});
|
||||
|
||||
cx.emit(DebugPanelEvent::CapabilitiesChanged(*client_id));
|
||||
cx.emit(DebugPanelEvent::CapabilitiesChanged(client_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,24 +5,21 @@ use crate::module_list::ModuleList;
|
||||
use crate::stack_frame_list::{StackFrameList, StackFrameListEvent};
|
||||
use crate::variable_list::VariableList;
|
||||
|
||||
use dap::proto_conversions::{self, ProtoConversion};
|
||||
use dap::{
|
||||
client::DebugAdapterClientId, debugger_settings::DebuggerSettings, Capabilities,
|
||||
ContinuedEvent, LoadedSourceEvent, ModuleEvent, OutputEvent, OutputEventCategory, StoppedEvent,
|
||||
ThreadEvent,
|
||||
};
|
||||
use editor::Editor;
|
||||
use gpui::{
|
||||
AnyElement, App, Entity, EventEmitter, FocusHandle, Focusable, Subscription, Task, WeakEntity,
|
||||
};
|
||||
use project::debugger::{dap_session::DebugSession, dap_store::DapStore};
|
||||
use rpc::proto::{self, DebuggerThreadStatus, PeerId, SetDebuggerPanelItem, UpdateDebugAdapter};
|
||||
use project::debugger::dap_session::{DebugSession, ThreadId};
|
||||
use rpc::proto::{self, DebuggerThreadStatus, PeerId, SetDebuggerPanelItem};
|
||||
use settings::Settings;
|
||||
use ui::{prelude::*, Indicator, Tooltip};
|
||||
use util::ResultExt as _;
|
||||
use workspace::{
|
||||
item::{self, Item, ItemEvent},
|
||||
FollowableItem, ItemHandle, ViewId, Workspace,
|
||||
FollowableItem, ViewId, Workspace,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -60,11 +57,10 @@ impl ThreadItem {
|
||||
}
|
||||
|
||||
pub struct DebugPanelItem {
|
||||
thread_id: u64,
|
||||
thread_id: ThreadId,
|
||||
console: Entity<Console>,
|
||||
focus_handle: FocusHandle,
|
||||
remote_id: Option<ViewId>,
|
||||
dap_store: Entity<DapStore>,
|
||||
session: Entity<DebugSession>,
|
||||
show_console_indicator: bool,
|
||||
module_list: Entity<ModuleList>,
|
||||
@@ -82,10 +78,9 @@ impl DebugPanelItem {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
client_id: DebugAdapterClientId,
|
||||
thread_id: ThreadId,
|
||||
thread_state: Entity<ThreadState>,
|
||||
dap_store: Entity<DapStore>,
|
||||
debug_panel: &Entity<DebugPanel>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
window: &mut Window,
|
||||
@@ -93,13 +88,9 @@ impl DebugPanelItem {
|
||||
) -> Self {
|
||||
let focus_handle = cx.focus_handle();
|
||||
|
||||
let this = cx.entity();
|
||||
|
||||
let stack_frame_list = cx.new(|cx| {
|
||||
StackFrameList::new(
|
||||
workspace.clone(),
|
||||
&this,
|
||||
dap_store.clone(),
|
||||
session.clone(),
|
||||
client_id,
|
||||
thread_id,
|
||||
@@ -112,23 +103,20 @@ impl DebugPanelItem {
|
||||
VariableList::new(
|
||||
session.clone(),
|
||||
client_id,
|
||||
dap_store.clone(),
|
||||
stack_frame_list.clone(),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let module_list = cx.new(|cx| ModuleList::new(session.clone(), &client_id, cx));
|
||||
let module_list = cx.new(|cx| ModuleList::new(session.clone(), client_id, cx));
|
||||
|
||||
let loaded_source_list =
|
||||
cx.new(|cx| LoadedSourceList::new(session.clone(), &client_id, cx));
|
||||
let loaded_source_list = cx.new(|cx| LoadedSourceList::new(session.clone(), client_id, cx));
|
||||
|
||||
let console = cx.new(|cx| {
|
||||
Console::new(
|
||||
session.clone(),
|
||||
client_id,
|
||||
dap_store.clone(),
|
||||
stack_frame_list.clone(),
|
||||
variable_list.clone(),
|
||||
window,
|
||||
@@ -188,7 +176,6 @@ impl DebugPanelItem {
|
||||
session,
|
||||
console,
|
||||
thread_id,
|
||||
dap_store,
|
||||
workspace,
|
||||
module_list,
|
||||
thread_state,
|
||||
@@ -198,33 +185,12 @@ impl DebugPanelItem {
|
||||
remote_id: None,
|
||||
stack_frame_list,
|
||||
loaded_source_list,
|
||||
client_id: *client_id,
|
||||
client_id,
|
||||
show_console_indicator: false,
|
||||
active_thread_item: ThreadItem::Variables,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_proto(&self, project_id: u64, cx: &App) -> SetDebuggerPanelItem {
|
||||
let thread_state = Some(self.thread_state.read(cx).to_proto());
|
||||
let variable_list = Some(self.variable_list.read(cx).to_proto());
|
||||
let stack_frame_list = Some(self.stack_frame_list.read(cx).to_proto());
|
||||
|
||||
SetDebuggerPanelItem {
|
||||
project_id,
|
||||
session_id: self.session.read(cx).id().to_proto(),
|
||||
client_id: self.client_id.to_proto(),
|
||||
thread_id: self.thread_id,
|
||||
console: None,
|
||||
module_list: None,
|
||||
active_thread_item: self.active_thread_item.to_proto().into(),
|
||||
thread_state,
|
||||
variable_list,
|
||||
stack_frame_list,
|
||||
loaded_source_list: None,
|
||||
session_name: self.session.read(cx).name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_proto(&mut self, state: &SetDebuggerPanelItem, cx: &mut Context<Self>) {
|
||||
self.thread_state.update(cx, |thread_state, _| {
|
||||
let (status, stopped) = state
|
||||
@@ -240,12 +206,6 @@ impl DebugPanelItem {
|
||||
|
||||
self.active_thread_item = ThreadItem::from_proto(state.active_thread_item());
|
||||
|
||||
if let Some(stack_frame_list) = state.stack_frame_list.as_ref() {
|
||||
self.stack_frame_list.update(cx, |this, cx| {
|
||||
this.set_from_proto(stack_frame_list.clone(), cx);
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(variable_list_state) = state.variable_list.as_ref() {
|
||||
self.variable_list
|
||||
.update(cx, |this, cx| this.set_from_proto(variable_list_state, cx));
|
||||
@@ -269,7 +229,7 @@ impl DebugPanelItem {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_skip_event(&self, client_id: &DebugAdapterClientId, thread_id: u64) -> bool {
|
||||
fn should_skip_event(&self, client_id: &DebugAdapterClientId, thread_id: ThreadId) -> bool {
|
||||
thread_id != self.thread_id || *client_id != self.client_id
|
||||
}
|
||||
|
||||
@@ -279,7 +239,7 @@ impl DebugPanelItem {
|
||||
event: &ContinuedEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.should_skip_event(client_id, event.thread_id) {
|
||||
if self.should_skip_event(client_id, ThreadId(event.thread_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -293,21 +253,20 @@ impl DebugPanelItem {
|
||||
go_to_stack_frame: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.should_skip_event(client_id, event.thread_id.unwrap_or(self.thread_id)) {
|
||||
if self.should_skip_event(
|
||||
client_id,
|
||||
event.thread_id.map(ThreadId).unwrap_or(self.thread_id),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(client_state) = self.session.read(cx).client_state(*client_id) {
|
||||
client_state.update(cx, |state, cx| state.invalidate(cx));
|
||||
client_state.update(cx, |state, cx| {
|
||||
state.invalidate(cx);
|
||||
});
|
||||
}
|
||||
|
||||
cx.emit(DebugPanelItemEvent::Stopped { go_to_stack_frame });
|
||||
|
||||
if let Some((downstream_client, project_id)) = self.dap_store.read(cx).downstream_client() {
|
||||
downstream_client
|
||||
.send(self.to_proto(*project_id, cx))
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_thread_event(
|
||||
@@ -316,7 +275,7 @@ impl DebugPanelItem {
|
||||
event: &ThreadEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.should_skip_event(client_id, event.thread_id) {
|
||||
if self.should_skip_event(client_id, ThreadId(event.thread_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -393,9 +352,10 @@ impl DebugPanelItem {
|
||||
|
||||
self.update_thread_state_status(ThreadStatus::Stopped, cx);
|
||||
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store.remove_active_debug_line_for_client(client_id, cx);
|
||||
});
|
||||
// TODO(debugger): make this work again
|
||||
// self.dap_store.update(cx, |store, cx| {
|
||||
// store.remove_active_debug_line_for_client(client_id, cx);
|
||||
// });
|
||||
|
||||
cx.emit(DebugPanelItemEvent::Close);
|
||||
}
|
||||
@@ -411,10 +371,6 @@ impl DebugPanelItem {
|
||||
|
||||
self.update_thread_state_status(ThreadStatus::Exited, cx);
|
||||
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store.remove_active_debug_line_for_client(client_id, cx);
|
||||
});
|
||||
|
||||
cx.emit(DebugPanelItemEvent::Close);
|
||||
}
|
||||
|
||||
@@ -427,56 +383,42 @@ impl DebugPanelItem {
|
||||
return;
|
||||
}
|
||||
|
||||
// notify the view that the capabilities have changed
|
||||
cx.notify();
|
||||
|
||||
if let Some((downstream_client, project_id)) = self.dap_store.read(cx).downstream_client() {
|
||||
if let Some(caps) = self.dap_store.read(cx).capabilities_by_id(client_id, cx) {
|
||||
let message = proto_conversions::capabilities_to_proto(
|
||||
&caps,
|
||||
*project_id,
|
||||
self.session.read(cx).id().to_proto(),
|
||||
self.client_id.to_proto(),
|
||||
);
|
||||
|
||||
downstream_client.send(message).log_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_adapter(
|
||||
&mut self,
|
||||
update: &UpdateDebugAdapter,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(update_variant) = update.variant.as_ref() {
|
||||
match update_variant {
|
||||
proto::update_debug_adapter::Variant::StackFrameList(stack_frame_list) => {
|
||||
self.stack_frame_list.update(cx, |this, cx| {
|
||||
this.set_from_proto(stack_frame_list.clone(), cx);
|
||||
})
|
||||
}
|
||||
proto::update_debug_adapter::Variant::ThreadState(thread_state) => {
|
||||
self.thread_state.update(cx, |this, _| {
|
||||
*this = ThreadState::from_proto(thread_state.clone());
|
||||
})
|
||||
}
|
||||
proto::update_debug_adapter::Variant::VariableList(variable_list) => self
|
||||
.variable_list
|
||||
.update(cx, |this, cx| this.set_from_proto(variable_list, cx)),
|
||||
proto::update_debug_adapter::Variant::AddToVariableList(variables_to_add) => self
|
||||
.variable_list
|
||||
.update(cx, |this, _| this.add_variables(variables_to_add.clone())),
|
||||
proto::update_debug_adapter::Variant::Modules(_) => {}
|
||||
proto::update_debug_adapter::Variant::OutputEvent(output_event) => {
|
||||
self.console.update(cx, |this, cx| {
|
||||
this.add_message(OutputEvent::from_proto(output_event.clone()), window, cx);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// pub(crate) fn update_adapter(
|
||||
// &mut self,
|
||||
// update: &UpdateDebugAdapter,
|
||||
// window: &mut Window,
|
||||
// cx: &mut Context<Self>,
|
||||
// ) {
|
||||
// if let Some(update_variant) = update.variant.as_ref() {
|
||||
// match update_variant {
|
||||
// proto::update_debug_adapter::Variant::StackFrameList(stack_frame_list) => {
|
||||
// self.stack_frame_list.update(cx, |this, cx| {
|
||||
// this.set_from_proto(stack_frame_list.clone(), cx);
|
||||
// })
|
||||
// }
|
||||
// proto::update_debug_adapter::Variant::ThreadState(thread_state) => {
|
||||
// self.thread_state.update(cx, |this, _| {
|
||||
// *this = ThreadState::from_proto(thread_state.clone());
|
||||
// })
|
||||
// }
|
||||
// proto::update_debug_adapter::Variant::VariableList(variable_list) => self
|
||||
// .variable_list
|
||||
// .update(cx, |this, cx| this.set_from_proto(variable_list, cx)),
|
||||
// proto::update_debug_adapter::Variant::AddToVariableList(variables_to_add) => self
|
||||
// .variable_list
|
||||
// .update(cx, |this, _| this.add_variables(variables_to_add.clone())),
|
||||
// proto::update_debug_adapter::Variant::Modules(_) => {}
|
||||
// proto::update_debug_adapter::Variant::OutputEvent(output_event) => {
|
||||
// self.console.update(cx, |this, cx| {
|
||||
// this.add_message(OutputEvent::from_proto(output_event.clone()), window, cx);
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn session(&self) -> &Entity<DebugSession> {
|
||||
&self.session
|
||||
@@ -486,7 +428,7 @@ impl DebugPanelItem {
|
||||
self.client_id
|
||||
}
|
||||
|
||||
pub fn thread_id(&self) -> u64 {
|
||||
pub fn thread_id(&self) -> ThreadId {
|
||||
self.thread_id
|
||||
}
|
||||
|
||||
@@ -527,41 +469,43 @@ impl DebugPanelItem {
|
||||
}
|
||||
|
||||
pub fn capabilities(&self, cx: &mut Context<Self>) -> Option<Capabilities> {
|
||||
self.dap_store
|
||||
self.session()
|
||||
.read(cx)
|
||||
.capabilities_by_id(&self.client_id, cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|state| state.read(cx).capabilities().clone())
|
||||
}
|
||||
|
||||
fn clear_highlights(&self, cx: &mut Context<Self>) {
|
||||
if let Some((_, project_path, _)) = self.dap_store.read(cx).active_debug_line() {
|
||||
self.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
let editor = workspace
|
||||
.items_of_type::<Editor>(cx)
|
||||
.find(|editor| Some(project_path.clone()) == editor.project_path(cx));
|
||||
// TODO(debugger): make this work again
|
||||
// if let Some((_, project_path, _)) = self.dap_store.read(cx).active_debug_line() {
|
||||
// self.workspace
|
||||
// .update(cx, |workspace, cx| {
|
||||
// let editor = workspace
|
||||
// .items_of_type::<Editor>(cx)
|
||||
// .find(|editor| Some(project_path.clone()) == editor.project_path(cx));
|
||||
|
||||
if let Some(editor) = editor {
|
||||
editor.update(cx, |editor, cx| {
|
||||
editor.clear_row_highlights::<editor::DebugCurrentRowHighlight>();
|
||||
// if let Some(editor) = editor {
|
||||
// editor.update(cx, |editor, cx| {
|
||||
// editor.clear_row_highlights::<editor::DebugCurrentRowHighlight>();
|
||||
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
// cx.notify();
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .ok();
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn go_to_current_stack_frame(&self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.stack_frame_list.update(cx, |stack_frame_list, cx| {
|
||||
if let Some(stack_frame) = stack_frame_list
|
||||
.stack_frames()
|
||||
.stack_frames(cx)
|
||||
.iter()
|
||||
.find(|frame| frame.id == stack_frame_list.current_stack_frame_id())
|
||||
.find(|frame| frame.dap.id == stack_frame_list.current_stack_frame_id())
|
||||
.cloned()
|
||||
{
|
||||
stack_frame_list
|
||||
.select_stack_frame(&stack_frame, true, window, cx)
|
||||
.select_stack_frame(&stack_frame.dap, true, window, cx)
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
});
|
||||
@@ -603,134 +547,110 @@ impl DebugPanelItem {
|
||||
}
|
||||
|
||||
pub fn continue_thread(&mut self, cx: &mut Context<Self>) {
|
||||
self.update_thread_state_status(ThreadStatus::Running, cx);
|
||||
|
||||
let task = self.dap_store.update(cx, |store, cx| {
|
||||
store.continue_thread(&self.client_id, self.thread_id, cx)
|
||||
});
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if task.await.log_err().is_none() {
|
||||
this.update(&mut cx, |debug_panel_item, cx| {
|
||||
debug_panel_item.update_thread_state_status(ThreadStatus::Stopped, cx);
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.continue_thread(self.thread_id, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn step_over(&mut self, cx: &mut Context<Self>) {
|
||||
self.update_thread_state_status(ThreadStatus::Running, cx);
|
||||
let granularity = DebuggerSettings::get_global(cx).stepping_granularity;
|
||||
|
||||
let task = self.dap_store.update(cx, |store, cx| {
|
||||
store.step_over(&self.client_id, self.thread_id, granularity, cx)
|
||||
});
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if task.await.log_err().is_none() {
|
||||
this.update(&mut cx, |debug_panel_item, cx| {
|
||||
debug_panel_item.update_thread_state_status(ThreadStatus::Stopped, cx);
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.step_over(self.thread_id, granularity, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn step_in(&mut self, cx: &mut Context<Self>) {
|
||||
self.update_thread_state_status(ThreadStatus::Running, cx);
|
||||
let granularity = DebuggerSettings::get_global(cx).stepping_granularity;
|
||||
|
||||
let task = self.dap_store.update(cx, |store, cx| {
|
||||
store.step_in(&self.client_id, self.thread_id, granularity, cx)
|
||||
});
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if task.await.log_err().is_none() {
|
||||
this.update(&mut cx, |debug_panel_item, cx| {
|
||||
debug_panel_item.update_thread_state_status(ThreadStatus::Stopped, cx);
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.step_in(self.thread_id, granularity, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn step_out(&mut self, cx: &mut Context<Self>) {
|
||||
self.update_thread_state_status(ThreadStatus::Running, cx);
|
||||
let granularity = DebuggerSettings::get_global(cx).stepping_granularity;
|
||||
|
||||
let task = self.dap_store.update(cx, |store, cx| {
|
||||
store.step_out(&self.client_id, self.thread_id, granularity, cx)
|
||||
});
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if task.await.log_err().is_none() {
|
||||
this.update(&mut cx, |debug_panel_item, cx| {
|
||||
debug_panel_item.update_thread_state_status(ThreadStatus::Stopped, cx);
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.step_out(self.thread_id, granularity, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn step_back(&mut self, cx: &mut Context<Self>) {
|
||||
self.update_thread_state_status(ThreadStatus::Running, cx);
|
||||
let granularity = DebuggerSettings::get_global(cx).stepping_granularity;
|
||||
|
||||
let task = self.dap_store.update(cx, |store, cx| {
|
||||
store.step_back(&self.client_id, self.thread_id, granularity, cx)
|
||||
});
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if task.await.log_err().is_none() {
|
||||
this.update(&mut cx, |debug_panel_item, cx| {
|
||||
debug_panel_item.update_thread_state_status(ThreadStatus::Stopped, cx);
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.step_back(self.thread_id, granularity, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn restart_client(&self, cx: &mut Context<Self>) {
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.restart(&self.client_id, None, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.restart(None, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn pause_thread(&self, cx: &mut Context<Self>) {
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.pause_thread(&self.client_id, self.thread_id, cx)
|
||||
.detach_and_log_err(cx)
|
||||
});
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.pause_thread(self.thread_id, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn stop_thread(&self, cx: &mut Context<Self>) {
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.terminate_threads(
|
||||
&self.session.read(cx).id(),
|
||||
&self.client_id,
|
||||
Some(vec![self.thread_id; 1]),
|
||||
cx,
|
||||
)
|
||||
.detach_and_log_err(cx)
|
||||
});
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.terminate_threads(Some(vec![self.thread_id; 1]), cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn disconnect_client(&self, cx: &mut Context<Self>) {
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.disconnect_client(&self.client_id, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
self.session()
|
||||
.read(cx)
|
||||
.client_state(self.client_id)
|
||||
.map(|entity| {
|
||||
entity.update(cx, |state, cx| {
|
||||
state.disconnect_client(cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn toggle_ignore_breakpoints(&mut self, cx: &mut Context<Self>) {
|
||||
@@ -760,7 +680,7 @@ impl Item for DebugPanelItem {
|
||||
Label::new(format!(
|
||||
"{} - Thread {}",
|
||||
self.session.read(cx).name(),
|
||||
self.thread_id
|
||||
self.thread_id.0
|
||||
))
|
||||
.color(if params.selected {
|
||||
Color::Default
|
||||
@@ -774,7 +694,7 @@ impl Item for DebugPanelItem {
|
||||
Some(SharedString::from(format!(
|
||||
"{} Thread {} - {:?}",
|
||||
self.session.read(cx).name(),
|
||||
self.thread_id,
|
||||
self.thread_id.0,
|
||||
self.thread_state.read(cx).status,
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct LoadedSourceList {
|
||||
impl LoadedSourceList {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let weak_entity = cx.weak_entity();
|
||||
@@ -35,7 +35,7 @@ impl LoadedSourceList {
|
||||
},
|
||||
);
|
||||
|
||||
let client_state = session.read(cx).client_state(*client_id).unwrap();
|
||||
let client_state = session.read(cx).client_state(client_id).unwrap();
|
||||
let _subscription = cx.observe(&client_state, |loaded_source_list, state, cx| {
|
||||
let len = state.update(cx, |state, cx| state.loaded_sources(cx).len());
|
||||
|
||||
@@ -48,7 +48,7 @@ impl LoadedSourceList {
|
||||
session,
|
||||
focus_handle,
|
||||
_subscription,
|
||||
client_id: *client_id,
|
||||
client_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct ModuleList {
|
||||
impl ModuleList {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let weak_entity = cx.weak_entity();
|
||||
@@ -32,7 +32,7 @@ impl ModuleList {
|
||||
},
|
||||
);
|
||||
|
||||
let client_state = session.read(cx).client_state(*client_id).unwrap();
|
||||
let client_state = session.read(cx).client_state(client_id).unwrap();
|
||||
|
||||
let _subscription = cx.observe(&client_state, |module_list, state, cx| {
|
||||
let modules_len = state.update(cx, |state, cx| state.modules(cx).len());
|
||||
@@ -46,7 +46,7 @@ impl ModuleList {
|
||||
session,
|
||||
focus_handle,
|
||||
_subscription,
|
||||
client_id: *client_id,
|
||||
client_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,22 +2,15 @@ use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use dap::client::DebugAdapterClientId;
|
||||
use dap::proto_conversions::ProtoConversion;
|
||||
use dap::StackFrame;
|
||||
use gpui::{
|
||||
list, AnyElement, Entity, EventEmitter, FocusHandle, Focusable, ListState, Subscription, Task,
|
||||
WeakEntity,
|
||||
};
|
||||
use project::debugger::{dap_session::DebugSession, dap_store::DapStore};
|
||||
use project::debugger::dap_session::{DebugSession, StackFrame, ThreadId};
|
||||
use project::ProjectPath;
|
||||
use rpc::proto::{DebuggerStackFrameList, UpdateDebugAdapter};
|
||||
use ui::{prelude::*, Tooltip};
|
||||
use util::ResultExt;
|
||||
use workspace::Workspace;
|
||||
|
||||
use crate::debugger_panel_item::DebugPanelItemEvent::Stopped;
|
||||
use crate::debugger_panel_item::{self, DebugPanelItem};
|
||||
|
||||
pub type StackFrameId = u64;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -27,36 +20,31 @@ pub enum StackFrameListEvent {
|
||||
}
|
||||
|
||||
pub struct StackFrameList {
|
||||
thread_id: u64,
|
||||
list: ListState,
|
||||
thread_id: ThreadId,
|
||||
focus_handle: FocusHandle,
|
||||
dap_store: Entity<DapStore>,
|
||||
_subscription: Subscription,
|
||||
session: Entity<DebugSession>,
|
||||
stack_frames: Vec<StackFrame>,
|
||||
entries: Vec<StackFrameEntry>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
client_id: DebugAdapterClientId,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
current_stack_frame_id: StackFrameId,
|
||||
fetch_stack_frames_task: Option<Task<Result<()>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum StackFrameEntry {
|
||||
Normal(StackFrame),
|
||||
Collapsed(Vec<StackFrame>),
|
||||
Normal(dap::StackFrame),
|
||||
Collapsed(Vec<dap::StackFrame>),
|
||||
}
|
||||
|
||||
impl StackFrameList {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
workspace: WeakEntity<Workspace>,
|
||||
debug_panel_item: &Entity<DebugPanelItem>,
|
||||
dap_store: Entity<DapStore>,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
window: &Window,
|
||||
client_id: DebugAdapterClientId,
|
||||
thread_id: ThreadId,
|
||||
_window: &Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let weak_entity = cx.weak_entity();
|
||||
@@ -76,68 +64,59 @@ impl StackFrameList {
|
||||
},
|
||||
);
|
||||
|
||||
let _subscriptions = vec![cx.subscribe_in(
|
||||
debug_panel_item,
|
||||
window,
|
||||
Self::handle_debug_panel_item_event,
|
||||
)];
|
||||
let client_state = session.read(cx).client_state(client_id).unwrap();
|
||||
|
||||
let _subscription = cx.observe(&client_state, |stack_frame_list, state, cx| {
|
||||
let _frame_len = state.update(cx, |state, cx| {
|
||||
state.stack_frames(stack_frame_list.thread_id, cx).len()
|
||||
});
|
||||
|
||||
stack_frame_list.build_entries(cx);
|
||||
});
|
||||
|
||||
Self {
|
||||
list,
|
||||
session,
|
||||
workspace,
|
||||
dap_store,
|
||||
thread_id,
|
||||
client_id,
|
||||
focus_handle,
|
||||
_subscriptions,
|
||||
client_id: *client_id,
|
||||
_subscription,
|
||||
entries: Default::default(),
|
||||
fetch_stack_frames_task: None,
|
||||
stack_frames: Default::default(),
|
||||
current_stack_frame_id: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn thread_id(&self) -> u64 {
|
||||
pub(crate) fn thread_id(&self) -> ThreadId {
|
||||
self.thread_id
|
||||
}
|
||||
|
||||
pub(crate) fn to_proto(&self) -> DebuggerStackFrameList {
|
||||
DebuggerStackFrameList {
|
||||
thread_id: self.thread_id,
|
||||
client_id: self.client_id.to_proto(),
|
||||
current_stack_frame: self.current_stack_frame_id,
|
||||
stack_frames: self.stack_frames.to_proto(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_from_proto(
|
||||
&mut self,
|
||||
stack_frame_list: DebuggerStackFrameList,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.thread_id = stack_frame_list.thread_id;
|
||||
self.client_id = DebugAdapterClientId::from_proto(stack_frame_list.client_id);
|
||||
self.current_stack_frame_id = stack_frame_list.current_stack_frame;
|
||||
self.stack_frames = Vec::from_proto(stack_frame_list.stack_frames);
|
||||
|
||||
self.build_entries();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn entries(&self) -> &Vec<StackFrameEntry> {
|
||||
&self.entries
|
||||
}
|
||||
|
||||
pub fn stack_frames(&self) -> &Vec<StackFrame> {
|
||||
&self.stack_frames
|
||||
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()
|
||||
}
|
||||
|
||||
pub fn first_stack_frame_id(&self) -> u64 {
|
||||
self.stack_frames
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn dap_stack_frames(&self, cx: &mut App) -> Vec<dap::StackFrame> {
|
||||
self.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|stack_frame| stack_frame.dap.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_main_stack_frame_id(&self, cx: &mut Context<Self>) -> u64 {
|
||||
self.stack_frames(cx)
|
||||
.first()
|
||||
.map(|stack_frame| stack_frame.id)
|
||||
.map(|stack_frame| stack_frame.dap.id)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
@@ -145,33 +124,14 @@ impl StackFrameList {
|
||||
self.current_stack_frame_id
|
||||
}
|
||||
|
||||
fn handle_debug_panel_item_event(
|
||||
&mut self,
|
||||
_: &Entity<DebugPanelItem>,
|
||||
event: &debugger_panel_item::DebugPanelItemEvent,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
match event {
|
||||
Stopped { go_to_stack_frame } => {
|
||||
self.fetch_stack_frames(*go_to_stack_frame, window, cx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invalidate(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.fetch_stack_frames(true, window, cx);
|
||||
}
|
||||
|
||||
fn build_entries(&mut self) {
|
||||
fn build_entries(&mut self, cx: &mut Context<Self>) {
|
||||
let mut entries = Vec::new();
|
||||
let mut collapsed_entries = Vec::new();
|
||||
|
||||
for stack_frame in &self.stack_frames {
|
||||
match stack_frame.presentation_hint {
|
||||
for stack_frame in &self.stack_frames(cx) {
|
||||
match stack_frame.dap.presentation_hint {
|
||||
Some(dap::StackFramePresentationHint::Deemphasize) => {
|
||||
collapsed_entries.push(stack_frame.clone());
|
||||
collapsed_entries.push(stack_frame.dap.clone());
|
||||
}
|
||||
_ => {
|
||||
let collapsed_entries = std::mem::take(&mut collapsed_entries);
|
||||
@@ -179,7 +139,7 @@ impl StackFrameList {
|
||||
entries.push(StackFrameEntry::Collapsed(collapsed_entries.clone()));
|
||||
}
|
||||
|
||||
entries.push(StackFrameEntry::Normal(stack_frame.clone()));
|
||||
entries.push(StackFrameEntry::Normal(stack_frame.dap.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,54 +151,55 @@ impl StackFrameList {
|
||||
|
||||
std::mem::swap(&mut self.entries, &mut entries);
|
||||
self.list.reset(self.entries.len());
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn fetch_stack_frames(
|
||||
&mut self,
|
||||
go_to_stack_frame: bool,
|
||||
window: &Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
// If this is a remote debug session we never need to fetch stack frames ourselves
|
||||
// because the host will fetch and send us stack frames whenever there's a stop event
|
||||
if self.dap_store.read(cx).as_remote().is_some() {
|
||||
return;
|
||||
}
|
||||
// fn fetch_stack_frames(
|
||||
// &mut self,
|
||||
// go_to_stack_frame: bool,
|
||||
// window: &Window,
|
||||
// cx: &mut Context<Self>,
|
||||
// ) {
|
||||
// // If this is a remote debug session we never need to fetch stack frames ourselves
|
||||
// // because the host will fetch and send us stack frames whenever there's a stop event
|
||||
// if self.dap_store.read(cx).as_remote().is_some() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
let task = self.dap_store.update(cx, |store, cx| {
|
||||
store.stack_frames(&self.client_id, self.thread_id, cx)
|
||||
});
|
||||
// let task = self.dap_store.update(cx, |store, cx| {
|
||||
// store.stack_frames(&self.client_id, self.thread_id, cx)
|
||||
// });
|
||||
|
||||
self.fetch_stack_frames_task = Some(cx.spawn_in(window, |this, mut cx| async move {
|
||||
let mut stack_frames = task.await?;
|
||||
// self.fetch_stack_frames_task = Some(cx.spawn_in(window, |this, mut cx| async move {
|
||||
// let mut stack_frames = task.await?;
|
||||
|
||||
let task = this.update_in(&mut cx, |this, window, cx| {
|
||||
std::mem::swap(&mut this.stack_frames, &mut stack_frames);
|
||||
// let task = this.update_in(&mut cx, |this, window, cx| {
|
||||
// std::mem::swap(&mut this.stack_frames, &mut stack_frames);
|
||||
|
||||
this.build_entries();
|
||||
// this.build_entries();
|
||||
|
||||
cx.emit(StackFrameListEvent::StackFramesUpdated);
|
||||
// cx.emit(StackFrameListEvent::StackFramesUpdated);
|
||||
|
||||
let stack_frame = this
|
||||
.stack_frames
|
||||
.first()
|
||||
.cloned()
|
||||
.ok_or_else(|| anyhow!("No stack frame found to select"))?;
|
||||
// let stack_frame = this
|
||||
// .stack_frames
|
||||
// .first()
|
||||
// .cloned()
|
||||
// .ok_or_else(|| anyhow!("No stack frame found to select"))?;
|
||||
|
||||
anyhow::Ok(this.select_stack_frame(&stack_frame, go_to_stack_frame, window, cx))
|
||||
})?;
|
||||
// anyhow::Ok(this.select_stack_frame(&stack_frame, go_to_stack_frame, window, cx))
|
||||
// })?;
|
||||
|
||||
task?.await?;
|
||||
// task?.await?;
|
||||
|
||||
this.update(&mut cx, |this, _| {
|
||||
this.fetch_stack_frames_task.take();
|
||||
})
|
||||
}));
|
||||
}
|
||||
// this.update(&mut cx, |this, _| {
|
||||
// this.fetch_stack_frames_task.take();
|
||||
// })
|
||||
// }));
|
||||
// }
|
||||
|
||||
pub fn select_stack_frame(
|
||||
&mut self,
|
||||
stack_frame: &StackFrame,
|
||||
stack_frame: &dap::StackFrame,
|
||||
go_to_stack_frame: bool,
|
||||
window: &Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -250,20 +211,6 @@ impl StackFrameList {
|
||||
));
|
||||
cx.notify();
|
||||
|
||||
if let Some((client, id)) = self.dap_store.read(cx).downstream_client() {
|
||||
let request = UpdateDebugAdapter {
|
||||
client_id: self.client_id.to_proto(),
|
||||
session_id: self.session.read(cx).id().to_proto(),
|
||||
project_id: *id,
|
||||
thread_id: Some(self.thread_id),
|
||||
variant: Some(rpc::proto::update_debug_adapter::Variant::StackFrameList(
|
||||
self.to_proto(),
|
||||
)),
|
||||
};
|
||||
|
||||
client.send(request).log_err();
|
||||
}
|
||||
|
||||
if !go_to_stack_frame {
|
||||
return Task::ready(Ok(()));
|
||||
};
|
||||
@@ -291,18 +238,21 @@ impl StackFrameList {
|
||||
})??
|
||||
.await?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.dap_store.update(cx, |store, cx| {
|
||||
store.set_active_debug_line(&client_id, &project_path, row, cx);
|
||||
})
|
||||
})
|
||||
Ok(())
|
||||
|
||||
// TODO(debugger): make this work again
|
||||
// this.update(&mut cx, |this, cx| {
|
||||
// this.dap_store.update(cx, |store, cx| {
|
||||
// store.set_active_debug_line(client_id, &project_path, row, cx);
|
||||
// })
|
||||
// })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn project_path_from_stack_frame(
|
||||
fn project_path_from_stack_frame(
|
||||
&self,
|
||||
stack_frame: &StackFrame,
|
||||
stack_frame: &dap::StackFrame,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<ProjectPath> {
|
||||
let path = stack_frame.source.as_ref().and_then(|s| s.path.as_ref())?;
|
||||
@@ -317,14 +267,18 @@ impl StackFrameList {
|
||||
}
|
||||
|
||||
pub fn restart_stack_frame(&mut self, stack_frame_id: u64, cx: &mut Context<Self>) {
|
||||
self.dap_store.update(cx, |store, cx| {
|
||||
store
|
||||
.restart_stack_frame(&self.client_id, stack_frame_id, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn render_normal_entry(&self, stack_frame: &StackFrame, cx: &mut Context<Self>) -> AnyElement {
|
||||
fn render_normal_entry(
|
||||
&self,
|
||||
stack_frame: &dap::StackFrame,
|
||||
cx: &mut Context<Self>,
|
||||
) -> AnyElement {
|
||||
let source = stack_frame.source.clone();
|
||||
let is_selected_frame = stack_frame.id == self.current_stack_frame_id;
|
||||
|
||||
@@ -335,11 +289,10 @@ impl StackFrameList {
|
||||
);
|
||||
|
||||
let supports_frame_restart = self
|
||||
.dap_store
|
||||
.session
|
||||
.read(cx)
|
||||
.capabilities_by_id(&self.client_id, cx)
|
||||
.map(|caps| caps.supports_restart_frame)
|
||||
.flatten()
|
||||
.client_state(self.client_id)
|
||||
.and_then(|client| client.read(cx).capabilities().supports_restart_frame)
|
||||
.unwrap_or_default();
|
||||
|
||||
let origin = stack_frame
|
||||
@@ -442,7 +395,7 @@ impl StackFrameList {
|
||||
pub fn expand_collapsed_entry(
|
||||
&mut self,
|
||||
ix: usize,
|
||||
stack_frames: &Vec<StackFrame>,
|
||||
stack_frames: &Vec<dap::StackFrame>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.entries.splice(
|
||||
@@ -458,7 +411,7 @@ impl StackFrameList {
|
||||
fn render_collapsed_entry(
|
||||
&self,
|
||||
ix: usize,
|
||||
stack_frames: &Vec<StackFrame>,
|
||||
stack_frames: &Vec<dap::StackFrame>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> AnyElement {
|
||||
let first_stack_frame = &stack_frames[0];
|
||||
|
||||
@@ -15,7 +15,7 @@ use editor::{
|
||||
};
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::{
|
||||
dap_store::{Breakpoint, BreakpointEditAction, BreakpointKind},
|
||||
debugger::dap_store::{Breakpoint, BreakpointEditAction, BreakpointKind},
|
||||
FakeFs, Project,
|
||||
};
|
||||
use serde_json::json;
|
||||
@@ -125,7 +125,7 @@ async fn test_basic_show_debug_panel(executor: BackgroundExecutor, cx: &mut Test
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -248,7 +248,7 @@ async fn test_we_can_only_have_one_panel_per_debug_thread(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -279,7 +279,7 @@ async fn test_we_can_only_have_one_panel_per_debug_thread(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -402,7 +402,7 @@ async fn test_client_can_open_multiple_thread_panels(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(1, active_debug_panel_item.read(cx).thread_id().0);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -433,7 +433,7 @@ async fn test_client_can_open_multiple_thread_panels(
|
||||
debug_panel.update(cx, |this, cx| this.pane().unwrap().read(cx).items_len())
|
||||
);
|
||||
assert_eq!(client.id(), active_debug_panel_item.read(cx).client_id());
|
||||
assert_eq!(2, active_debug_panel_item.read(cx).thread_id());
|
||||
assert_eq!(2, active_debug_panel_item.read(cx).thread_id().0);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -749,7 +749,7 @@ async fn test_handle_start_debugging_reverse_request(
|
||||
cx.run_until_parked();
|
||||
|
||||
project.update(cx, |_, cx| {
|
||||
assert_eq!(2, session.read(cx).as_local().unwrap().clients_len());
|
||||
assert_eq!(2, session.read(cx).clients_len());
|
||||
});
|
||||
assert!(
|
||||
send_response.load(std::sync::atomic::Ordering::SeqCst),
|
||||
@@ -759,9 +759,10 @@ async fn test_handle_start_debugging_reverse_request(
|
||||
let second_client = project.update(cx, |_, cx| {
|
||||
session
|
||||
.read(cx)
|
||||
.as_local()
|
||||
.client_state(DebugAdapterClientId(1))
|
||||
.unwrap()
|
||||
.client_by_id(&DebugAdapterClientId(1))
|
||||
.read(cx)
|
||||
.adapter_client()
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
|
||||
@@ -162,10 +162,19 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame(
|
||||
.unwrap();
|
||||
|
||||
active_debug_panel_item.update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(1, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(1, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
@@ -324,10 +333,19 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC
|
||||
.unwrap();
|
||||
|
||||
active_debug_panel_item.update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(1, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(1, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
});
|
||||
|
||||
let editors = workspace.items_of_type::<Editor>(cx).collect::<Vec<_>>();
|
||||
@@ -383,10 +401,19 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC
|
||||
.unwrap();
|
||||
|
||||
active_debug_panel_item.update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(2, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(2, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
});
|
||||
|
||||
let editors = workspace.items_of_type::<Editor>(cx).collect::<Vec<_>>();
|
||||
|
||||
@@ -191,10 +191,19 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_panel_item(workspace, cx).update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(1, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(1, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
|
||||
debug_panel_item
|
||||
.variable_list()
|
||||
@@ -444,10 +453,19 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_panel_item(workspace, cx).update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(1, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(1, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
|
||||
debug_panel_item
|
||||
.variable_list()
|
||||
@@ -1324,11 +1342,21 @@ async fn test_it_only_fetches_scopes_and_variables_for_the_first_stack_frame(
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_panel_item(workspace, cx).update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let variable_list = debug_panel_item.variable_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(1, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(1, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
|
||||
let variable_list = debug_panel_item.variable_list().read(cx);
|
||||
|
||||
assert_eq!(
|
||||
frame_1_variables
|
||||
@@ -1560,11 +1588,21 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_panel_item(workspace, cx).update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
let variable_list = debug_panel_item.variable_list().read(cx);
|
||||
|
||||
assert_eq!(1, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(1, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
|
||||
assert_eq!(
|
||||
frame_1_variables
|
||||
@@ -1663,11 +1701,21 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_panel_item(workspace, cx).update(cx, |debug_panel_item, cx| {
|
||||
let stack_frame_list = debug_panel_item.stack_frame_list().read(cx);
|
||||
let (stack_frame_list, stack_frame_id) =
|
||||
debug_panel_item.stack_frame_list().update(cx, |list, cx| {
|
||||
(
|
||||
list.stack_frames(cx)
|
||||
.into_iter()
|
||||
.map(|frame| frame.dap)
|
||||
.collect::<Vec<_>>(),
|
||||
list.current_stack_frame_id(),
|
||||
)
|
||||
});
|
||||
|
||||
let variable_list = debug_panel_item.variable_list().read(cx);
|
||||
|
||||
assert_eq!(2, stack_frame_list.current_stack_frame_id());
|
||||
assert_eq!(stack_frames, stack_frame_list.stack_frames().clone());
|
||||
assert_eq!(2, stack_frame_id);
|
||||
assert_eq!(stack_frames, stack_frame_list);
|
||||
|
||||
assert_eq!(
|
||||
frame_1_variables
|
||||
|
||||
@@ -10,10 +10,10 @@ use gpui::{
|
||||
FocusHandle, Focusable, Hsla, ListOffset, ListState, MouseDownEvent, Point, Subscription, Task,
|
||||
};
|
||||
use menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev};
|
||||
use project::debugger::{dap_session::DebugSession, dap_store::DapStore};
|
||||
use project::debugger::dap_session::DebugSession;
|
||||
use rpc::proto::{
|
||||
self, DebuggerScopeVariableIndex, DebuggerVariableContainer, UpdateDebugAdapter,
|
||||
VariableListScopes, VariableListVariables,
|
||||
self, DebuggerScopeVariableIndex, DebuggerVariableContainer, VariableListScopes,
|
||||
VariableListVariables,
|
||||
};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
@@ -329,7 +329,6 @@ type ScopeId = u64;
|
||||
pub struct VariableList {
|
||||
list: ListState,
|
||||
focus_handle: FocusHandle,
|
||||
dap_store: Entity<DapStore>,
|
||||
open_entries: Vec<OpenEntry>,
|
||||
session: Entity<DebugSession>,
|
||||
client_id: DebugAdapterClientId,
|
||||
@@ -348,8 +347,7 @@ pub struct VariableList {
|
||||
impl VariableList {
|
||||
pub fn new(
|
||||
session: Entity<DebugSession>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
dap_store: Entity<DapStore>,
|
||||
client_id: DebugAdapterClientId,
|
||||
stack_frame_list: Entity<StackFrameList>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -387,13 +385,12 @@ impl VariableList {
|
||||
Self {
|
||||
list,
|
||||
session,
|
||||
dap_store,
|
||||
focus_handle,
|
||||
_subscriptions,
|
||||
selection: None,
|
||||
stack_frame_list,
|
||||
set_variable_editor,
|
||||
client_id: *client_id,
|
||||
client_id,
|
||||
open_context_menu: None,
|
||||
set_variable_state: None,
|
||||
fetch_variables_task: None,
|
||||
@@ -426,11 +423,7 @@ impl VariableList {
|
||||
})
|
||||
.collect();
|
||||
|
||||
proto::DebuggerVariableList {
|
||||
scopes,
|
||||
variables,
|
||||
added_variables: vec![],
|
||||
}
|
||||
proto::DebuggerVariableList { scopes, variables }
|
||||
}
|
||||
|
||||
pub(crate) fn set_from_proto(
|
||||
@@ -465,44 +458,10 @@ impl VariableList {
|
||||
})
|
||||
.collect();
|
||||
|
||||
for variables in state.added_variables.iter() {
|
||||
self.add_variables(variables.clone());
|
||||
}
|
||||
|
||||
self.build_entries(true, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub(crate) fn add_variables(&mut self, variables_to_add: proto::AddToVariableList) {
|
||||
let variables: Vec<Variable> = Vec::from_proto(variables_to_add.variables);
|
||||
let variable_id = variables_to_add.variable_id;
|
||||
let stack_frame_id = variables_to_add.stack_frame_id;
|
||||
let scope_id = variables_to_add.scope_id;
|
||||
let key = (stack_frame_id, scope_id);
|
||||
|
||||
if let Some(depth) = self.variables.get(&key).and_then(|containers| {
|
||||
containers
|
||||
.variables
|
||||
.iter()
|
||||
.find(|container| container.variable.variables_reference == variable_id)
|
||||
.map(|container| container.depth + 1usize)
|
||||
}) {
|
||||
if let Some(index) = self.variables.get_mut(&key) {
|
||||
index.add_variables(
|
||||
variable_id,
|
||||
variables
|
||||
.into_iter()
|
||||
.map(|var| VariableContainer {
|
||||
container_reference: variable_id,
|
||||
variable: var,
|
||||
depth,
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_stack_frame_list_events(
|
||||
&mut self,
|
||||
_: Entity<StackFrameList>,
|
||||
@@ -526,35 +485,34 @@ impl VariableList {
|
||||
stack_frame_id: StackFrameId,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.scopes.contains_key(&stack_frame_id) {
|
||||
return self.build_entries(true, cx);
|
||||
}
|
||||
// if self.scopes.contains_key(&stack_frame_id) {
|
||||
// return self.build_entries(true, cx);
|
||||
// }
|
||||
|
||||
self.fetch_variables_task = Some(cx.spawn(|this, mut cx| async move {
|
||||
let task = this.update(&mut cx, |variable_list, cx| {
|
||||
variable_list.fetch_variables_for_stack_frame(stack_frame_id, cx)
|
||||
})?;
|
||||
// self.fetch_variables_task = Some(cx.spawn(|this, mut cx| async move {
|
||||
// let task = this.update(&mut cx, |variable_list, cx| {
|
||||
// variable_list.fetch_variables_for_stack_frame(stack_frame_id, cx)
|
||||
// })?;
|
||||
|
||||
let (scopes, variables) = task.await?;
|
||||
// let (scopes, variables) = task.await?;
|
||||
|
||||
this.update(&mut cx, |variable_list, cx| {
|
||||
variable_list.scopes.insert(stack_frame_id, scopes);
|
||||
// this.update(&mut cx, |variable_list, cx| {
|
||||
// variable_list.scopes.insert(stack_frame_id, scopes);
|
||||
|
||||
for (scope_id, variables) in variables.into_iter() {
|
||||
let mut variable_index = ScopeVariableIndex::new();
|
||||
variable_index.add_variables(scope_id, variables);
|
||||
// for (scope_id, variables) in variables.into_iter() {
|
||||
// let mut variable_index = ScopeVariableIndex::new();
|
||||
// variable_index.add_variables(scope_id, variables);
|
||||
|
||||
variable_list
|
||||
.variables
|
||||
.insert((stack_frame_id, scope_id), variable_index);
|
||||
}
|
||||
// variable_list
|
||||
// .variables
|
||||
// .insert((stack_frame_id, scope_id), variable_index);
|
||||
// }
|
||||
|
||||
variable_list.build_entries(true, cx);
|
||||
variable_list.send_update_proto_message(cx);
|
||||
// variable_list.build_entries(true, cx);
|
||||
|
||||
variable_list.fetch_variables_task.take();
|
||||
})
|
||||
}));
|
||||
// variable_list.fetch_variables_task.take();
|
||||
// })
|
||||
// }));
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
@@ -595,7 +553,9 @@ impl VariableList {
|
||||
}
|
||||
|
||||
pub fn completion_variables(&self, cx: &mut Context<Self>) -> Vec<VariableContainer> {
|
||||
let stack_frame_id = self.stack_frame_list.read(cx).first_stack_frame_id();
|
||||
let stack_frame_id = self
|
||||
.stack_frame_list
|
||||
.update(cx, |this, cx| this.get_main_stack_frame_id(cx));
|
||||
|
||||
self.variables
|
||||
.range((stack_frame_id, u64::MIN)..(stack_frame_id, u64::MAX))
|
||||
@@ -665,24 +625,27 @@ impl VariableList {
|
||||
return self.toggle_entry(&entry_id, cx);
|
||||
}
|
||||
|
||||
let fetch_variables_task = self.dap_store.update(cx, |store, cx| {
|
||||
let thread_id = self.stack_frame_list.read(cx).thread_id();
|
||||
store.variables(
|
||||
&self.client_id,
|
||||
thread_id,
|
||||
stack_frame_id,
|
||||
scope_id,
|
||||
self.session.read(cx).id(),
|
||||
variable.variables_reference,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
// let fetch_variables_task = self.dap_store.update(cx, |store, cx| {
|
||||
// let thread_id = self.stack_frame_list.read(cx).thread_id();
|
||||
// store.variables(
|
||||
// &self.client_id,
|
||||
// thread_id,
|
||||
// stack_frame_id,
|
||||
// scope_id,
|
||||
// self.session.read(cx).id(),
|
||||
// variable.variables_reference,
|
||||
// cx,
|
||||
// )
|
||||
// });
|
||||
let fetch_variables_task = Task::ready(anyhow::Result::Err(anyhow!(
|
||||
"Toggling variables isn't supported yet (dued to refactor)"
|
||||
)));
|
||||
|
||||
let container_reference = variable.variables_reference;
|
||||
let entry_id = entry_id.clone();
|
||||
|
||||
self.fetch_variables_task = Some(cx.spawn(|this, mut cx| async move {
|
||||
let new_variables = fetch_variables_task.await?;
|
||||
let new_variables: Vec<Variable> = fetch_variables_task.await?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
let Some(index) = this.variables.get_mut(&(stack_frame_id, scope_id)) else {
|
||||
@@ -867,119 +830,7 @@ impl VariableList {
|
||||
open_entries: &Vec<OpenEntry>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<VariableContainer>>> {
|
||||
let stack_frame_list = self.stack_frame_list.read(cx);
|
||||
let thread_id = stack_frame_list.thread_id();
|
||||
let stack_frame_id = stack_frame_list.current_stack_frame_id();
|
||||
|
||||
let variables_task = self.dap_store.update(cx, |store, cx| {
|
||||
store.variables(
|
||||
&self.client_id,
|
||||
thread_id,
|
||||
stack_frame_id,
|
||||
scope.variables_reference,
|
||||
self.session.read(cx).id(),
|
||||
container_reference,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
cx.spawn({
|
||||
let scope = scope.clone();
|
||||
let open_entries = open_entries.clone();
|
||||
|this, mut cx| async move {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
for variable in variables_task.await? {
|
||||
variables.push(VariableContainer {
|
||||
depth,
|
||||
container_reference,
|
||||
variable: variable.clone(),
|
||||
});
|
||||
|
||||
if open_entries
|
||||
.binary_search(&OpenEntry::Variable {
|
||||
depth,
|
||||
name: variable.name,
|
||||
scope_name: scope.name.clone(),
|
||||
})
|
||||
.is_ok()
|
||||
{
|
||||
let task = this.update(&mut cx, |this, cx| {
|
||||
this.fetch_nested_variables(
|
||||
&scope,
|
||||
variable.variables_reference,
|
||||
depth + 1,
|
||||
&open_entries,
|
||||
cx,
|
||||
)
|
||||
})?;
|
||||
|
||||
variables.extend(task.await?);
|
||||
}
|
||||
}
|
||||
|
||||
anyhow::Ok(variables)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn fetch_variables_for_stack_frame(
|
||||
&self,
|
||||
stack_frame_id: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<(Vec<Scope>, HashMap<u64, Vec<VariableContainer>>)>> {
|
||||
let scopes_task = self.dap_store.update(cx, |store, cx| {
|
||||
store.scopes(&self.client_id, stack_frame_id, cx)
|
||||
});
|
||||
|
||||
cx.spawn({
|
||||
|this, mut cx| async move {
|
||||
let mut variables = HashMap::new();
|
||||
|
||||
let scopes = scopes_task.await?;
|
||||
|
||||
let open_entries = this.read_with(&cx, |variable_list, _| {
|
||||
variable_list
|
||||
.open_entries
|
||||
.iter()
|
||||
.filter(|entry| matches!(entry, OpenEntry::Variable { .. }))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
})?;
|
||||
|
||||
for scope in scopes.iter() {
|
||||
let variables_task = this.update(&mut cx, |this, cx| {
|
||||
this.fetch_nested_variables(
|
||||
scope,
|
||||
scope.variables_reference,
|
||||
1,
|
||||
&open_entries,
|
||||
cx,
|
||||
)
|
||||
})?;
|
||||
|
||||
variables.insert(scope.variables_reference, variables_task.await?);
|
||||
}
|
||||
|
||||
Ok((scopes, variables))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn send_update_proto_message(&self, cx: &mut Context<Self>) {
|
||||
if let Some((client, project_id)) = self.dap_store.read(cx).downstream_client() {
|
||||
let request = UpdateDebugAdapter {
|
||||
client_id: self.client_id.to_proto(),
|
||||
session_id: self.session.read(cx).id().to_proto(),
|
||||
thread_id: Some(self.stack_frame_list.read(cx).thread_id()),
|
||||
project_id: *project_id,
|
||||
variant: Some(rpc::proto::update_debug_adapter::Variant::VariableList(
|
||||
self.to_proto(),
|
||||
)),
|
||||
};
|
||||
|
||||
client.send(request).log_err();
|
||||
};
|
||||
Task::ready(Ok(vec![]))
|
||||
}
|
||||
|
||||
fn deploy_variable_context_menu(
|
||||
@@ -991,14 +842,20 @@ impl VariableList {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(caps) = self
|
||||
.dap_store
|
||||
let Some((support_set_variable, support_clipboard_context)) = self
|
||||
.session
|
||||
.read(cx)
|
||||
.capabilities_by_id(&self.client_id, 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 support_set_variable = caps.supports_set_variable.unwrap_or_default();
|
||||
|
||||
let this = cx.entity();
|
||||
|
||||
@@ -1016,36 +873,26 @@ impl VariableList {
|
||||
let evaluate_name = variable.evaluate_name.clone();
|
||||
|
||||
window.handler_for(&this.clone(), move |this, _window, cx| {
|
||||
this.dap_store.update(cx, |dap_store, cx| {
|
||||
if dap_store
|
||||
.capabilities_by_id(&this.client_id, cx)
|
||||
.map(|caps| caps.supports_clipboard_context)
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
let task = dap_store.evaluate(
|
||||
&this.client_id,
|
||||
this.stack_frame_list.read(cx).current_stack_frame_id(),
|
||||
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| {
|
||||
state.evaluate(
|
||||
evaluate_name.clone().unwrap_or(variable_name.clone()),
|
||||
dap::EvaluateArgumentsContext::Clipboard,
|
||||
Some(dap::EvaluateArgumentsContext::Clipboard),
|
||||
Some(this.stack_frame_list.read(cx).current_stack_frame_id()),
|
||||
source.clone(),
|
||||
cx,
|
||||
);
|
||||
|
||||
cx.spawn(|_, cx| async move {
|
||||
let response = task.await?;
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(
|
||||
response.result,
|
||||
))
|
||||
})
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
} else {
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(variable_value.clone()))
|
||||
}
|
||||
});
|
||||
});
|
||||
// TODO(debugger): make this work again:
|
||||
// cx.write_to_clipboard(ClipboardItem::new_string(response.result));
|
||||
} else {
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(variable_value.clone()))
|
||||
}
|
||||
})
|
||||
})
|
||||
.when_some(
|
||||
@@ -1126,46 +973,28 @@ impl VariableList {
|
||||
new_variable_value
|
||||
});
|
||||
|
||||
let Some(state) = self.set_variable_state.take() else {
|
||||
let Some(set_variable_state) = self.set_variable_state.take() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if new_variable_value == state.value
|
||||
|| state.stack_frame_id != self.stack_frame_list.read(cx).current_stack_frame_id()
|
||||
if new_variable_value == set_variable_state.value
|
||||
|| set_variable_state.stack_frame_id
|
||||
!= self.stack_frame_list.read(cx).current_stack_frame_id()
|
||||
{
|
||||
return cx.notify();
|
||||
}
|
||||
|
||||
let set_value_task = self.dap_store.update(cx, |store, cx| {
|
||||
store.set_variable_value(
|
||||
&self.client_id,
|
||||
state.stack_frame_id,
|
||||
state.parent_variables_reference,
|
||||
state.name,
|
||||
let Some(client_state) = self.session.read(cx).client_state(self.client_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
client_state.update(cx, |state, cx| {
|
||||
state.set_variable_value(
|
||||
set_variable_state.parent_variables_reference,
|
||||
set_variable_state.name,
|
||||
new_variable_value,
|
||||
state.evaluate_name,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
cx.spawn_in(window, |this, mut cx| async move {
|
||||
set_value_task.await?;
|
||||
|
||||
this.update_in(&mut cx, |this, window, cx| {
|
||||
this.build_entries(false, cx);
|
||||
this.invalidate(window, cx);
|
||||
})
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
pub fn invalidate(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.variables.clear();
|
||||
self.scopes.clear();
|
||||
self.entries.clear();
|
||||
|
||||
self.stack_frame_list.update(cx, |stack_frame_list, cx| {
|
||||
stack_frame_list.invalidate(window, cx);
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ use parking_lot::Mutex;
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
use project::FakeFs;
|
||||
use project::{
|
||||
dap_store::BreakpointKind,
|
||||
debugger::dap_store::BreakpointKind,
|
||||
lsp_command::SIGNATURE_HELP_HIGHLIGHT_CURRENT,
|
||||
project_settings::{LspSettings, ProjectSettings},
|
||||
};
|
||||
|
||||
@@ -44,6 +44,7 @@ globset.workspace = true
|
||||
gpui.workspace = true
|
||||
http_client.workspace = true
|
||||
itertools.workspace = true
|
||||
indexmap.workspace = true
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
lsp.workspace = true
|
||||
|
||||
@@ -5,14 +5,13 @@ use dap::{
|
||||
client::DebugAdapterClientId,
|
||||
proto_conversions::ProtoConversion,
|
||||
requests::{Continue, Next},
|
||||
Capabilities, ContinueArguments, NextArguments, StepInArguments, StepOutArguments,
|
||||
SteppingGranularity, ValueFormat, Variable, VariablesArgumentsFilter,
|
||||
Capabilities, ContinueArguments, NextArguments, SetVariableResponse, StepInArguments,
|
||||
StepOutArguments, SteppingGranularity, ValueFormat, Variable, VariablesArgumentsFilter,
|
||||
};
|
||||
use gpui::{AsyncApp, WeakEntity};
|
||||
use rpc::proto;
|
||||
use util::ResultExt;
|
||||
|
||||
use super::{dap_session::DebugSessionId, dap_store::DapStore};
|
||||
use super::dap_session::DebugSessionId;
|
||||
|
||||
pub(crate) trait DapCommand: 'static + Send + Sync + std::fmt::Debug {
|
||||
type Response: 'static + Send + std::fmt::Debug;
|
||||
@@ -21,28 +20,18 @@ pub(crate) trait DapCommand: 'static + Send + Sync + std::fmt::Debug {
|
||||
|
||||
fn is_supported(&self, capabilities: &Capabilities) -> bool;
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
_dap_store: WeakEntity<DapStore>,
|
||||
_client_id: &DebugAdapterClientId,
|
||||
response: Result<Self::Response>,
|
||||
_cx: &mut AsyncApp,
|
||||
) -> Result<Self::Response> {
|
||||
response
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId;
|
||||
|
||||
fn from_proto(request: &Self::ProtoRequest) -> Self;
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest;
|
||||
|
||||
fn response_to_proto(
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
|
||||
|
||||
@@ -78,14 +67,14 @@ impl<T: DapCommand> DapCommand for Arc<T> {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
T::to_proto(self, debug_client_id, upstream_project_id)
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
T::response_to_proto(debug_client_id, message)
|
||||
@@ -161,7 +150,7 @@ impl DapCommand for NextCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -169,7 +158,7 @@ impl DapCommand for NextCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapNextRequest {
|
||||
proto::DapNextRequest {
|
||||
@@ -235,7 +224,7 @@ impl DapCommand for StepInCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -243,7 +232,7 @@ impl DapCommand for StepInCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapStepInRequest {
|
||||
proto::DapStepInRequest {
|
||||
@@ -294,36 +283,6 @@ impl DapCommand for StepOutCommand {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
dap_store: WeakEntity<DapStore>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
response: Result<Self::Response>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<Self::Response> {
|
||||
if response.is_ok() {
|
||||
dap_store
|
||||
.update(cx, |this, cx| {
|
||||
if let Some((client, project_id)) = this.downstream_client() {
|
||||
let thread_message = proto::UpdateThreadStatus {
|
||||
project_id: *project_id,
|
||||
client_id: client_id.to_proto(),
|
||||
thread_id: self.inner.thread_id,
|
||||
status: proto::DebuggerThreadStatus::Running.into(),
|
||||
};
|
||||
|
||||
cx.emit(super::dap_store::DapStoreEvent::UpdateThreadStatus(
|
||||
thread_message.clone(),
|
||||
));
|
||||
|
||||
client.send(thread_message).log_err();
|
||||
}
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
response
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
@@ -341,7 +300,7 @@ impl DapCommand for StepOutCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -349,7 +308,7 @@ impl DapCommand for StepOutCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapStepOutRequest {
|
||||
proto::DapStepOutRequest {
|
||||
@@ -415,7 +374,7 @@ impl DapCommand for StepBackCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -423,7 +382,7 @@ impl DapCommand for StepBackCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapStepBackRequest {
|
||||
proto::DapStepBackRequest {
|
||||
@@ -472,43 +431,13 @@ impl DapCommand for ContinueCommand {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
dap_store: WeakEntity<DapStore>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
response: Result<Self::Response>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<Self::Response> {
|
||||
if response.is_ok() {
|
||||
dap_store
|
||||
.update(cx, |this, cx| {
|
||||
if let Some((client, project_id)) = this.downstream_client() {
|
||||
let thread_message = proto::UpdateThreadStatus {
|
||||
project_id: *project_id,
|
||||
client_id: client_id.to_proto(),
|
||||
thread_id: self.args.thread_id,
|
||||
status: proto::DebuggerThreadStatus::Running.into(),
|
||||
};
|
||||
|
||||
cx.emit(super::dap_store::DapStoreEvent::UpdateThreadStatus(
|
||||
thread_message.clone(),
|
||||
));
|
||||
|
||||
client.send(thread_message).log_err();
|
||||
}
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
response
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapContinueRequest {
|
||||
proto::DapContinueRequest {
|
||||
@@ -549,7 +478,7 @@ impl DapCommand for ContinueCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapContinueResponse {
|
||||
@@ -585,7 +514,7 @@ impl DapCommand for PauseCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapPauseRequest {
|
||||
proto::DapPauseRequest {
|
||||
@@ -596,7 +525,7 @@ impl DapCommand for PauseCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -653,7 +582,7 @@ impl DapCommand for DisconnectCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapDisconnectRequest {
|
||||
proto::DapDisconnectRequest {
|
||||
@@ -666,7 +595,7 @@ impl DapCommand for DisconnectCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -727,7 +656,7 @@ impl DapCommand for TerminateThreadsCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapTerminateThreadsRequest {
|
||||
proto::DapTerminateThreadsRequest {
|
||||
@@ -738,7 +667,7 @@ impl DapCommand for TerminateThreadsCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -791,7 +720,7 @@ impl DapCommand for TerminateCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapTerminateRequest {
|
||||
proto::DapTerminateRequest {
|
||||
@@ -802,7 +731,7 @@ impl DapCommand for TerminateCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -857,7 +786,7 @@ impl DapCommand for RestartCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapRestartRequest {
|
||||
let raw_args = serde_json::to_vec(&self.raw).log_err().unwrap_or_default();
|
||||
@@ -870,7 +799,7 @@ impl DapCommand for RestartCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -900,7 +829,6 @@ impl DapCommand for RestartCommand {
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
pub struct VariablesCommand {
|
||||
pub stack_frame_id: u64,
|
||||
pub scope_id: u64,
|
||||
pub thread_id: u64,
|
||||
pub variables_reference: u64,
|
||||
pub session_id: DebugSessionId,
|
||||
@@ -919,40 +847,6 @@ impl DapCommand for VariablesCommand {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
dap_store: WeakEntity<DapStore>,
|
||||
client_id: &DebugAdapterClientId,
|
||||
response: Result<Self::Response>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<Self::Response> {
|
||||
let variables = response?;
|
||||
|
||||
dap_store.update(cx, |this, _| {
|
||||
if let Some((downstream_clients, project_id)) = this.downstream_client() {
|
||||
let update = proto::UpdateDebugAdapter {
|
||||
project_id: *project_id,
|
||||
session_id: self.session_id.to_proto(),
|
||||
client_id: client_id.to_proto(),
|
||||
thread_id: Some(self.thread_id),
|
||||
variant: Some(proto::update_debug_adapter::Variant::AddToVariableList(
|
||||
proto::AddToVariableList {
|
||||
scope_id: self.scope_id,
|
||||
stack_frame_id: self.stack_frame_id,
|
||||
variable_id: self.variables_reference,
|
||||
variables: variables.to_proto(),
|
||||
},
|
||||
)),
|
||||
};
|
||||
|
||||
downstream_clients.send(update.clone()).log_err();
|
||||
// cx.emit(crate::dap_store::DapStoreEvent::UpdateDebugAdapter(update));
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(variables)
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
@@ -976,7 +870,7 @@ impl DapCommand for VariablesCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
proto::VariablesRequest {
|
||||
@@ -985,7 +879,6 @@ impl DapCommand for VariablesCommand {
|
||||
thread_id: self.thread_id,
|
||||
session_id: self.session_id.to_proto(),
|
||||
stack_frame_id: self.stack_frame_id,
|
||||
scope_id: self.scope_id,
|
||||
variables_reference: self.variables_reference,
|
||||
filter: None,
|
||||
start: self.start,
|
||||
@@ -999,7 +892,6 @@ impl DapCommand for VariablesCommand {
|
||||
thread_id: request.thread_id,
|
||||
session_id: DebugSessionId::from_proto(request.session_id),
|
||||
stack_frame_id: request.stack_frame_id,
|
||||
scope_id: request.scope_id,
|
||||
variables_reference: request.variables_reference,
|
||||
filter: None,
|
||||
start: request.start,
|
||||
@@ -1009,7 +901,7 @@ impl DapCommand for VariablesCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapVariables {
|
||||
@@ -1026,6 +918,94 @@ impl DapCommand for VariablesCommand {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
pub(crate) struct SetVariableValueCommand {
|
||||
pub name: String,
|
||||
pub value: String,
|
||||
pub variables_reference: u64,
|
||||
}
|
||||
|
||||
impl DapCommand for SetVariableValueCommand {
|
||||
type Response = SetVariableResponse;
|
||||
type DapRequest = dap::requests::SetVariable;
|
||||
type ProtoRequest = proto::DapSetVariableValueRequest;
|
||||
|
||||
fn is_supported(&self, capabilities: &Capabilities) -> bool {
|
||||
capabilities.supports_set_variable.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
|
||||
fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
|
||||
dap::SetVariableArguments {
|
||||
format: None,
|
||||
name: self.name.clone(),
|
||||
value: self.value.clone(),
|
||||
variables_reference: self.variables_reference,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_dap(
|
||||
&self,
|
||||
message: <Self::DapRequest as dap::requests::Request>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
proto::DapSetVariableValueRequest {
|
||||
project_id: upstream_project_id,
|
||||
client_id: debug_client_id.to_proto(),
|
||||
variables_reference: self.variables_reference,
|
||||
value: self.value.clone(),
|
||||
name: self.name.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(request: &Self::ProtoRequest) -> Self {
|
||||
Self {
|
||||
variables_reference: request.variables_reference,
|
||||
name: request.name.clone(),
|
||||
value: request.value.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapSetVariableValueResponse {
|
||||
client_id: debug_client_id.to_proto(),
|
||||
value: message.value,
|
||||
variable_type: message.type_,
|
||||
named_variables: message.named_variables,
|
||||
variables_reference: message.variables_reference,
|
||||
indexed_variables: message.indexed_variables,
|
||||
memory_reference: message.memory_reference,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_proto(
|
||||
&self,
|
||||
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(SetVariableResponse {
|
||||
value: message.value,
|
||||
type_: message.variable_type,
|
||||
variables_reference: message.variables_reference,
|
||||
named_variables: message.named_variables,
|
||||
indexed_variables: message.indexed_variables,
|
||||
memory_reference: message.memory_reference,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub(crate) struct RestartStackFrameCommand {
|
||||
pub stack_frame_id: u64,
|
||||
@@ -1052,7 +1032,7 @@ impl DapCommand for RestartStackFrameCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapRestartStackFrameRequest {
|
||||
proto::DapRestartStackFrameRequest {
|
||||
@@ -1063,7 +1043,7 @@ impl DapCommand for RestartStackFrameCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: &DebugAdapterClientId,
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
_message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::Ack {}
|
||||
@@ -1112,7 +1092,7 @@ impl DapCommand for ModulesCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapModulesRequest {
|
||||
proto::DapModulesRequest {
|
||||
@@ -1122,7 +1102,7 @@ impl DapCommand for ModulesCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapModulesResponse {
|
||||
@@ -1184,7 +1164,7 @@ impl DapCommand for LoadedSourcesCommand {
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> proto::DapLoadedSourcesRequest {
|
||||
proto::DapLoadedSourcesRequest {
|
||||
@@ -1194,7 +1174,7 @@ impl DapCommand for LoadedSourcesCommand {
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
debug_client_id: &DebugAdapterClientId,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapLoadedSourcesResponse {
|
||||
@@ -1228,3 +1208,381 @@ impl DapCommand for LoadedSourcesCommand {
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub(crate) struct StackTraceCommand {
|
||||
pub thread_id: u64,
|
||||
pub start_frame: Option<u64>,
|
||||
pub levels: Option<u64>,
|
||||
}
|
||||
|
||||
impl DapCommand for StackTraceCommand {
|
||||
type Response = Vec<dap::StackFrame>;
|
||||
type DapRequest = dap::requests::StackTrace;
|
||||
type ProtoRequest = proto::DapStackTraceRequest;
|
||||
|
||||
fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
|
||||
dap::StackTraceArguments {
|
||||
thread_id: self.thread_id,
|
||||
start_frame: self.start_frame,
|
||||
levels: self.levels,
|
||||
format: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_dap(
|
||||
&self,
|
||||
message: <Self::DapRequest as dap::requests::Request>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(message.stack_frames)
|
||||
}
|
||||
|
||||
fn is_supported(&self, _capabilities: &Capabilities) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
proto::DapStackTraceRequest {
|
||||
project_id: upstream_project_id,
|
||||
client_id: debug_client_id.to_proto(),
|
||||
thread_id: self.thread_id,
|
||||
start_frame: self.start_frame,
|
||||
stack_trace_levels: self.levels,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(request: &Self::ProtoRequest) -> Self {
|
||||
Self {
|
||||
thread_id: request.thread_id,
|
||||
start_frame: request.start_frame,
|
||||
levels: request.stack_trace_levels,
|
||||
}
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
|
||||
fn response_from_proto(
|
||||
&self,
|
||||
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(message
|
||||
.frames
|
||||
.into_iter()
|
||||
.map(dap::StackFrame::from_proto)
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapStackTraceResponse {
|
||||
frames: message.to_proto(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub(crate) struct ScopesCommand {
|
||||
pub thread_id: u64,
|
||||
pub stack_frame_id: u64,
|
||||
}
|
||||
|
||||
impl DapCommand for ScopesCommand {
|
||||
type Response = Vec<dap::Scope>;
|
||||
type DapRequest = dap::requests::Scopes;
|
||||
type ProtoRequest = proto::DapScopesRequest;
|
||||
|
||||
fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
|
||||
dap::ScopesArguments {
|
||||
frame_id: self.stack_frame_id,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_dap(
|
||||
&self,
|
||||
message: <Self::DapRequest as dap::requests::Request>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(message.scopes)
|
||||
}
|
||||
|
||||
fn is_supported(&self, _capabilities: &Capabilities) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
proto::DapScopesRequest {
|
||||
project_id: upstream_project_id,
|
||||
client_id: debug_client_id.to_proto(),
|
||||
thread_id: self.thread_id,
|
||||
stack_frame_id: self.stack_frame_id,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(request: &Self::ProtoRequest) -> Self {
|
||||
Self {
|
||||
thread_id: request.thread_id,
|
||||
stack_frame_id: request.stack_frame_id,
|
||||
}
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
|
||||
fn response_from_proto(
|
||||
&self,
|
||||
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(Vec::from_proto(message.scopes))
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapScopesResponse {
|
||||
scopes: message.to_proto(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DapCommand for super::dap_session::CompletionsQuery {
|
||||
type Response = dap::CompletionsResponse;
|
||||
type DapRequest = dap::requests::Completions;
|
||||
type ProtoRequest = proto::DapCompletionRequest;
|
||||
|
||||
fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
|
||||
dap::CompletionsArguments {
|
||||
text: self.query.clone(),
|
||||
frame_id: self.frame_id,
|
||||
column: self.column,
|
||||
line: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_dap(
|
||||
&self,
|
||||
message: <Self::DapRequest as dap::requests::Request>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
fn is_supported(&self, capabilities: &Capabilities) -> bool {
|
||||
capabilities
|
||||
.supports_completions_request
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
proto::DapCompletionRequest {
|
||||
client_id: debug_client_id.to_proto(),
|
||||
project_id: upstream_project_id,
|
||||
frame_id: self.frame_id,
|
||||
query: self.query.clone(),
|
||||
column: self.column,
|
||||
line: self.line.map(u64::from),
|
||||
}
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
|
||||
fn from_proto(request: &Self::ProtoRequest) -> Self {
|
||||
Self {
|
||||
query: request.query.clone(),
|
||||
frame_id: request.frame_id,
|
||||
column: request.column,
|
||||
line: request.line,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_proto(
|
||||
&self,
|
||||
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(dap::CompletionsResponse {
|
||||
targets: Vec::from_proto(message.completions),
|
||||
})
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapCompletionResponse {
|
||||
client_id: _debug_client_id.to_proto(),
|
||||
completions: message.targets.to_proto(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub(crate) struct EvaluateCommand {
|
||||
pub expression: String,
|
||||
pub frame_id: Option<u64>,
|
||||
pub context: Option<dap::EvaluateArgumentsContext>,
|
||||
pub source: Option<dap::Source>,
|
||||
}
|
||||
|
||||
impl DapCommand for EvaluateCommand {
|
||||
type Response = dap::EvaluateResponse;
|
||||
type DapRequest = dap::requests::Evaluate;
|
||||
type ProtoRequest = proto::DapEvaluateRequest;
|
||||
|
||||
fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
|
||||
dap::EvaluateArguments {
|
||||
expression: self.expression.clone(),
|
||||
frame_id: self.frame_id,
|
||||
context: self.context.clone(),
|
||||
source: self.source.clone(),
|
||||
line: None,
|
||||
column: None,
|
||||
format: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_dap(
|
||||
&self,
|
||||
message: <Self::DapRequest as dap::requests::Request>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
fn is_supported(&self, _capabilities: &Capabilities) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
proto::DapEvaluateRequest {
|
||||
client_id: debug_client_id.to_proto(),
|
||||
project_id: upstream_project_id,
|
||||
expression: self.expression.clone(),
|
||||
frame_id: self.frame_id,
|
||||
context: self
|
||||
.context
|
||||
.clone()
|
||||
.map(|context| context.to_proto().into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
|
||||
fn from_proto(request: &Self::ProtoRequest) -> Self {
|
||||
Self {
|
||||
expression: request.expression.clone(),
|
||||
frame_id: request.frame_id,
|
||||
context: Some(dap::EvaluateArgumentsContext::from_proto(request.context())),
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn response_from_proto(
|
||||
&self,
|
||||
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(dap::EvaluateResponse {
|
||||
result: message.result.clone(),
|
||||
type_: message.evaluate_type.clone(),
|
||||
presentation_hint: None,
|
||||
variables_reference: message.variable_reference,
|
||||
named_variables: message.named_variables,
|
||||
indexed_variables: message.indexed_variables,
|
||||
memory_reference: message.memory_reference.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapEvaluateResponse {
|
||||
result: message.result,
|
||||
evaluate_type: message.type_,
|
||||
variable_reference: message.variables_reference,
|
||||
named_variables: message.named_variables,
|
||||
indexed_variables: message.indexed_variables,
|
||||
memory_reference: message.memory_reference,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub(crate) struct ThreadsCommand;
|
||||
|
||||
impl DapCommand for ThreadsCommand {
|
||||
type Response = Vec<dap::Thread>;
|
||||
type DapRequest = dap::requests::Threads;
|
||||
type ProtoRequest = proto::DapThreadsRequest;
|
||||
|
||||
fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
|
||||
()
|
||||
}
|
||||
|
||||
fn response_from_dap(
|
||||
&self,
|
||||
message: <Self::DapRequest as dap::requests::Request>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(message.threads)
|
||||
}
|
||||
|
||||
fn is_supported(&self, _capabilities: &Capabilities) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn to_proto(
|
||||
&self,
|
||||
debug_client_id: DebugAdapterClientId,
|
||||
upstream_project_id: u64,
|
||||
) -> Self::ProtoRequest {
|
||||
proto::DapThreadsRequest {
|
||||
project_id: upstream_project_id,
|
||||
client_id: debug_client_id.to_proto(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_proto(_request: &Self::ProtoRequest) -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn client_id_from_proto(request: &Self::ProtoRequest) -> DebugAdapterClientId {
|
||||
DebugAdapterClientId::from_proto(request.client_id)
|
||||
}
|
||||
|
||||
fn response_from_proto(
|
||||
&self,
|
||||
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
||||
) -> Result<Self::Response> {
|
||||
Ok(Vec::from_proto(message.threads))
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
_debug_client_id: DebugAdapterClientId,
|
||||
message: Self::Response,
|
||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response {
|
||||
proto::DapThreadsResponse {
|
||||
threads: message.to_proto(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
use collections::{BTreeMap, HashMap};
|
||||
use dap::{Capabilities, Module, Source};
|
||||
use super::dap_command::{
|
||||
self, ContinueCommand, DapCommand, DisconnectCommand, EvaluateCommand, NextCommand,
|
||||
PauseCommand, RestartCommand, RestartStackFrameCommand, ScopesCommand, SetVariableValueCommand,
|
||||
StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand,
|
||||
TerminateThreadsCommand, VariablesCommand,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::{BTreeMap, HashMap, IndexMap};
|
||||
use dap::client::{DebugAdapterClient, DebugAdapterClientId};
|
||||
use dap::requests::Request;
|
||||
use dap::{
|
||||
Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, SteppingGranularity,
|
||||
};
|
||||
use futures::{future::Shared, FutureExt};
|
||||
use gpui::{AppContext, Context, Entity, Task, WeakEntity};
|
||||
use gpui::{App, AppContext, Context, Entity, Task};
|
||||
use rpc::AnyProtoClient;
|
||||
use serde_json::Value;
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::btree_map::Entry as BTreeMapEntry;
|
||||
use std::u64;
|
||||
use std::{
|
||||
any::Any,
|
||||
collections::hash_map::Entry,
|
||||
@@ -9,14 +25,9 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
use task::DebugAdapterConfig;
|
||||
use text::{PointUtf16, ToPointUtf16};
|
||||
use util::ResultExt;
|
||||
|
||||
use super::{
|
||||
dap_command::{self, DapCommand},
|
||||
dap_store::DapStore,
|
||||
};
|
||||
use dap::client::{DebugAdapterClient, DebugAdapterClientId};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct DebugSessionId(pub usize);
|
||||
@@ -31,23 +42,58 @@ impl DebugSessionId {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)]
|
||||
#[repr(transparent)]
|
||||
struct ThreadId(u64);
|
||||
pub struct ThreadId(pub u64);
|
||||
|
||||
struct Variable {
|
||||
_variable: dap::Variable,
|
||||
_variables: Vec<Variable>,
|
||||
impl ThreadId {
|
||||
pub const MIN: ThreadId = ThreadId(u64::MIN);
|
||||
pub const MAX: ThreadId = ThreadId(u64::MAX);
|
||||
}
|
||||
|
||||
struct Scope {
|
||||
_scope: dap::Scope,
|
||||
_variables: Vec<Variable>,
|
||||
#[derive(Clone)]
|
||||
pub struct Variable {
|
||||
dap: dap::Variable,
|
||||
variables: Vec<Variable>,
|
||||
}
|
||||
|
||||
struct StackFrame {
|
||||
_stack_frame: dap::StackFrame,
|
||||
_scopes: Vec<Scope>,
|
||||
impl From<dap::Variable> for Variable {
|
||||
fn from(dap: dap::Variable) -> Self {
|
||||
Self {
|
||||
dap,
|
||||
variables: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Scope {
|
||||
pub dap: dap::Scope,
|
||||
pub variables: Vec<Variable>,
|
||||
}
|
||||
|
||||
impl From<dap::Scope> for Scope {
|
||||
fn from(scope: dap::Scope) -> Self {
|
||||
Self {
|
||||
dap: scope,
|
||||
variables: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StackFrame {
|
||||
pub dap: dap::StackFrame,
|
||||
pub scopes: Vec<Scope>,
|
||||
}
|
||||
|
||||
impl From<dap::StackFrame> for StackFrame {
|
||||
fn from(stack_frame: dap::StackFrame) -> Self {
|
||||
Self {
|
||||
scopes: vec![],
|
||||
dap: stack_frame,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, PartialEq, Eq)]
|
||||
@@ -59,20 +105,140 @@ pub enum ThreadStatus {
|
||||
Ended,
|
||||
}
|
||||
|
||||
struct Thread {
|
||||
_thread: dap::Thread,
|
||||
_stack_frames: Vec<StackFrame>,
|
||||
pub struct Thread {
|
||||
dap: dap::Thread,
|
||||
stack_frames: Vec<StackFrame>,
|
||||
_status: ThreadStatus,
|
||||
_has_stopped: bool,
|
||||
}
|
||||
|
||||
pub struct DebugAdapterClientState {
|
||||
dap_store: WeakEntity<DapStore>,
|
||||
impl From<dap::Thread> for Thread {
|
||||
fn from(dap: dap::Thread) -> Self {
|
||||
Self {
|
||||
dap,
|
||||
stack_frames: vec![],
|
||||
_status: ThreadStatus::default(),
|
||||
_has_stopped: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type UpstreamProjectId = u64;
|
||||
|
||||
pub struct RemoteConnection {
|
||||
client: AnyProtoClient,
|
||||
upstream_project_id: UpstreamProjectId,
|
||||
}
|
||||
|
||||
impl RemoteConnection {
|
||||
fn send_proto_client_request<R: DapCommand>(
|
||||
&self,
|
||||
request: R,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<R::Response>> {
|
||||
let message = request.to_proto(client_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>(
|
||||
&self,
|
||||
request: R,
|
||||
client_id: DebugAdapterClientId,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Mode {
|
||||
Local(Arc<DebugAdapterClient>),
|
||||
Remote(RemoteConnection),
|
||||
}
|
||||
|
||||
impl From<RemoteConnection> for Mode {
|
||||
fn from(value: RemoteConnection) -> Self {
|
||||
Self::Remote(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<DebugAdapterClient>> for Mode {
|
||||
fn from(client: Arc<DebugAdapterClient>) -> Self {
|
||||
Mode::Local(client)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
fn request_local<R: DapCommand>(
|
||||
connection: &Arc<DebugAdapterClient>,
|
||||
caps: &Capabilities,
|
||||
request: R,
|
||||
cx: &mut Context<Client>,
|
||||
) -> Task<Result<R::Response>>
|
||||
where
|
||||
<R::DapRequest as dap::requests::Request>::Response: 'static,
|
||||
<R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
|
||||
{
|
||||
if !request.is_supported(&caps) {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Request {} is not supported",
|
||||
R::DapRequest::COMMAND
|
||||
)));
|
||||
}
|
||||
|
||||
let request = Arc::new(request);
|
||||
|
||||
let request_clone = request.clone();
|
||||
let connection = connection.clone();
|
||||
let request_task = cx.background_executor().spawn(async move {
|
||||
let args = request_clone.to_dap();
|
||||
connection.request::<R::DapRequest>(args).await
|
||||
});
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
let response = request.response_from_dap(request_task.await?);
|
||||
response
|
||||
})
|
||||
}
|
||||
|
||||
fn request_dap<R: DapCommand>(
|
||||
&self,
|
||||
caps: &Capabilities,
|
||||
client_id: DebugAdapterClientId,
|
||||
request: R,
|
||||
cx: &mut Context<Client>,
|
||||
) -> Task<Result<R::Response>>
|
||||
where
|
||||
<R::DapRequest as dap::requests::Request>::Response: 'static,
|
||||
<R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
|
||||
{
|
||||
match self {
|
||||
Mode::Local(debug_adapter_client) => {
|
||||
Self::request_local(&debug_adapter_client, caps, request, cx)
|
||||
}
|
||||
Mode::Remote(remote_connection) => {
|
||||
remote_connection.request_remote(request, client_id, cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a current state of a single debug adapter and provides ways to mutate it.
|
||||
pub struct Client {
|
||||
mode: Mode,
|
||||
|
||||
pub(super) capabilities: Capabilities,
|
||||
client_id: DebugAdapterClientId,
|
||||
modules: Vec<dap::Module>,
|
||||
loaded_sources: Vec<dap::Source>,
|
||||
_threads: BTreeMap<ThreadId, Thread>,
|
||||
threads: IndexMap<ThreadId, Thread>,
|
||||
requests: HashMap<RequestSlot, Shared<Task<Option<()>>>>,
|
||||
}
|
||||
|
||||
@@ -127,7 +293,35 @@ impl Hash for RequestSlot {
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugAdapterClientState {
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct CompletionsQuery {
|
||||
pub query: String,
|
||||
pub column: u64,
|
||||
pub line: Option<u64>,
|
||||
pub frame_id: Option<u64>,
|
||||
}
|
||||
|
||||
impl CompletionsQuery {
|
||||
pub fn new(
|
||||
buffer: &language::Buffer,
|
||||
cursor_position: language::Anchor,
|
||||
frame_id: Option<u64>,
|
||||
) -> Self {
|
||||
let PointUtf16 { row, column } = cursor_position.to_point_utf16(&buffer.snapshot());
|
||||
Self {
|
||||
query: buffer.text(),
|
||||
column: column as u64,
|
||||
frame_id,
|
||||
line: Some(row as u64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn capabilities(&self) -> &Capabilities {
|
||||
&self.capabilities
|
||||
}
|
||||
|
||||
pub(crate) fn _wait_for_request<R: DapCommand + PartialEq + Eq + Hash>(
|
||||
&self,
|
||||
request: R,
|
||||
@@ -136,48 +330,102 @@ impl DebugAdapterClientState {
|
||||
self.requests.get(&request_slot).cloned()
|
||||
}
|
||||
|
||||
/// Ensure that there's a request in flight for the given command, and if not, send it.
|
||||
fn request<T: DapCommand + PartialEq + Eq + Hash>(
|
||||
/// Ensure that there's a request in flight for the given command, and if not, send it. Use this to run requests that are idempotent.
|
||||
fn fetch<T: DapCommand + PartialEq + Eq + Hash>(
|
||||
&mut self,
|
||||
request: T,
|
||||
process_result: impl FnOnce(&mut Self, T::Response) + 'static + Send + Sync,
|
||||
process_result: impl FnOnce(&mut Self, &T::Response, &mut Context<Self>) + 'static,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Entry::Vacant(vacant) = self.requests.entry(request.into()) {
|
||||
let command = vacant.key().0.clone().as_any_arc().downcast::<T>().unwrap();
|
||||
|
||||
if let Ok(request) = self.dap_store.update(cx, |dap_store, cx| {
|
||||
dap_store.request_dap(&self.client_id, command, cx)
|
||||
}) {
|
||||
let task = cx
|
||||
.spawn(|this, mut cx| async move {
|
||||
let result = request.await.log_err()?;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
process_result(this, result);
|
||||
cx.notify();
|
||||
})
|
||||
.log_err()
|
||||
})
|
||||
.shared();
|
||||
let task = Self::request_inner::<Arc<T>>(
|
||||
&self.capabilities,
|
||||
self.client_id,
|
||||
&self.mode,
|
||||
command,
|
||||
process_result,
|
||||
cx,
|
||||
);
|
||||
let task = cx
|
||||
.background_executor()
|
||||
.spawn(async move {
|
||||
let _ = task.await?;
|
||||
Some(())
|
||||
})
|
||||
.shared();
|
||||
|
||||
vacant.insert(task);
|
||||
}
|
||||
vacant.insert(task);
|
||||
}
|
||||
}
|
||||
|
||||
fn request_inner<T: DapCommand + PartialEq + Eq + Hash>(
|
||||
capabilities: &Capabilities,
|
||||
client_id: DebugAdapterClientId,
|
||||
mode: &Mode,
|
||||
request: T,
|
||||
process_result: impl FnOnce(&mut Self, &T::Response, &mut Context<Self>) + 'static,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Option<T::Response>> {
|
||||
let request = mode.request_dap(&capabilities, client_id, request, cx);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let result = request.await.log_err()?;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
process_result(this, &result, cx);
|
||||
})
|
||||
.log_err();
|
||||
Some(result)
|
||||
})
|
||||
}
|
||||
|
||||
fn request<T: DapCommand + PartialEq + Eq + Hash>(
|
||||
&self,
|
||||
request: T,
|
||||
process_result: impl FnOnce(&mut Self, &T::Response, &mut Context<Self>) + 'static,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Option<T::Response>> {
|
||||
Self::request_inner(
|
||||
&self.capabilities,
|
||||
self.client_id,
|
||||
&self.mode,
|
||||
request,
|
||||
process_result,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn invalidate(&mut self, cx: &mut Context<Self>) {
|
||||
self.requests.clear();
|
||||
self.modules.clear();
|
||||
self.loaded_sources.clear();
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn threads(&mut self, cx: &mut Context<Self>) -> Vec<dap::Thread> {
|
||||
self.fetch(
|
||||
dap_command::ThreadsCommand,
|
||||
|this, result, cx| {
|
||||
this.threads.extend(
|
||||
result
|
||||
.iter()
|
||||
.map(|thread| (ThreadId(thread.id), Thread::from(thread.clone()))),
|
||||
);
|
||||
},
|
||||
cx,
|
||||
);
|
||||
self.threads
|
||||
.values()
|
||||
.map(|thread| thread.dap.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn modules(&mut self, cx: &mut Context<Self>) -> &[Module] {
|
||||
self.request(
|
||||
self.fetch(
|
||||
dap_command::ModulesCommand,
|
||||
|this, result| {
|
||||
this.modules = result;
|
||||
|this, result, cx| {
|
||||
this.modules = result.clone();
|
||||
cx.notify();
|
||||
},
|
||||
cx,
|
||||
);
|
||||
@@ -198,16 +446,224 @@ impl DebugAdapterClientState {
|
||||
}
|
||||
|
||||
pub fn loaded_sources(&mut self, cx: &mut Context<Self>) -> &[Source] {
|
||||
self.request(
|
||||
self.fetch(
|
||||
dap_command::LoadedSourcesCommand,
|
||||
|this, result| {
|
||||
this.loaded_sources = result;
|
||||
|this, result, cx| {
|
||||
this.loaded_sources = result.clone();
|
||||
cx.notify();
|
||||
},
|
||||
cx,
|
||||
);
|
||||
&self.loaded_sources
|
||||
}
|
||||
|
||||
fn empty_response(&mut self, _: &(), _cx: &mut Context<Self>) {}
|
||||
|
||||
pub fn pause_thread(&mut self, thread_id: ThreadId, cx: &mut Context<Self>) {
|
||||
self.request(
|
||||
PauseCommand {
|
||||
thread_id: thread_id.0,
|
||||
},
|
||||
Self::empty_response,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn restart_stack_frame(&mut self, stack_frame_id: u64, cx: &mut Context<Self>) {
|
||||
self.request(
|
||||
RestartStackFrameCommand { stack_frame_id },
|
||||
Self::empty_response,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn restart(&mut self, args: Option<Value>, cx: &mut Context<Self>) {
|
||||
if self.capabilities.supports_restart_request.unwrap_or(false) {
|
||||
self.request(
|
||||
RestartCommand {
|
||||
raw: args.unwrap_or(Value::Null),
|
||||
},
|
||||
Self::empty_response,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
} else {
|
||||
self.request(
|
||||
DisconnectCommand {
|
||||
restart: Some(false),
|
||||
terminate_debuggee: Some(true),
|
||||
suspend_debuggee: Some(false),
|
||||
},
|
||||
Self::empty_response,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&mut self, cx: &mut Context<Self>) {
|
||||
if self
|
||||
.capabilities
|
||||
.supports_terminate_request
|
||||
.unwrap_or_default()
|
||||
{
|
||||
self.request(
|
||||
TerminateCommand {
|
||||
restart: Some(false),
|
||||
},
|
||||
Self::empty_response,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
} else {
|
||||
self.request(
|
||||
DisconnectCommand {
|
||||
restart: Some(false),
|
||||
terminate_debuggee: Some(true),
|
||||
suspend_debuggee: Some(false),
|
||||
},
|
||||
Self::empty_response,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn completions(
|
||||
&mut self,
|
||||
query: CompletionsQuery,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<dap::CompletionItem>>> {
|
||||
let task = self.request(query, |_, _, _| {}, cx);
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
anyhow::Ok(
|
||||
task.await
|
||||
.map(|response| response.targets)
|
||||
.ok_or_else(|| anyhow!("failed to fetch completions"))?,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn continue_thread(&mut self, thread_id: ThreadId, cx: &mut Context<Self>) {
|
||||
self.request(
|
||||
ContinueCommand {
|
||||
args: ContinueArguments {
|
||||
thread_id: thread_id.0,
|
||||
single_thread: Some(true),
|
||||
},
|
||||
},
|
||||
|_, _, _| {}, // todo: what do we do about the payload here?
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn adapter_client(&self) -> Option<Arc<DebugAdapterClient>> {
|
||||
match self.mode {
|
||||
Mode::Local(ref adapter_client) => Some(adapter_client.clone()),
|
||||
Mode::Remote(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step_over(
|
||||
&mut self,
|
||||
thread_id: ThreadId,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let supports_single_thread_execution_requests =
|
||||
self.capabilities.supports_single_thread_execution_requests;
|
||||
let supports_stepping_granularity = self
|
||||
.capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = NextCommand {
|
||||
inner: StepCommand {
|
||||
thread_id: thread_id.0,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests,
|
||||
},
|
||||
};
|
||||
|
||||
self.request(command, Self::empty_response, cx).detach();
|
||||
}
|
||||
|
||||
pub fn step_in(
|
||||
&self,
|
||||
thread_id: ThreadId,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let supports_single_thread_execution_requests =
|
||||
self.capabilities.supports_single_thread_execution_requests;
|
||||
let supports_stepping_granularity = self
|
||||
.capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = StepInCommand {
|
||||
inner: StepCommand {
|
||||
thread_id: thread_id.0,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests,
|
||||
},
|
||||
};
|
||||
|
||||
self.request(command, Self::empty_response, cx).detach();
|
||||
}
|
||||
|
||||
pub fn step_out(
|
||||
&self,
|
||||
thread_id: ThreadId,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let supports_single_thread_execution_requests =
|
||||
self.capabilities.supports_single_thread_execution_requests;
|
||||
let supports_stepping_granularity = self
|
||||
.capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = StepOutCommand {
|
||||
inner: StepCommand {
|
||||
thread_id: thread_id.0,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests,
|
||||
},
|
||||
};
|
||||
|
||||
self.request(command, Self::empty_response, cx).detach();
|
||||
}
|
||||
|
||||
pub fn step_back(
|
||||
&self,
|
||||
thread_id: ThreadId,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let supports_single_thread_execution_requests =
|
||||
self.capabilities.supports_single_thread_execution_requests;
|
||||
let supports_stepping_granularity = self
|
||||
.capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = StepBackCommand {
|
||||
inner: StepCommand {
|
||||
thread_id: thread_id.0,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests,
|
||||
},
|
||||
};
|
||||
|
||||
self.request(command, Self::empty_response, cx).detach();
|
||||
}
|
||||
|
||||
pub fn handle_loaded_source_event(
|
||||
&mut self,
|
||||
event: &dap::LoadedSourceEvent,
|
||||
@@ -241,12 +697,205 @@ impl DebugAdapterClientState {
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn stack_frames(&mut self, thread_id: ThreadId, cx: &mut Context<Self>) -> Vec<StackFrame> {
|
||||
self.fetch(
|
||||
super::dap_command::StackTraceCommand {
|
||||
thread_id: thread_id.0,
|
||||
start_frame: None,
|
||||
levels: None,
|
||||
},
|
||||
move |this, stack_frames, cx| {
|
||||
let entry = this.threads.entry(thread_id).and_modify(|thread| {
|
||||
thread.stack_frames = stack_frames.iter().cloned().map(From::from).collect();
|
||||
});
|
||||
debug_assert!(
|
||||
matches!(entry, indexmap::map::Entry::Occupied(_)),
|
||||
"Sent request for thread_id that doesn't exist"
|
||||
);
|
||||
|
||||
cx.notify();
|
||||
},
|
||||
cx,
|
||||
);
|
||||
|
||||
self.threads
|
||||
.get(&thread_id)
|
||||
.map(|thread| thread.stack_frames.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn scopes(
|
||||
&mut self,
|
||||
thread_id: ThreadId,
|
||||
stack_frame_id: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Vec<Scope> {
|
||||
self.fetch(
|
||||
ScopesCommand {
|
||||
thread_id: thread_id.0,
|
||||
stack_frame_id,
|
||||
},
|
||||
move |this, scopes, cx| {
|
||||
this.threads.entry(thread_id).and_modify(|thread| {
|
||||
if let Some(stack_frame) = thread
|
||||
.stack_frames
|
||||
.iter_mut()
|
||||
.find(|frame| frame.dap.id == stack_frame_id)
|
||||
{
|
||||
stack_frame.scopes = scopes.iter().cloned().map(From::from).collect();
|
||||
cx.notify();
|
||||
}
|
||||
});
|
||||
},
|
||||
cx,
|
||||
);
|
||||
self.threads
|
||||
.get(&thread_id)
|
||||
.and_then(|thread| {
|
||||
thread.stack_frames.iter().find_map(|stack_frame| {
|
||||
(stack_frame.dap.id == stack_frame_id).then(|| stack_frame.scopes.clone())
|
||||
})
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn find_scope(
|
||||
&mut self,
|
||||
thread_id: ThreadId,
|
||||
stack_frame_id: u64,
|
||||
variables_reference: u64,
|
||||
) -> Option<&mut Scope> {
|
||||
self.threads.get_mut(&thread_id).and_then(|thread| {
|
||||
let stack_frame = thread
|
||||
.stack_frames
|
||||
.iter_mut()
|
||||
.find(|stack_frame| (stack_frame.dap.id == stack_frame_id))?;
|
||||
stack_frame
|
||||
.scopes
|
||||
.iter_mut()
|
||||
.find(|scope| scope.dap.variables_reference == variables_reference)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn variables(
|
||||
&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,
|
||||
start: None,
|
||||
count: None,
|
||||
format: None,
|
||||
};
|
||||
|
||||
self.fetch(
|
||||
command,
|
||||
move |this, variables, cx| {
|
||||
if let Some(scope) = this.find_scope(thread_id, stack_frame_id, variables_reference)
|
||||
{
|
||||
// This is only valid if scope.variable[x].ref_id == variables_reference
|
||||
// otherwise we have to search the tree for the right index to add variables too
|
||||
// todo(debugger): Fix this ^
|
||||
scope.variables = variables.iter().cloned().map(From::from).collect();
|
||||
cx.notify();
|
||||
}
|
||||
},
|
||||
cx,
|
||||
);
|
||||
|
||||
self.find_scope(thread_id, stack_frame_id, variables_reference)
|
||||
.map(|scope| scope.variables.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn set_variable_value(
|
||||
&mut self,
|
||||
variables_reference: u64,
|
||||
name: String,
|
||||
value: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.capabilities.supports_set_variable.unwrap_or_default() {
|
||||
self.request(
|
||||
SetVariableValueCommand {
|
||||
name,
|
||||
value,
|
||||
variables_reference,
|
||||
},
|
||||
|this, _response, cx| {
|
||||
this.invalidate(cx);
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.detach()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evaluate(
|
||||
&mut self,
|
||||
expression: String,
|
||||
context: Option<EvaluateArgumentsContext>,
|
||||
frame_id: Option<u64>,
|
||||
source: Option<Source>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.request(
|
||||
EvaluateCommand {
|
||||
expression,
|
||||
context,
|
||||
frame_id,
|
||||
source,
|
||||
},
|
||||
|this, _response, cx| {
|
||||
this.invalidate(cx);
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.detach()
|
||||
}
|
||||
|
||||
pub fn disconnect_client(&mut self, cx: &mut Context<Self>) {
|
||||
let command = DisconnectCommand {
|
||||
restart: Some(false),
|
||||
terminate_debuggee: Some(true),
|
||||
suspend_debuggee: Some(false),
|
||||
};
|
||||
|
||||
self.request(command, Self::empty_response, cx).detach()
|
||||
}
|
||||
|
||||
pub fn terminate_threads(&mut self, thread_ids: Option<Vec<ThreadId>>, cx: &mut Context<Self>) {
|
||||
if self
|
||||
.capabilities
|
||||
.supports_terminate_threads_request
|
||||
.unwrap_or_default()
|
||||
{
|
||||
self.request(
|
||||
TerminateThreadsCommand {
|
||||
thread_ids: thread_ids.map(|ids| ids.into_iter().map(|id| id.0).collect()),
|
||||
},
|
||||
Self::empty_response,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugSession {
|
||||
id: DebugSessionId,
|
||||
mode: DebugSessionMode,
|
||||
pub(super) states: HashMap<DebugAdapterClientId, Entity<DebugAdapterClientState>>,
|
||||
pub(super) states: BTreeMap<DebugAdapterClientId, Entity<Client>>,
|
||||
ignore_breakpoints: bool,
|
||||
}
|
||||
|
||||
@@ -257,7 +906,6 @@ pub enum DebugSessionMode {
|
||||
|
||||
pub struct LocalDebugSession {
|
||||
configuration: DebugAdapterConfig,
|
||||
clients: HashMap<DebugAdapterClientId, Arc<DebugAdapterClient>>,
|
||||
}
|
||||
|
||||
impl LocalDebugSession {
|
||||
@@ -273,42 +921,6 @@ impl LocalDebugSession {
|
||||
f(&mut self.configuration);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn add_client(&mut self, client: Arc<DebugAdapterClient>, cx: &mut Context<DebugSession>) {
|
||||
self.clients.insert(client.id(), client);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn remove_client(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
cx: &mut Context<DebugSession>,
|
||||
) -> Option<Arc<DebugAdapterClient>> {
|
||||
let client = self.clients.remove(client_id);
|
||||
cx.notify();
|
||||
|
||||
client
|
||||
}
|
||||
|
||||
pub fn client_by_id(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
) -> Option<Arc<DebugAdapterClient>> {
|
||||
self.clients.get(client_id).cloned()
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn clients_len(&self) -> usize {
|
||||
self.clients.len()
|
||||
}
|
||||
|
||||
pub fn clients(&self) -> impl Iterator<Item = Arc<DebugAdapterClient>> + '_ {
|
||||
self.clients.values().cloned()
|
||||
}
|
||||
|
||||
pub fn client_ids(&self) -> impl Iterator<Item = DebugAdapterClientId> + '_ {
|
||||
self.clients.keys().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RemoteDebugSession {
|
||||
@@ -320,11 +932,8 @@ impl DebugSession {
|
||||
Self {
|
||||
id,
|
||||
ignore_breakpoints: false,
|
||||
states: HashMap::default(),
|
||||
mode: DebugSessionMode::Local(LocalDebugSession {
|
||||
configuration,
|
||||
clients: HashMap::default(),
|
||||
}),
|
||||
states: BTreeMap::default(),
|
||||
mode: DebugSessionMode::Local(LocalDebugSession { configuration }),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +955,7 @@ impl DebugSession {
|
||||
Self {
|
||||
id,
|
||||
ignore_breakpoints,
|
||||
states: HashMap::default(),
|
||||
states: BTreeMap::default(),
|
||||
mode: DebugSessionMode::Remote(RemoteDebugSession { label }),
|
||||
}
|
||||
}
|
||||
@@ -371,38 +980,64 @@ impl DebugSession {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn client_state(
|
||||
&self,
|
||||
client_id: DebugAdapterClientId,
|
||||
) -> Option<Entity<DebugAdapterClientState>> {
|
||||
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: Option<Arc<DebugAdapterClient>>,
|
||||
client: impl Into<Mode>,
|
||||
client_id: DebugAdapterClientId,
|
||||
weak_dap: WeakEntity<DapStore>,
|
||||
cx: &mut Context<DebugSession>,
|
||||
) {
|
||||
if !self.states.contains_key(&client_id) {
|
||||
let state = cx.new(|_cx| DebugAdapterClientState {
|
||||
dap_store: weak_dap,
|
||||
let mode = client.into();
|
||||
let state = cx.new(|_cx| Client {
|
||||
client_id,
|
||||
modules: Vec::default(),
|
||||
loaded_sources: Vec::default(),
|
||||
_threads: BTreeMap::default(),
|
||||
threads: IndexMap::default(),
|
||||
requests: HashMap::default(),
|
||||
capabilities: Default::default(),
|
||||
mode,
|
||||
});
|
||||
|
||||
self.states.insert(client_id, state);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(client) = client {
|
||||
self.as_local_mut()
|
||||
.expect("Client can only exist on local Zed instances")
|
||||
.add_client(client, cx);
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,30 @@
|
||||
use super::{
|
||||
dap_command::{
|
||||
ContinueCommand, DapCommand, DisconnectCommand, NextCommand, PauseCommand, RestartCommand,
|
||||
RestartStackFrameCommand, StepBackCommand, StepCommand, StepInCommand, StepOutCommand,
|
||||
TerminateCommand, TerminateThreadsCommand, VariablesCommand,
|
||||
},
|
||||
dap_session::{DebugSession, DebugSessionId},
|
||||
// Will need to uncomment this once we implement rpc message handler again
|
||||
// dap_command::{
|
||||
// ContinueCommand, DapCommand, DisconnectCommand, NextCommand, PauseCommand, RestartCommand,
|
||||
// RestartStackFrameCommand, StepBackCommand, StepCommand, StepInCommand, StepOutCommand,
|
||||
// TerminateCommand, TerminateThreadsCommand, VariablesCommand,
|
||||
// },
|
||||
dap_command::DapCommand,
|
||||
dap_session::{self, DebugSession, DebugSessionId},
|
||||
};
|
||||
use crate::{project_settings::ProjectSettings, ProjectEnvironment, ProjectItem as _, ProjectPath};
|
||||
use anyhow::{anyhow, bail, Context as _, Result};
|
||||
use async_trait::async_trait;
|
||||
use collections::HashMap;
|
||||
use dap::ContinueResponse;
|
||||
use dap::{
|
||||
adapters::{DapDelegate, DapStatus, DebugAdapter, DebugAdapterBinary, DebugAdapterName},
|
||||
client::{DebugAdapterClient, DebugAdapterClientId},
|
||||
messages::{Message, Response},
|
||||
requests::{
|
||||
Attach, Completions, ConfigurationDone, Disconnect, Evaluate, Initialize, Launch,
|
||||
LoadedSources, Modules, Request as _, RunInTerminal, Scopes, SetBreakpoints, SetExpression,
|
||||
SetVariable, StackTrace, StartDebugging, Terminate,
|
||||
Attach, Completions, Evaluate, Initialize, Launch, Request as _, RunInTerminal,
|
||||
SetBreakpoints, SetExpression, SetVariable, StartDebugging,
|
||||
},
|
||||
AttachRequestArguments, Capabilities, CompletionItem, CompletionsArguments,
|
||||
ConfigurationDoneArguments, ContinueArguments, DisconnectArguments, ErrorResponse,
|
||||
AttachRequestArguments, Capabilities, CompletionItem, CompletionsArguments, ErrorResponse,
|
||||
EvaluateArguments, EvaluateArgumentsContext, EvaluateResponse, InitializeRequestArguments,
|
||||
InitializeRequestArgumentsPathFormat, LaunchRequestArguments, LoadedSourcesArguments, Module,
|
||||
ModulesArguments, Scope, ScopesArguments, SetBreakpointsArguments, SetExpressionArguments,
|
||||
SetVariableArguments, Source, SourceBreakpoint, StackFrame, StackTraceArguments,
|
||||
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest, SteppingGranularity,
|
||||
TerminateArguments, Variable,
|
||||
InitializeRequestArgumentsPathFormat, LaunchRequestArguments, SetBreakpointsArguments,
|
||||
SetExpressionArguments, SetVariableArguments, Source, SourceBreakpoint,
|
||||
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
|
||||
};
|
||||
use dap_adapters::build_adapter;
|
||||
use fs::Fs;
|
||||
@@ -47,8 +44,8 @@ use rpc::{
|
||||
use serde_json::Value;
|
||||
use settings::{Settings as _, WorktreeId};
|
||||
use smol::lock::Mutex;
|
||||
use std::collections::VecDeque;
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
collections::{BTreeMap, HashSet},
|
||||
ffi::OsStr,
|
||||
hash::{Hash, Hasher},
|
||||
@@ -58,6 +55,7 @@ use std::{
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
use std::{collections::VecDeque, sync::atomic::AtomicU32};
|
||||
use task::{AttachConfig, DebugAdapterConfig, DebugRequestType};
|
||||
use text::Point;
|
||||
use util::{merge_json_value_into, ResultExt as _};
|
||||
@@ -92,7 +90,7 @@ pub enum DapStoreMode {
|
||||
pub struct LocalDapStore {
|
||||
fs: Arc<dyn Fs>,
|
||||
node_runtime: NodeRuntime,
|
||||
next_client_id: AtomicUsize,
|
||||
next_client_id: AtomicU32,
|
||||
next_session_id: AtomicUsize,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
environment: Entity<ProjectEnvironment>,
|
||||
@@ -142,18 +140,19 @@ impl DapStore {
|
||||
client.add_entity_message_handler(Self::handle_ignore_breakpoint_state);
|
||||
client.add_entity_message_handler(Self::handle_session_has_shutdown);
|
||||
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<NextCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<StepInCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<StepOutCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<StepBackCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<ContinueCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<PauseCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<DisconnectCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<TerminateThreadsCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<TerminateCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<RestartCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<VariablesCommand>);
|
||||
client.add_entity_request_handler(Self::handle_dap_command::<RestartStackFrameCommand>);
|
||||
// todo(debugger): Reenable these after we finish handle_dap_command refactor
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<NextCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<StepInCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<StepOutCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<StepBackCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<ContinueCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<PauseCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<DisconnectCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<TerminateThreadsCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<TerminateCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<RestartCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<VariablesCommand>);
|
||||
// client.add_entity_request_handler(Self::handle_dap_command::<RestartStackFrameCommand>);
|
||||
client.add_entity_request_handler(Self::handle_shutdown_session_request);
|
||||
}
|
||||
|
||||
@@ -293,29 +292,32 @@ impl DapStore {
|
||||
|
||||
pub fn session_by_client_id(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: impl Borrow<DebugAdapterClientId>,
|
||||
) -> Option<Entity<DebugSession>> {
|
||||
self.sessions
|
||||
.get(self.client_by_session.get(client_id)?)
|
||||
.get(self.client_by_session.get(client_id.borrow())?)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn client_by_id(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: impl Borrow<DebugAdapterClientId>,
|
||||
cx: &Context<Self>,
|
||||
) -> Option<(Entity<DebugSession>, Arc<DebugAdapterClient>)> {
|
||||
let local_session = self.session_by_client_id(client_id)?;
|
||||
let client = local_session.read(cx).as_local()?.client_by_id(client_id)?;
|
||||
) -> Option<(Entity<DebugSession>, Entity<dap_session::Client>)> {
|
||||
let client_id = client_id.borrow();
|
||||
let session = self.session_by_client_id(client_id)?;
|
||||
|
||||
Some((local_session, client))
|
||||
let client = session.read(cx).client_by_id(*client_id)?;
|
||||
|
||||
Some((session, client))
|
||||
}
|
||||
|
||||
pub fn capabilities_by_id(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: impl Borrow<DebugAdapterClientId>,
|
||||
cx: &App,
|
||||
) -> Option<Capabilities> {
|
||||
let client_id = client_id.borrow();
|
||||
self.session_by_client_id(client_id).and_then(|session| {
|
||||
session
|
||||
.read(cx)
|
||||
@@ -327,13 +329,13 @@ impl DapStore {
|
||||
pub fn update_capabilities_for_client(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
capabilities: &Capabilities,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some((client, _)) = self.client_by_id(client_id, cx) {
|
||||
client.update(cx, |this, cx| {
|
||||
if let Some(state) = this.client_state(*client_id) {
|
||||
if let Some(state) = this.client_state(client_id) {
|
||||
state.update(cx, |this, _| {
|
||||
this.capabilities = this.capabilities.merge(capabilities.clone());
|
||||
});
|
||||
@@ -584,10 +586,9 @@ impl DapStore {
|
||||
store.client_by_session.insert(client_id, session_id);
|
||||
|
||||
let session = store.session_by_id(&session_id).unwrap();
|
||||
let weak_dap = cx.weak_entity();
|
||||
|
||||
session.update(cx, |session, cx| {
|
||||
session.add_client(Some(Arc::new(client)), client_id, weak_dap, cx);
|
||||
session.add_client(Arc::new(client), client_id, cx);
|
||||
let local_session = session
|
||||
.as_local_mut()
|
||||
.expect("Only local sessions should attempt to reconnect");
|
||||
@@ -735,10 +736,8 @@ impl DapStore {
|
||||
};
|
||||
|
||||
this.update(&mut cx, |store, cx| {
|
||||
let weak_dap = cx.weak_entity();
|
||||
|
||||
session.update(cx, |session, cx| {
|
||||
session.add_client(Some(client.clone()), client.id(), weak_dap, cx);
|
||||
session.add_client(client.clone(), client.id(), cx);
|
||||
});
|
||||
|
||||
let client_id = client.id();
|
||||
@@ -757,10 +756,13 @@ impl DapStore {
|
||||
pub fn initialize(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some(client) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Could not find debug client: {:?} for session {:?}",
|
||||
client_id,
|
||||
@@ -769,7 +771,6 @@ impl DapStore {
|
||||
};
|
||||
|
||||
let session_id = *session_id;
|
||||
let client_id = *client_id;
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let capabilities = client
|
||||
@@ -794,18 +795,49 @@ impl DapStore {
|
||||
.await?;
|
||||
|
||||
this.update(&mut cx, |store, cx| {
|
||||
store.update_capabilities_for_client(&session_id, &client_id, &capabilities, cx);
|
||||
store.update_capabilities_for_client(&session_id, client_id, &capabilities, cx);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn configuration_done(
|
||||
&self,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(client) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
|
||||
if self
|
||||
.capabilities_by_id(client_id, cx)
|
||||
.map(|caps| caps.supports_configuration_done_request)
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
cx.background_executor().spawn(async move {
|
||||
client
|
||||
.request::<dap::requests::ConfigurationDone>(dap::ConfigurationDoneArguments)
|
||||
.await
|
||||
})
|
||||
} else {
|
||||
Task::ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn launch(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((session, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some((session, client)) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(session, client)| Some((session, client.read(cx).adapter_client()?)))
|
||||
else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Could not find debug client: {:?} for session {:?}",
|
||||
client_id,
|
||||
@@ -844,11 +876,14 @@ impl DapStore {
|
||||
pub fn attach(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
process_id: u32,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((session, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some((session, client)) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(session, client)| Some((session, client.read(cx).adapter_client()?)))
|
||||
else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Could not find debug client: {:?} for session {:?}",
|
||||
client_id,
|
||||
@@ -884,156 +919,18 @@ impl DapStore {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modules(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<Module>>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Client was not found")));
|
||||
};
|
||||
|
||||
if !self
|
||||
.capabilities_by_id(client_id, cx)
|
||||
.map(|caps| caps.supports_modules_request)
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Task::ready(Ok(Vec::default()));
|
||||
}
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
Ok(client
|
||||
.request::<Modules>(ModulesArguments {
|
||||
start_module: None,
|
||||
module_count: None,
|
||||
})
|
||||
.await?
|
||||
.modules)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn loaded_sources(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<Source>>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Client was not found")));
|
||||
};
|
||||
|
||||
if !self
|
||||
.capabilities_by_id(client_id, cx)
|
||||
.map(|caps| caps.supports_loaded_sources_request)
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Task::ready(Ok(Vec::default()));
|
||||
}
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
Ok(client
|
||||
.request::<LoadedSources>(LoadedSourcesArguments {})
|
||||
.await?
|
||||
.sources)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stack_frames(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<StackFrame>>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Client was not found")));
|
||||
};
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
Ok(client
|
||||
.request::<StackTrace>(StackTraceArguments {
|
||||
thread_id,
|
||||
start_frame: None,
|
||||
levels: None,
|
||||
format: None,
|
||||
})
|
||||
.await?
|
||||
.stack_frames)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn restart_stack_frame(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
stack_frame_id: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
if !self
|
||||
.capabilities_by_id(client_id, cx)
|
||||
.map(|caps| caps.supports_restart_frame)
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Task::ready(Ok(()));
|
||||
}
|
||||
|
||||
self.request_dap(client_id, RestartStackFrameCommand { stack_frame_id }, cx)
|
||||
}
|
||||
|
||||
pub fn scopes(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
stack_frame_id: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<Scope>>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Client was not found")));
|
||||
};
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
Ok(client
|
||||
.request::<Scopes>(ScopesArguments {
|
||||
frame_id: stack_frame_id,
|
||||
})
|
||||
.await?
|
||||
.scopes)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn configuration_done(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
|
||||
if self
|
||||
.capabilities_by_id(client_id, cx)
|
||||
.map(|caps| caps.supports_configuration_done_request)
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
cx.background_executor().spawn(async move {
|
||||
client
|
||||
.request::<ConfigurationDone>(ConfigurationDoneArguments)
|
||||
.await
|
||||
})
|
||||
} else {
|
||||
Task::ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn respond_to_start_debugging(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
seq: u64,
|
||||
args: Option<StartDebuggingRequestArguments>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((session, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some((session, client)) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(session, client)| Some((session, client.read(cx).adapter_client()?)))
|
||||
else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Could not find debug client: {:?} for session {:?}",
|
||||
client_id,
|
||||
@@ -1158,13 +1055,16 @@ impl DapStore {
|
||||
pub fn respond_to_run_in_terminal(
|
||||
&self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
success: bool,
|
||||
seq: u64,
|
||||
body: Option<Value>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some(client) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Could not find debug client: {:?} for session {:?}",
|
||||
client_id,
|
||||
@@ -1185,231 +1085,6 @@ impl DapStore {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn continue_thread(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<ContinueResponse>> {
|
||||
let command = ContinueCommand {
|
||||
args: ContinueArguments {
|
||||
thread_id,
|
||||
single_thread: Some(true),
|
||||
},
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
}
|
||||
|
||||
pub(crate) fn request_dap<R: DapCommand>(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
request: R,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<R::Response>>
|
||||
where
|
||||
<R::DapRequest as dap::requests::Request>::Response: 'static,
|
||||
<R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
|
||||
{
|
||||
if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
|
||||
return self.send_proto_client_request::<R>(
|
||||
upstream_client,
|
||||
upstream_project_id,
|
||||
client_id,
|
||||
request,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
let Some((session, client)) = self.client_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
|
||||
let Some(caps) = session
|
||||
.read(cx)
|
||||
.client_state(*client_id)
|
||||
.map(|state| state.read(cx).capabilities.clone())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
if !request.is_supported(&caps) {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Request {} is not supported",
|
||||
R::DapRequest::COMMAND
|
||||
)));
|
||||
}
|
||||
|
||||
let client_id = *client_id;
|
||||
let request = Arc::new(request);
|
||||
|
||||
let request_clone = request.clone();
|
||||
let request_task = cx.background_executor().spawn(async move {
|
||||
let args = request_clone.to_dap();
|
||||
client.request::<R::DapRequest>(args).await
|
||||
});
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let response = request.response_from_dap(request_task.await?);
|
||||
request.handle_response(this, &client_id, response, &mut cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn send_proto_client_request<R: DapCommand>(
|
||||
&self,
|
||||
upstream_client: AnyProtoClient,
|
||||
upstream_project_id: u64,
|
||||
client_id: &DebugAdapterClientId,
|
||||
request: R,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<R::Response>> {
|
||||
let message = request.to_proto(&client_id, upstream_project_id);
|
||||
cx.background_executor().spawn(async move {
|
||||
let response = upstream_client.request(message).await?;
|
||||
request.response_from_proto(response)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn step_over(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(capabilities) = self.capabilities_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
let supports_single_thread_execution_requests = capabilities
|
||||
.supports_single_thread_execution_requests
|
||||
.unwrap_or_default();
|
||||
let supports_stepping_granularity = capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = NextCommand {
|
||||
inner: StepCommand {
|
||||
thread_id,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests.then(|| true),
|
||||
},
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
}
|
||||
|
||||
pub fn step_in(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(capabilities) = self.capabilities_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
let supports_single_thread_execution_requests = capabilities
|
||||
.supports_single_thread_execution_requests
|
||||
.unwrap_or_default();
|
||||
let supports_stepping_granularity = capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = StepInCommand {
|
||||
inner: StepCommand {
|
||||
thread_id,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests.then(|| true),
|
||||
},
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
}
|
||||
|
||||
pub fn step_out(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(capabilities) = self.capabilities_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
let supports_single_thread_execution_requests = capabilities
|
||||
.supports_single_thread_execution_requests
|
||||
.unwrap_or_default();
|
||||
let supports_stepping_granularity = capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = StepOutCommand {
|
||||
inner: StepCommand {
|
||||
thread_id,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests.then(|| true),
|
||||
},
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
}
|
||||
|
||||
pub fn step_back(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
granularity: SteppingGranularity,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(capabilities) = self.capabilities_by_id(client_id, cx) else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
if !capabilities.supports_step_back.unwrap_or_default() {
|
||||
return Task::ready(Ok(()));
|
||||
}
|
||||
|
||||
let supports_single_thread_execution_requests = capabilities
|
||||
.supports_single_thread_execution_requests
|
||||
.unwrap_or_default();
|
||||
let supports_stepping_granularity = capabilities
|
||||
.supports_stepping_granularity
|
||||
.unwrap_or_default();
|
||||
|
||||
let command = StepBackCommand {
|
||||
inner: StepCommand {
|
||||
thread_id,
|
||||
granularity: supports_stepping_granularity.then(|| granularity),
|
||||
single_thread: supports_single_thread_execution_requests.then(|| true),
|
||||
},
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn variables(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
stack_frame_id: u64,
|
||||
scope_id: u64,
|
||||
session_id: DebugSessionId,
|
||||
variables_reference: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<Variable>>> {
|
||||
let command = VariablesCommand {
|
||||
stack_frame_id,
|
||||
scope_id,
|
||||
session_id,
|
||||
thread_id,
|
||||
variables_reference,
|
||||
filter: None,
|
||||
start: None,
|
||||
count: None,
|
||||
format: None,
|
||||
};
|
||||
|
||||
self.request_dap(&client_id, command, cx)
|
||||
}
|
||||
|
||||
pub fn evaluate(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
@@ -1419,7 +1094,10 @@ impl DapStore {
|
||||
source: Option<Source>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<EvaluateResponse>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some(client) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
|
||||
@@ -1446,7 +1124,10 @@ impl DapStore {
|
||||
completion_column: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Vec<CompletionItem>>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some(client) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
|
||||
@@ -1474,7 +1155,10 @@ impl DapStore {
|
||||
evaluate_name: Option<String>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some(client) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
|
||||
@@ -1509,76 +1193,10 @@ impl DapStore {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pause_thread(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_id: u64,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
self.request_dap(client_id, PauseCommand { thread_id }, cx)
|
||||
}
|
||||
|
||||
pub fn terminate_threads(
|
||||
&mut self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
thread_ids: Option<Vec<u64>>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
if self
|
||||
.capabilities_by_id(client_id, cx)
|
||||
.map(|caps| caps.supports_terminate_threads_request)
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
self.request_dap(client_id, TerminateThreadsCommand { thread_ids }, cx)
|
||||
} else {
|
||||
self.shutdown_session(session_id, cx)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disconnect_client(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let command = DisconnectCommand {
|
||||
restart: Some(false),
|
||||
terminate_debuggee: Some(true),
|
||||
suspend_debuggee: Some(false),
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
}
|
||||
|
||||
pub fn restart(
|
||||
&mut self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
args: Option<Value>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let supports_restart = self
|
||||
.capabilities_by_id(client_id, cx)
|
||||
.map(|caps| caps.supports_restart_request)
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
|
||||
if supports_restart {
|
||||
let command = RestartCommand {
|
||||
raw: args.unwrap_or(Value::Null),
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
} else {
|
||||
let command = DisconnectCommand {
|
||||
restart: Some(false),
|
||||
terminate_debuggee: Some(true),
|
||||
suspend_debuggee: Some(false),
|
||||
};
|
||||
|
||||
self.request_dap(client_id, command, cx)
|
||||
}
|
||||
}
|
||||
// .. get the client and what not
|
||||
// let _ = client.modules(); // This can fire a request to a dap adapter or be a cheap getter.
|
||||
// client.wait_for_request(request::Modules); // This ensures that the request that we've fired off runs to completions
|
||||
// let returned_value = client.modules(); // this is a cheap getter.
|
||||
|
||||
pub fn shutdown_sessions(&mut self, cx: &mut Context<Self>) -> Task<()> {
|
||||
let Some(_) = self.as_local() else {
|
||||
@@ -1633,89 +1251,12 @@ impl DapStore {
|
||||
return Task::ready(Err(anyhow!("Could not find session: {:?}", session_id)));
|
||||
};
|
||||
|
||||
let Some(local_session) = session.read(cx).as_local() else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Cannot shutdown session on remote side: {:?}",
|
||||
session_id
|
||||
)));
|
||||
};
|
||||
|
||||
let mut tasks = Vec::new();
|
||||
for client in local_session.clients().collect::<Vec<_>>() {
|
||||
tasks.push(self.shutdown_client(&session, client, cx));
|
||||
}
|
||||
|
||||
if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
|
||||
downstream_client
|
||||
.send(proto::DebuggerSessionEnded {
|
||||
project_id: *project_id,
|
||||
session_id: session_id.to_proto(),
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
futures::future::join_all(tasks).await;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn shutdown_client(
|
||||
&mut self,
|
||||
session: &Entity<DebugSession>,
|
||||
client: Arc<DebugAdapterClient>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let client_id = client.id();
|
||||
|
||||
cx.emit(DapStoreEvent::DebugClientShutdown(client_id));
|
||||
let Some(capabilities) = self.session_by_client_id(&client_id).and_then(|session| {
|
||||
session
|
||||
.read(cx)
|
||||
.client_state(client_id)
|
||||
.map(|state| state.read(cx).capabilities.clone())
|
||||
}) else {
|
||||
return Task::ready(Err(anyhow!("Client not found")));
|
||||
};
|
||||
let session = session.clone();
|
||||
self.client_by_session.remove(&client_id);
|
||||
if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
|
||||
downstream_client
|
||||
.send(proto::ShutdownDebugClient {
|
||||
session_id: session.read(cx).id().to_proto(),
|
||||
client_id: client_id.to_proto(),
|
||||
project_id: *project_id,
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
if capabilities.supports_terminate_request.unwrap_or_default() {
|
||||
let _ = client
|
||||
.request::<Terminate>(TerminateArguments {
|
||||
restart: Some(false),
|
||||
})
|
||||
.await
|
||||
.log_err();
|
||||
} else {
|
||||
let _ = client
|
||||
.request::<Disconnect>(DisconnectArguments {
|
||||
restart: Some(false),
|
||||
terminate_debuggee: Some(true),
|
||||
suspend_debuggee: Some(false),
|
||||
})
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
|
||||
client.shutdown().await?;
|
||||
|
||||
let _ = session.update(&mut cx, |this, _| {
|
||||
this.states.remove(&client_id);
|
||||
for client_id in session.read(cx).client_ids().collect::<Vec<_>>() {
|
||||
session.update(cx, |this, cx| {
|
||||
this.shutdown_client(client_id, cx);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
Task::ready(Ok(()))
|
||||
}
|
||||
|
||||
pub fn request_active_debug_sessions(&mut self, cx: &mut Context<Self>) {
|
||||
@@ -1766,7 +1307,7 @@ impl DapStore {
|
||||
|
||||
self.update_capabilities_for_client(
|
||||
&session_id,
|
||||
&client,
|
||||
client,
|
||||
&dap::proto_conversions::capabilities_from_proto(
|
||||
&debug_client.capabilities.unwrap_or_default(),
|
||||
),
|
||||
@@ -1834,7 +1375,7 @@ impl DapStore {
|
||||
let client_id = T::client_id_from_proto(&envelope.payload);
|
||||
|
||||
let _state = this.update(&mut cx, |this, cx| {
|
||||
this.session_by_client_id(&client_id)?
|
||||
this.session_by_client_id(client_id)?
|
||||
.read(cx)
|
||||
.client_state(client_id)?
|
||||
.read(cx)
|
||||
@@ -1844,27 +1385,27 @@ impl DapStore {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn handle_dap_command<T: DapCommand>(
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<T::ProtoRequest>,
|
||||
mut cx: AsyncApp,
|
||||
) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
|
||||
where
|
||||
<T::DapRequest as dap::requests::Request>::Arguments: Send,
|
||||
<T::DapRequest as dap::requests::Request>::Response: Send,
|
||||
{
|
||||
let _sender_id = envelope.original_sender_id().unwrap_or_default();
|
||||
let client_id = T::client_id_from_proto(&envelope.payload);
|
||||
// async fn handle_dap_command<T: DapCommand>(
|
||||
// this: Entity<Self>,
|
||||
// envelope: TypedEnvelope<T::ProtoRequest>,
|
||||
// mut cx: AsyncApp,
|
||||
// ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
|
||||
// where
|
||||
// <T::DapRequest as dap::requests::Request>::Arguments: Send,
|
||||
// <T::DapRequest as dap::requests::Request>::Response: Send,
|
||||
// {
|
||||
// let _sender_id = envelope.original_sender_id().unwrap_or_default();
|
||||
// let client_id = T::client_id_from_proto(&envelope.payload);
|
||||
|
||||
let request = T::from_proto(&envelope.payload);
|
||||
let response = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.request_dap::<T>(&client_id, request, cx)
|
||||
})?
|
||||
.await?;
|
||||
// let request = T::from_proto(&envelope.payload);
|
||||
// let response = this
|
||||
// .update(&mut cx, |this, cx| {
|
||||
// this.request_dap::<T>(&client_id, request, cx)
|
||||
// })?
|
||||
// .await?;
|
||||
|
||||
Ok(T::response_to_proto(&client_id, response))
|
||||
}
|
||||
// Ok(T::response_to_proto(&client_id, response))
|
||||
// }
|
||||
|
||||
async fn handle_synchronize_breakpoints(
|
||||
this: Entity<Self>,
|
||||
@@ -1939,7 +1480,7 @@ impl DapStore {
|
||||
this.update(&mut cx, |dap_store, cx| {
|
||||
dap_store.update_capabilities_for_client(
|
||||
&DebugSessionId::from_proto(envelope.payload.session_id),
|
||||
&DebugAdapterClientId::from_proto(envelope.payload.client_id),
|
||||
DebugAdapterClientId::from_proto(envelope.payload.client_id),
|
||||
&dap::proto_conversions::capabilities_from_proto(&envelope.payload),
|
||||
cx,
|
||||
);
|
||||
@@ -1954,7 +1495,7 @@ impl DapStore {
|
||||
this.update(&mut cx, |dap_store, cx| {
|
||||
let client_id = DebugAdapterClientId::from_proto(envelope.payload.client_id);
|
||||
|
||||
dap_store.session_by_client_id(&client_id).map(|state| {
|
||||
dap_store.session_by_client_id(client_id).map(|state| {
|
||||
state.update(cx, |this, _| {
|
||||
this.states.remove(&client_id);
|
||||
})
|
||||
@@ -2056,14 +1597,17 @@ impl DapStore {
|
||||
|
||||
pub fn send_breakpoints(
|
||||
&self,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
absolute_file_path: Arc<Path>,
|
||||
mut breakpoints: Vec<SourceBreakpoint>,
|
||||
ignore: bool,
|
||||
source_changed: bool,
|
||||
cx: &Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some((_, client)) = self.client_by_id(client_id, cx) else {
|
||||
let Some(client) = self
|
||||
.client_by_id(client_id, cx)
|
||||
.and_then(|(_, client)| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id)));
|
||||
};
|
||||
|
||||
@@ -2121,9 +1665,9 @@ impl DapStore {
|
||||
{
|
||||
let session = session.read(cx);
|
||||
let ignore_breakpoints = session.ignore_breakpoints();
|
||||
for client in session.as_local().unwrap().clients().collect::<Vec<_>>() {
|
||||
for client_id in session.client_ids().collect::<Vec<_>>() {
|
||||
tasks.push(self.send_breakpoints(
|
||||
&client.id(),
|
||||
client_id,
|
||||
Arc::from(absolute_path.clone()),
|
||||
source_breakpoints.clone(),
|
||||
ignore_breakpoints,
|
||||
|
||||
@@ -1311,7 +1311,7 @@ impl Project {
|
||||
pub fn initial_send_breakpoints(
|
||||
&self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<()> {
|
||||
let mut tasks = Vec::new();
|
||||
@@ -1439,7 +1439,7 @@ impl Project {
|
||||
project
|
||||
.toggle_ignore_breakpoints(
|
||||
&DebugSessionId::from_proto(envelope.payload.session_id),
|
||||
&DebugAdapterClientId::from_proto(envelope.payload.client_id),
|
||||
DebugAdapterClientId::from_proto(envelope.payload.client_id),
|
||||
cx,
|
||||
)
|
||||
.detach_and_log_err(cx);
|
||||
@@ -1450,7 +1450,7 @@ impl Project {
|
||||
pub fn toggle_ignore_breakpoints(
|
||||
&self,
|
||||
session_id: &DebugSessionId,
|
||||
client_id: &DebugAdapterClientId,
|
||||
client_id: DebugAdapterClientId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let tasks = self.dap_store.update(cx, |store, cx| {
|
||||
|
||||
@@ -355,7 +355,19 @@ message Envelope {
|
||||
DapLoadedSourcesRequest dap_loaded_sources_request = 331;
|
||||
DapLoadedSourcesResponse dap_loaded_sources_response = 332;
|
||||
ActiveDebugSessionsRequest active_debug_sessions_request = 333;
|
||||
ActiveDebugSessionsResponse active_debug_sessions_response = 334; // current max
|
||||
ActiveDebugSessionsResponse active_debug_sessions_response = 334;
|
||||
DapStackTraceRequest dap_stack_trace_request = 335;
|
||||
DapStackTraceResponse dap_stack_trace_response = 336;
|
||||
DapScopesRequest dap_scopes_request = 337;
|
||||
DapScopesResponse dap_scopes_response = 338;
|
||||
DapSetVariableValueRequest dap_set_variable_value_request = 339;
|
||||
DapSetVariableValueResponse dap_set_variable_value_response = 340;
|
||||
DapEvaluateRequest dap_evaluate_request = 341;
|
||||
DapEvaluateResponse dap_evaluate_response = 342;
|
||||
DapCompletionRequest dap_completion_request = 343;
|
||||
DapCompletionResponse dap_completion_response = 344;
|
||||
DapThreadsRequest dap_threads_request = 345;
|
||||
DapThreadsResponse dap_threads_response = 346; // current max
|
||||
}
|
||||
|
||||
reserved 87 to 88;
|
||||
@@ -2708,7 +2720,6 @@ message VariableListVariables {
|
||||
message DebuggerVariableList {
|
||||
repeated VariableListScopes scopes = 1;
|
||||
repeated VariableListVariables variables = 2;
|
||||
repeated AddToVariableList added_variables = 3;
|
||||
}
|
||||
|
||||
enum VariablesArgumentsFilter {
|
||||
@@ -2726,20 +2737,13 @@ message VariablesRequest {
|
||||
uint64 thread_id = 3;
|
||||
uint64 session_id = 4;
|
||||
uint64 stack_frame_id = 5;
|
||||
uint64 scope_id = 6;
|
||||
uint64 variables_reference = 7;
|
||||
optional VariablesArgumentsFilter filter = 8;
|
||||
optional uint64 start = 9;
|
||||
optional uint64 count = 10;
|
||||
optional ValueFormat format = 11;
|
||||
uint64 variables_reference = 6;
|
||||
optional VariablesArgumentsFilter filter = 7;
|
||||
optional uint64 start = 8;
|
||||
optional uint64 count = 9;
|
||||
optional ValueFormat format = 10;
|
||||
}
|
||||
|
||||
message AddToVariableList {
|
||||
uint64 variable_id = 1;
|
||||
uint64 stack_frame_id = 2;
|
||||
uint64 scope_id = 3;
|
||||
repeated DapVariable variables = 4;
|
||||
}
|
||||
|
||||
message DebuggerStackFrameList {
|
||||
uint64 thread_id = 1;
|
||||
@@ -2754,6 +2758,110 @@ enum SteppingGranularity {
|
||||
Instruction = 2;
|
||||
}
|
||||
|
||||
enum DapEvaluateContext {
|
||||
Repl = 0;
|
||||
Watch = 1;
|
||||
Hover = 2;
|
||||
Clipboard = 3;
|
||||
EvaluateVariables = 4;
|
||||
EvaluateUnknown = 5;
|
||||
}
|
||||
|
||||
message DapEvaluateRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
string expression = 3;
|
||||
optional uint64 frame_id = 4;
|
||||
optional DapEvaluateContext context = 5;
|
||||
}
|
||||
|
||||
message DapEvaluateResponse {
|
||||
string result = 1;
|
||||
optional string evaluate_type = 2;
|
||||
uint64 variable_reference = 3;
|
||||
optional uint64 named_variables = 4;
|
||||
optional uint64 indexed_variables = 5;
|
||||
optional string memory_reference = 6;
|
||||
}
|
||||
|
||||
|
||||
message DapCompletionRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
string query = 3;
|
||||
optional uint64 frame_id = 4;
|
||||
optional uint64 line = 5;
|
||||
uint64 column = 6;
|
||||
}
|
||||
|
||||
enum DapCompletionItemType {
|
||||
Method = 0;
|
||||
Function = 1;
|
||||
Constructor = 2;
|
||||
Field = 3;
|
||||
Variable = 4;
|
||||
Class = 5;
|
||||
Interface = 6;
|
||||
Module = 7;
|
||||
Property = 8;
|
||||
Unit = 9;
|
||||
Value = 10;
|
||||
Enum = 11;
|
||||
Keyword = 12;
|
||||
Snippet = 13;
|
||||
Text = 14;
|
||||
Color = 15;
|
||||
CompletionItemFile = 16;
|
||||
Reference = 17;
|
||||
Customcolor = 19;
|
||||
}
|
||||
|
||||
message DapCompletionItem {
|
||||
string label = 1;
|
||||
optional string text = 2;
|
||||
optional string sort_text = 3;
|
||||
optional string detail = 4;
|
||||
optional DapCompletionItemType typ = 5;
|
||||
optional uint64 start = 6;
|
||||
optional uint64 length = 7;
|
||||
optional uint64 selection_start = 8;
|
||||
optional uint64 selection_length = 9;
|
||||
}
|
||||
|
||||
message DapCompletionResponse {
|
||||
uint64 client_id = 1;
|
||||
repeated DapCompletionItem completions = 2;
|
||||
}
|
||||
|
||||
message DapScopesRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
uint64 thread_id = 3;
|
||||
uint64 stack_frame_id = 4;
|
||||
}
|
||||
|
||||
message DapScopesResponse {
|
||||
repeated DapScope scopes = 1;
|
||||
}
|
||||
|
||||
message DapSetVariableValueRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
string name = 3;
|
||||
string value = 4;
|
||||
uint64 variables_reference = 5;
|
||||
}
|
||||
|
||||
message DapSetVariableValueResponse {
|
||||
uint64 client_id = 1;
|
||||
string value = 2;
|
||||
optional string variable_type = 3;
|
||||
optional uint64 variables_reference = 4;
|
||||
optional uint64 named_variables = 5;
|
||||
optional uint64 indexed_variables = 6;
|
||||
optional string memory_reference = 7;
|
||||
}
|
||||
|
||||
message DapPauseRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
@@ -2774,6 +2882,15 @@ message DapTerminateThreadsRequest {
|
||||
repeated uint64 thread_ids = 3;
|
||||
}
|
||||
|
||||
message DapThreadsRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
}
|
||||
|
||||
message DapThreadsResponse {
|
||||
repeated DapThread threads = 1;
|
||||
}
|
||||
|
||||
message DapTerminateRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
@@ -2874,6 +2991,18 @@ message DapLoadedSourcesResponse {
|
||||
repeated DapSource sources = 2;
|
||||
}
|
||||
|
||||
message DapStackTraceRequest {
|
||||
uint64 project_id = 1;
|
||||
uint64 client_id = 2;
|
||||
uint64 thread_id = 3;
|
||||
optional uint64 start_frame = 4;
|
||||
optional uint64 stack_trace_levels = 5;
|
||||
}
|
||||
|
||||
message DapStackTraceResponse {
|
||||
repeated DapStackFrame frames = 1;
|
||||
}
|
||||
|
||||
message DapStackFrame {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
@@ -2926,9 +3055,8 @@ message UpdateDebugAdapter {
|
||||
DebuggerThreadState thread_state = 5;
|
||||
DebuggerStackFrameList stack_frame_list = 6;
|
||||
DebuggerVariableList variable_list = 7;
|
||||
AddToVariableList add_to_variable_list = 8;
|
||||
DebuggerModuleList modules = 9;
|
||||
DapOutputEvent output_event = 10;
|
||||
DebuggerModuleList modules = 8;
|
||||
DapOutputEvent output_event = 9;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2952,6 +3080,11 @@ message DapVariable {
|
||||
optional string memory_reference = 9;
|
||||
}
|
||||
|
||||
message DapThread {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message DapScope {
|
||||
string name = 1;
|
||||
optional DapScopePresentationHint presentation_hint = 2;
|
||||
|
||||
@@ -476,6 +476,18 @@ messages!(
|
||||
(DebuggerSessionEnded, Background),
|
||||
(ActiveDebugSessionsRequest, Foreground),
|
||||
(ActiveDebugSessionsResponse, Foreground),
|
||||
(DapStackTraceRequest, Background),
|
||||
(DapStackTraceResponse, Background),
|
||||
(DapScopesRequest, Background),
|
||||
(DapScopesResponse, Background),
|
||||
(DapSetVariableValueRequest, Background),
|
||||
(DapSetVariableValueResponse, Background),
|
||||
(DapEvaluateRequest, Background),
|
||||
(DapEvaluateResponse, Background),
|
||||
(DapCompletionRequest, Background),
|
||||
(DapCompletionResponse, Background),
|
||||
(DapThreadsRequest, Background),
|
||||
(DapThreadsResponse, Background),
|
||||
);
|
||||
|
||||
request_messages!(
|
||||
@@ -627,7 +639,13 @@ request_messages!(
|
||||
(DapRestartStackFrameRequest, Ack),
|
||||
(DapShutdownSession, Ack),
|
||||
(VariablesRequest, DapVariables),
|
||||
(ActiveDebugSessionsRequest, ActiveDebugSessionsResponse)
|
||||
(ActiveDebugSessionsRequest, ActiveDebugSessionsResponse),
|
||||
(DapStackTraceRequest, DapStackTraceResponse),
|
||||
(DapScopesRequest, DapScopesResponse),
|
||||
(DapSetVariableValueRequest, DapSetVariableValueResponse),
|
||||
(DapEvaluateRequest, DapEvaluateResponse),
|
||||
(DapCompletionRequest, DapCompletionResponse),
|
||||
(DapThreadsRequest, DapThreadsResponse),
|
||||
);
|
||||
|
||||
entity_messages!(
|
||||
@@ -748,6 +766,12 @@ entity_messages!(
|
||||
ToggleIgnoreBreakpoints,
|
||||
DebuggerSessionEnded,
|
||||
ActiveDebugSessionsRequest,
|
||||
DapStackTraceRequest,
|
||||
DapScopesRequest,
|
||||
DapSetVariableValueRequest,
|
||||
DapEvaluateRequest,
|
||||
DapCompletionRequest,
|
||||
DapThreadsRequest,
|
||||
);
|
||||
|
||||
entity_messages!(
|
||||
|
||||
@@ -9,7 +9,7 @@ use language::{proto::serialize_operation, Buffer, BufferEvent, LanguageRegistry
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::{
|
||||
buffer_store::{BufferStore, BufferStoreEvent},
|
||||
dap_store::DapStore,
|
||||
debugger::dap_store::DapStore,
|
||||
git::GitStore,
|
||||
project_settings::SettingsObserver,
|
||||
search::SearchQuery,
|
||||
|
||||
@@ -4208,7 +4208,7 @@ mod tests {
|
||||
repl::init(app_state.fs.clone(), cx);
|
||||
repl::notebook::init(cx);
|
||||
tasks_ui::init(cx);
|
||||
project::dap_store::DapStore::init(&app_state.client.clone().into());
|
||||
project::debugger::dap_store::DapStore::init(&app_state.client.clone().into());
|
||||
debugger_ui::init(cx);
|
||||
initialize_workspace(app_state.clone(), prompt_builder, cx);
|
||||
search::init(cx);
|
||||
|
||||
Reference in New Issue
Block a user