Skip to content

Commit

Permalink
WIP start fetching variables recursively
Browse files Browse the repository at this point in the history
  • Loading branch information
RemcoSmitsDev committed Aug 7, 2024
1 parent 57542bc commit f4cf31f
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 85 deletions.
13 changes: 11 additions & 2 deletions crates/dap/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ use std::{
use task::{DebugAdapterConfig, DebugConnectionType, DebugRequestType, TCPHost};
use text::Point;

#[derive(Debug, Clone)]
pub enum ThreadEntry {
Scope(Scope),
Variable {
depth: usize,
variable: Variable,
has_children: bool,
},
}

#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ThreadStatus {
#[default]
Expand All @@ -55,8 +65,7 @@ pub struct DebugAdapterClientId(pub usize);
pub struct ThreadState {
pub status: ThreadStatus,
pub stack_frames: Vec<StackFrame>,
pub scopes: HashMap<u64, Vec<Scope>>, // stack_frame_id -> scopes
pub variables: HashMap<u64, Vec<Variable>>, // scope.variable_reference -> variables
pub stack_frame_entries: HashMap<u64, Vec<ThreadEntry>>, // stack_frame_id -> ThreadEntry(scope & variables)
pub current_stack_frame_id: Option<u64>,
}

Expand Down
85 changes: 55 additions & 30 deletions crates/debugger_ui/src/debugger_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use anyhow::Result;
use dap::client::{DebugAdapterClientId, ThreadState, ThreadStatus};
use dap::requests::{Disconnect, Request, Scopes, StackTrace, StartDebugging, Variables};
use dap::transport::Payload;
use dap::{client::DebugAdapterClient, transport::Events};
use dap::{client::DebugAdapterClient, client::ThreadEntry, transport::Events};
use dap::{
Capabilities, ContinuedEvent, DisconnectArguments, ExitedEvent, OutputEvent, Scope,
ScopesArguments, StackFrame, StackTraceArguments, StartDebuggingRequestArguments, StoppedEvent,
TerminatedEvent, ThreadEvent, ThreadEventReason, Variable, VariablesArguments,
Capabilities, ContinuedEvent, DisconnectArguments, ExitedEvent, OutputEvent, ScopesArguments,
StackFrame, StackTraceArguments, StartDebuggingRequestArguments, StoppedEvent, TerminatedEvent,
ThreadEvent, ThreadEventReason, VariablesArguments,
};
use editor::Editor;
use futures::future::try_join_all;
Expand Down Expand Up @@ -389,6 +389,45 @@ impl DebugPanel {
cx.notify();
}

async fn fetch_variables(
client: Arc<DebugAdapterClient>,
variables_reference: u64,
depth: usize,
) -> Result<Vec<ThreadEntry>> {
let response = client
.request::<Variables>(VariablesArguments {
variables_reference,
filter: None,
start: None,
count: None,
format: None,
})
.await?;

let mut variables = Vec::new();
for variable in response.variables {
variables.push(ThreadEntry::Variable {
depth,
variable: variable.clone(),
has_children: variable.variables_reference > 0,
});

if variable.variables_reference > 0 {
let client = client.clone();
let mut nested_variables = Box::pin(Self::fetch_variables(
client,
variable.variables_reference,
depth + 1,
))
.await?;

variables.append(&mut nested_variables);
}
}

anyhow::Ok(variables)
}

fn handle_stopped_event(
client: Arc<DebugAdapterClient>,
event: &StoppedEvent,
Expand Down Expand Up @@ -427,35 +466,22 @@ impl DebugPanel {
});
}

let mut scopes: HashMap<u64, Vec<Scope>> = HashMap::new();
let mut variables: HashMap<u64, Vec<Variable>> = HashMap::new();
let mut stack_frame_entries: HashMap<u64, Vec<ThreadEntry>> = HashMap::new();

let mut variable_tasks = Vec::new();
for (thread_id, response) in try_join_all(scope_tasks).await? {
scopes.insert(thread_id, response.scopes.clone());
let entries = stack_frame_entries
.entry(thread_id)
.or_insert(Vec::default());

for scope in response.scopes {
let scope_reference = scope.variables_reference;
let client = client.clone();
variable_tasks.push(async move {
anyhow::Ok((
scope_reference,
client
.request::<Variables>(VariablesArguments {
variables_reference: scope_reference,
filter: None,
start: None,
count: None,
format: None,
})
.await?,
))
});
}
}

for (scope_reference, response) in try_join_all(variable_tasks).await? {
variables.insert(scope_reference, response.variables.clone());
entries.push(ThreadEntry::Scope(scope));

entries.append(
&mut Self::fetch_variables(client.clone(), scope_reference, 1).await?,
);
}
}

this.update(&mut cx, |this, cx| {
Expand All @@ -466,8 +492,7 @@ impl DebugPanel {

thread_state.current_stack_frame_id = Some(current_stack_frame.clone().id);
thread_state.stack_frames = stack_trace_response.stack_frames;
thread_state.scopes = scopes;
thread_state.variables = variables;
thread_state.stack_frame_entries = stack_frame_entries;
thread_state.status = ThreadStatus::Stopped;

let existing_item = this
Expand Down Expand Up @@ -496,7 +521,7 @@ impl DebugPanel {
)
});

this.add_item(Box::new(tab.clone()), false, false, None, cx)
this.add_item(Box::new(tab), false, false, None, cx)
})
})
.log_err();
Expand Down
98 changes: 45 additions & 53 deletions crates/debugger_ui/src/debugger_panel_item.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::debugger_panel::{DebugPanel, DebugPanelEvent};
use anyhow::Result;
use dap::client::{DebugAdapterClient, DebugAdapterClientId, ThreadState, ThreadStatus};
use dap::client::{
DebugAdapterClient, DebugAdapterClientId, ThreadEntry, ThreadState, ThreadStatus,
};
use dap::{
OutputEvent, OutputEventCategory, Scope, StackFrame, StoppedEvent, ThreadEvent, Variable,
};
Expand All @@ -21,28 +23,17 @@ enum ThreadItem {
Output,
}

#[derive(Debug)]
enum VariableListEntry {
Scope(Scope),
Variable {
depth: usize,
variable: Variable,
has_children: bool,
},
}

pub struct DebugPanelItem {
thread_id: u64,
variable_list: ListState,
focus_handle: FocusHandle,
stack_frame_list: ListState,
output_editor: View<Editor>,
collapsed_variables: Vec<u64>,
collapsed_variables: Vec<SharedString>,
active_thread_item: ThreadItem,
client: Arc<DebugAdapterClient>,
_subscriptions: Vec<Subscription>,
current_stack_frame_id: Option<u64>,
variable_list_entries: Vec<VariableListEntry>,
}

actions!(
Expand Down Expand Up @@ -121,7 +112,6 @@ impl DebugPanelItem {
stack_frame_list,
current_stack_frame_id: None,
collapsed_variables: Default::default(),
variable_list_entries: Default::default(),
active_thread_item: ThreadItem::Variables,
}
}
Expand Down Expand Up @@ -149,7 +139,9 @@ impl DebugPanelItem {
this.stack_frame_list.reset(thread_state.stack_frames.len());
this.current_stack_frame_id = thread_state.stack_frames.first().map(|s| s.id);

this.build_variable_list_entries(thread_state.stack_frames.first().unwrap().id);
if let Some(stack_frame_id) = this.current_stack_frame_id {
this.build_variable_list_entries(stack_frame_id);
}

cx.notify();
}
Expand Down Expand Up @@ -267,35 +259,47 @@ impl DebugPanelItem {
ix: usize,
cx: &mut ViewContext<Self>,
) -> AnyElement {
match &self.variable_list_entries[ix] {
VariableListEntry::Scope(scope) => self.render_scope(scope, cx),
VariableListEntry::Variable {
let thread_state = self.current_thread_state();
let Some(entries) = thread_state
.stack_frame_entries
.get(&self.current_stack_frame_id.unwrap_or_default())
else {
return div().into_any_element();
};

match &entries[ix] {
ThreadEntry::Scope(scope) => self.render_scope(scope, cx),
ThreadEntry::Variable {
depth,
variable,
has_children,
..
} => self.render_variable(variable.clone(), *depth, *has_children, cx),
}
}

fn render_scope(&self, scope: &Scope, cx: &mut ViewContext<Self>) -> AnyElement {
let scope_id = scope.variables_reference;
let element_id = scope.variables_reference;

let disclosed = self.collapsed_variables.binary_search(&scope_id).is_err();
let scope_id = SharedString::from(format!("scope-{}", element_id));
let disclosed = self
.collapsed_variables
.binary_search(&scope_id.clone())
.is_err();

div()
.id(scope_id as usize)
.id(element_id as usize)
.group("")
.flex()
.w_full()
.h_full()
.child(
ListItem::new(scope_id as usize)
ListItem::new(element_id as usize)
.indent_level(1)
.selected(false)
.toggle(disclosed)
.on_toggle(
cx.listener(move |this, _, cx| {
this.toggle_variable_collapsed(scope_id, cx)
this.toggle_variable_collapsed(&scope_id, cx)
}),
)
.child(div().text_ui(cx).h_6().w_full().child(scope.name.clone())),
Expand All @@ -310,8 +314,7 @@ impl DebugPanelItem {
has_children: bool,
cx: &mut ViewContext<Self>,
) -> AnyElement {
let variable_id = variable.variables_reference;

let variable_id = SharedString::from(format!("variable-{}", variable.name));
let disclosed = has_children.then(|| {
self.collapsed_variables
.binary_search(&variable_id)
Expand All @@ -329,10 +332,9 @@ impl DebugPanelItem {
ListItem::new(element_id)
.indent_level(depth + 1)
.indent_step_size(px(20.))
.selected(false)
.toggle(disclosed)
.on_toggle(cx.listener(move |this, _, cx| {
this.toggle_variable_collapsed(variable_id, cx)
this.toggle_variable_collapsed(&variable_id, cx)
}))
.child(
h_flex()
Expand Down Expand Up @@ -416,31 +418,12 @@ impl DebugPanelItem {
}

pub fn build_variable_list_entries(&mut self, stack_frame_id: u64) {
let mut entries: Vec<VariableListEntry> = vec![];

let thread_state = self.current_thread_state();
let scopes = thread_state.scopes.get(&stack_frame_id).unwrap();

for scope in scopes {
entries.push(VariableListEntry::Scope(scope.clone()));

let variables = thread_state
.variables
.get(&scope.variables_reference)
.unwrap();

for variable in variables {
entries.push(VariableListEntry::Variable {
depth: 0,
variable: variable.clone(),
has_children: variable.variables_reference > 0,
});
}
}
let Some(entries) = thread_state.stack_frame_entries.get(&stack_frame_id) else {
return;
};

let len = entries.len();
self.variable_list_entries = entries;
self.variable_list.reset(len);
self.variable_list.reset(entries.len());
}

// fn render_scopes(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
Expand Down Expand Up @@ -631,15 +614,24 @@ impl DebugPanelItem {
.detach_and_log_err(cx);
}

fn toggle_variable_collapsed(&mut self, variable_id: u64, cx: &mut ViewContext<Self>) {
fn toggle_variable_collapsed(
&mut self,
variable_id: &SharedString,
cx: &mut ViewContext<Self>,
) {
match self.collapsed_variables.binary_search(&variable_id) {
Ok(ix) => {
self.collapsed_variables.remove(ix);
}
Err(ix) => {
self.collapsed_variables.insert(ix, variable_id);
self.collapsed_variables.insert(ix, variable_id.clone());
}
};

if let Some(stack_frame_id) = self.current_stack_frame_id {
self.build_variable_list_entries(stack_frame_id);
}

cx.notify();
}
}
Expand Down

0 comments on commit f4cf31f

Please sign in to comment.