debugger: Add support for label presentation hints for stack frames (#32719)
Release Notes: - debugger: Add support for `Label` stack frame kinds Co-authored-by: Remco Smits <djsmits12@gmail.com>
This commit is contained in:
parent
6650be8e0f
commit
feef68bec7
3 changed files with 72 additions and 23 deletions
|
@ -5,9 +5,10 @@ use std::time::Duration;
|
||||||
use anyhow::{Context as _, Result, anyhow};
|
use anyhow::{Context as _, Result, anyhow};
|
||||||
use dap::StackFrameId;
|
use dap::StackFrameId;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, Entity, EventEmitter, FocusHandle, Focusable, ListState, MouseButton, Stateful,
|
AnyElement, Entity, EventEmitter, FocusHandle, Focusable, FontWeight, ListState, MouseButton,
|
||||||
Subscription, Task, WeakEntity, list,
|
Stateful, Subscription, Task, WeakEntity, list,
|
||||||
};
|
};
|
||||||
|
use util::debug_panic;
|
||||||
|
|
||||||
use crate::StackTraceView;
|
use crate::StackTraceView;
|
||||||
use language::PointUtf16;
|
use language::PointUtf16;
|
||||||
|
@ -43,6 +44,8 @@ pub struct StackFrameList {
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum StackFrameEntry {
|
pub enum StackFrameEntry {
|
||||||
Normal(dap::StackFrame),
|
Normal(dap::StackFrame),
|
||||||
|
/// Used to indicate that the frame is artificial and is a visual label or separator
|
||||||
|
Label(dap::StackFrame),
|
||||||
Collapsed(Vec<dap::StackFrame>),
|
Collapsed(Vec<dap::StackFrame>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,18 +102,18 @@ impl StackFrameList {
|
||||||
&self.entries
|
&self.entries
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn flatten_entries(&self, show_collapsed: bool) -> Vec<dap::StackFrame> {
|
pub(crate) fn flatten_entries(
|
||||||
|
&self,
|
||||||
|
show_collapsed: bool,
|
||||||
|
show_labels: bool,
|
||||||
|
) -> Vec<dap::StackFrame> {
|
||||||
self.entries
|
self.entries
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|frame| match frame {
|
.flat_map(|frame| match frame {
|
||||||
StackFrameEntry::Normal(frame) => vec![frame.clone()],
|
StackFrameEntry::Normal(frame) => vec![frame.clone()],
|
||||||
StackFrameEntry::Collapsed(frames) => {
|
StackFrameEntry::Label(frame) if show_labels => vec![frame.clone()],
|
||||||
if show_collapsed {
|
StackFrameEntry::Collapsed(frames) if show_collapsed => frames.clone(),
|
||||||
frames.clone()
|
_ => vec![],
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
@ -176,9 +179,7 @@ impl StackFrameList {
|
||||||
.and_then(|ix| self.entries.get(ix))
|
.and_then(|ix| self.entries.get(ix))
|
||||||
.and_then(|entry| match entry {
|
.and_then(|entry| match entry {
|
||||||
StackFrameEntry::Normal(stack_frame) => Some(stack_frame.id),
|
StackFrameEntry::Normal(stack_frame) => Some(stack_frame.id),
|
||||||
StackFrameEntry::Collapsed(stack_frames) => {
|
StackFrameEntry::Collapsed(_) | StackFrameEntry::Label(_) => None,
|
||||||
stack_frames.first().map(|stack_frame| stack_frame.id)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
let mut entries = Vec::new();
|
let mut entries = Vec::new();
|
||||||
let mut collapsed_entries = Vec::new();
|
let mut collapsed_entries = Vec::new();
|
||||||
|
@ -202,6 +203,9 @@ impl StackFrameList {
|
||||||
Some(dap::StackFramePresentationHint::Deemphasize) => {
|
Some(dap::StackFramePresentationHint::Deemphasize) => {
|
||||||
collapsed_entries.push(stack_frame.dap.clone());
|
collapsed_entries.push(stack_frame.dap.clone());
|
||||||
}
|
}
|
||||||
|
Some(dap::StackFramePresentationHint::Label) => {
|
||||||
|
entries.push(StackFrameEntry::Label(stack_frame.dap.clone()));
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let collapsed_entries = std::mem::take(&mut collapsed_entries);
|
let collapsed_entries = std::mem::take(&mut collapsed_entries);
|
||||||
if !collapsed_entries.is_empty() {
|
if !collapsed_entries.is_empty() {
|
||||||
|
@ -234,9 +238,7 @@ impl StackFrameList {
|
||||||
} else if let Some(old_selected_frame_id) = old_selected_frame_id {
|
} else if let Some(old_selected_frame_id) = old_selected_frame_id {
|
||||||
let ix = self.entries.iter().position(|entry| match entry {
|
let ix = self.entries.iter().position(|entry| match entry {
|
||||||
StackFrameEntry::Normal(frame) => frame.id == old_selected_frame_id,
|
StackFrameEntry::Normal(frame) => frame.id == old_selected_frame_id,
|
||||||
StackFrameEntry::Collapsed(frames) => {
|
StackFrameEntry::Collapsed(_) | StackFrameEntry::Label(_) => false,
|
||||||
frames.iter().any(|frame| frame.id == old_selected_frame_id)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
self.selected_ix = ix;
|
self.selected_ix = ix;
|
||||||
}
|
}
|
||||||
|
@ -256,6 +258,7 @@ impl StackFrameList {
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|entry| match entry {
|
.flat_map(|entry| match entry {
|
||||||
|
StackFrameEntry::Label(stack_frame) => std::slice::from_ref(stack_frame),
|
||||||
StackFrameEntry::Normal(stack_frame) => std::slice::from_ref(stack_frame),
|
StackFrameEntry::Normal(stack_frame) => std::slice::from_ref(stack_frame),
|
||||||
StackFrameEntry::Collapsed(stack_frames) => stack_frames.as_slice(),
|
StackFrameEntry::Collapsed(stack_frames) => stack_frames.as_slice(),
|
||||||
})
|
})
|
||||||
|
@ -380,6 +383,33 @@ impl StackFrameList {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_label_entry(
|
||||||
|
&self,
|
||||||
|
stack_frame: &dap::StackFrame,
|
||||||
|
_cx: &mut Context<Self>,
|
||||||
|
) -> AnyElement {
|
||||||
|
h_flex()
|
||||||
|
.rounded_md()
|
||||||
|
.justify_between()
|
||||||
|
.w_full()
|
||||||
|
.group("")
|
||||||
|
.id(("label-stack-frame", stack_frame.id))
|
||||||
|
.p_1()
|
||||||
|
.on_any_mouse_down(|_, _, cx| {
|
||||||
|
cx.stop_propagation();
|
||||||
|
})
|
||||||
|
.child(
|
||||||
|
v_flex().justify_center().gap_0p5().child(
|
||||||
|
Label::new(stack_frame.name.clone())
|
||||||
|
.size(LabelSize::Small)
|
||||||
|
.weight(FontWeight::BOLD)
|
||||||
|
.truncate()
|
||||||
|
.color(Color::Info),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.into_any()
|
||||||
|
}
|
||||||
|
|
||||||
fn render_normal_entry(
|
fn render_normal_entry(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
|
@ -541,6 +571,7 @@ impl StackFrameList {
|
||||||
|
|
||||||
fn render_entry(&self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
|
fn render_entry(&self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
|
||||||
match &self.entries[ix] {
|
match &self.entries[ix] {
|
||||||
|
StackFrameEntry::Label(stack_frame) => self.render_label_entry(stack_frame, cx),
|
||||||
StackFrameEntry::Normal(stack_frame) => self.render_normal_entry(ix, stack_frame, cx),
|
StackFrameEntry::Normal(stack_frame) => self.render_normal_entry(ix, stack_frame, cx),
|
||||||
StackFrameEntry::Collapsed(stack_frames) => {
|
StackFrameEntry::Collapsed(stack_frames) => {
|
||||||
self.render_collapsed_entry(ix, stack_frames, cx)
|
self.render_collapsed_entry(ix, stack_frames, cx)
|
||||||
|
@ -657,6 +688,9 @@ impl StackFrameList {
|
||||||
self.go_to_stack_frame_inner(stack_frame, window, cx)
|
self.go_to_stack_frame_inner(stack_frame, window, cx)
|
||||||
.detach_and_log_err(cx)
|
.detach_and_log_err(cx)
|
||||||
}
|
}
|
||||||
|
StackFrameEntry::Label(_) => {
|
||||||
|
debug_panic!("You should not be able to select a label stack frame")
|
||||||
|
}
|
||||||
StackFrameEntry::Collapsed(_) => self.expand_collapsed_entry(ix),
|
StackFrameEntry::Collapsed(_) => self.expand_collapsed_entry(ix),
|
||||||
}
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
|
@ -148,7 +148,7 @@ impl StackTraceView {
|
||||||
|
|
||||||
let stack_frames = self
|
let stack_frames = self
|
||||||
.stack_frame_list
|
.stack_frame_list
|
||||||
.read_with(cx, |list, _| list.flatten_entries(false));
|
.read_with(cx, |list, _| list.flatten_entries(false, false));
|
||||||
|
|
||||||
let frames_to_open: Vec<_> = stack_frames
|
let frames_to_open: Vec<_> = stack_frames
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -237,7 +237,7 @@ impl StackTraceView {
|
||||||
|
|
||||||
let stack_frames = self
|
let stack_frames = self
|
||||||
.stack_frame_list
|
.stack_frame_list
|
||||||
.read_with(cx, |session, _| session.flatten_entries(false));
|
.read_with(cx, |session, _| session.flatten_entries(false, false));
|
||||||
|
|
||||||
let active_idx = self
|
let active_idx = self
|
||||||
.selected_stack_frame_id
|
.selected_stack_frame_id
|
||||||
|
|
|
@ -191,7 +191,10 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||||
running_state.update(cx, |running_state, cx| {
|
running_state.update(cx, |running_state, cx| {
|
||||||
let (stack_frame_list, stack_frame_id) =
|
let (stack_frame_list, stack_frame_id) =
|
||||||
running_state.stack_frame_list().update(cx, |list, _| {
|
running_state.stack_frame_list().update(cx, |list, _| {
|
||||||
(list.flatten_entries(true), list.opened_stack_frame_id())
|
(
|
||||||
|
list.flatten_entries(true, true),
|
||||||
|
list.opened_stack_frame_id(),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(stack_frames, stack_frame_list);
|
assert_eq!(stack_frames, stack_frame_list);
|
||||||
|
@ -432,7 +435,10 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||||
running_state.update(cx, |running_state, cx| {
|
running_state.update(cx, |running_state, cx| {
|
||||||
let (stack_frame_list, stack_frame_id) =
|
let (stack_frame_list, stack_frame_id) =
|
||||||
running_state.stack_frame_list().update(cx, |list, _| {
|
running_state.stack_frame_list().update(cx, |list, _| {
|
||||||
(list.flatten_entries(true), list.opened_stack_frame_id())
|
(
|
||||||
|
list.flatten_entries(true, true),
|
||||||
|
list.opened_stack_frame_id(),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(Some(1), stack_frame_id);
|
assert_eq!(Some(1), stack_frame_id);
|
||||||
|
@ -1459,7 +1465,10 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||||
running_state.update(cx, |running_state, cx| {
|
running_state.update(cx, |running_state, cx| {
|
||||||
let (stack_frame_list, stack_frame_id) =
|
let (stack_frame_list, stack_frame_id) =
|
||||||
running_state.stack_frame_list().update(cx, |list, _| {
|
running_state.stack_frame_list().update(cx, |list, _| {
|
||||||
(list.flatten_entries(true), list.opened_stack_frame_id())
|
(
|
||||||
|
list.flatten_entries(true, true),
|
||||||
|
list.opened_stack_frame_id(),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(Some(1), stack_frame_id);
|
assert_eq!(Some(1), stack_frame_id);
|
||||||
|
@ -1741,7 +1750,10 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||||
running_state.update(cx, |running_state, cx| {
|
running_state.update(cx, |running_state, cx| {
|
||||||
let (stack_frame_list, stack_frame_id) =
|
let (stack_frame_list, stack_frame_id) =
|
||||||
running_state.stack_frame_list().update(cx, |list, _| {
|
running_state.stack_frame_list().update(cx, |list, _| {
|
||||||
(list.flatten_entries(true), list.opened_stack_frame_id())
|
(
|
||||||
|
list.flatten_entries(true, true),
|
||||||
|
list.opened_stack_frame_id(),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let variable_list = running_state.variable_list().read(cx);
|
let variable_list = running_state.variable_list().read(cx);
|
||||||
|
@ -1796,7 +1808,10 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||||
running_state.update(cx, |running_state, cx| {
|
running_state.update(cx, |running_state, cx| {
|
||||||
let (stack_frame_list, stack_frame_id) =
|
let (stack_frame_list, stack_frame_id) =
|
||||||
running_state.stack_frame_list().update(cx, |list, _| {
|
running_state.stack_frame_list().update(cx, |list, _| {
|
||||||
(list.flatten_entries(true), list.opened_stack_frame_id())
|
(
|
||||||
|
list.flatten_entries(true, true),
|
||||||
|
list.opened_stack_frame_id(),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let variable_list = running_state.variable_list().read(cx);
|
let variable_list = running_state.variable_list().read(cx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue