debugger: Add refinements to the UI (#35940)
Took a little bit of time to add just a handful of small tweaks to the debugger UI so it looks slightly more polished. This PR includes adjustments to size, focus styles, and more in icon buttons, overall spacing nudges in each section pane, making tooltip labels title case (for overall consistency), and some icon SVG iteration. Release Notes: - N/A
This commit is contained in:
parent
95e302fa68
commit
f3d6deb5a3
8 changed files with 263 additions and 204 deletions
|
@ -1,3 +1,5 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.9999 11.0333C13.9999 11.3516 13.8735 11.6568 13.6484 11.8818C13.4234 12.1069 13.1182 12.2333 12.7999 12.2333H4.8966C4.57836 12.2334 4.27318 12.3599 4.04818 12.5849L2.72697 13.9061C2.66739 13.9657 2.59149 14.0063 2.50886 14.0227C2.42623 14.0391 2.34058 14.0307 2.26274 13.9985C2.18491 13.9662 2.11838 13.9116 2.07157 13.8416C2.02476 13.7715 1.99977 13.6892 1.99976 13.6049V3.8332C1.99976 3.51493 2.12619 3.2097 2.35123 2.98466C2.57628 2.75961 2.88151 2.63318 3.19977 2.63318H12.7999C13.1182 2.63318 13.4234 2.75961 13.6484 2.98466C13.8735 3.2097 13.9999 3.51493 13.9999 3.8332V11.0333Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.8889 2H4.11111C3.49746 2 3 2.59695 3 3.33333V12.6667C3 13.403 3.49746 14 4.11111 14H11.8889C12.5025 14 13 13.403 13 12.6667V3.33333C13 2.59695 12.5025 2 11.8889 2Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 6H6" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10 10H6" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 785 B After Width: | Height: | Size: 566 B |
|
@ -1 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M2.998 3 13 13.002M6.174 3.345a5.001 5.001 0 0 1 6.476 6.481M11.54 11.542A5.008 5.008 0 0 1 4.458 4.46"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 2L14 14M5.81044 2.41392C6.89676 1.98976 8.08314 1.89138 9.22449 2.13079C10.3658 2.37021 11.4127 2.93705 12.237 3.76199C13.0613 4.58693 13.6273 5.6342 13.8658 6.77573C14.1044 7.91727 14.0051 9.10357 13.5801 10.1896M12.2484 12.2484C11.1176 13.3558 9.59562 13.9724 8.01292 13.9642C6.43021 13.956 4.91467 13.3236 3.79552 12.2045C2.67636 11.0853 2.044 9.56979 2.03578 7.98708C2.02757 6.40438 2.64417 4.88236 3.75165 3.75165" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 618 B |
|
@ -1,3 +1,3 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.9999 11.0333C13.9999 11.3516 13.8735 11.6568 13.6484 11.8818C13.4234 12.1069 13.1182 12.2333 12.7999 12.2333H4.8966C4.57836 12.2334 4.27318 12.3599 4.04818 12.5849L2.72697 13.9061C2.66739 13.9657 2.59149 14.0063 2.50886 14.0227C2.42623 14.0391 2.34058 14.0307 2.26274 13.9985C2.18491 13.9662 2.11838 13.9116 2.07157 13.8416C2.02476 13.7715 1.99977 13.6892 1.99976 13.6049V3.8332C1.99976 3.51493 2.12619 3.2097 2.35123 2.98466C2.57628 2.75961 2.88151 2.63318 3.19977 2.63318H12.7999C13.1182 2.63318 13.4234 2.75961 13.6484 2.98466C13.8735 3.2097 13.9999 3.51493 13.9999 3.8332V11.0333Z" fill="black" fill-opacity="0.6" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.8887 1.25C13.0386 1.25 13.7498 2.31634 13.75 3.33301V12.667C13.7499 13.6836 13.0386 14.75 11.8887 14.75H4.11133C2.96134 14.75 2.25014 13.6836 2.25 12.667V3.33301C2.25015 2.31635 2.96136 1.25 4.11133 1.25H11.8887ZM6 9.25C5.58579 9.25 5.25 9.58579 5.25 10C5.25 10.4142 5.58579 10.75 6 10.75H10C10.4142 10.75 10.75 10.4142 10.75 10C10.75 9.58579 10.4142 9.25 10 9.25H6ZM6 5.25C5.58579 5.25 5.25 5.58579 5.25 6C5.25 6.41421 5.58579 6.75 6 6.75H9C9.41421 6.75 9.75 6.41421 9.75 6C9.75 5.58579 9.41421 5.25 9 5.25H6Z" fill="black"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 817 B After Width: | Height: | Size: 643 B |
|
@ -36,7 +36,7 @@ use settings::Settings;
|
|||
use std::sync::{Arc, LazyLock};
|
||||
use task::{DebugScenario, TaskContext};
|
||||
use tree_sitter::{Query, StreamingIterator as _};
|
||||
use ui::{ContextMenu, Divider, PopoverMenuHandle, Tooltip, prelude::*};
|
||||
use ui::{ContextMenu, Divider, PopoverMenuHandle, Tab, Tooltip, prelude::*};
|
||||
use util::{ResultExt, debug_panic, maybe};
|
||||
use workspace::SplitDirection;
|
||||
use workspace::item::SaveOptions;
|
||||
|
@ -642,12 +642,14 @@ impl DebugPanel {
|
|||
}
|
||||
})
|
||||
};
|
||||
|
||||
let documentation_button = || {
|
||||
IconButton::new("debug-open-documentation", IconName::CircleHelp)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(move |_, _, cx| cx.open_url("https://zed.dev/docs/debugger"))
|
||||
.tooltip(Tooltip::text("Open Documentation"))
|
||||
};
|
||||
|
||||
let logs_button = || {
|
||||
IconButton::new("debug-open-logs", IconName::Notepad)
|
||||
.icon_size(IconSize::Small)
|
||||
|
@ -658,16 +660,18 @@ impl DebugPanel {
|
|||
};
|
||||
|
||||
Some(
|
||||
div.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.p_1()
|
||||
div.w_full()
|
||||
.py_1()
|
||||
.px_1p5()
|
||||
.justify_between()
|
||||
.w_full()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.when(is_side, |this| this.gap_1())
|
||||
.child(
|
||||
h_flex()
|
||||
.justify_between()
|
||||
.child(
|
||||
h_flex().gap_2().w_full().when_some(
|
||||
h_flex().gap_1().w_full().when_some(
|
||||
active_session
|
||||
.as_ref()
|
||||
.map(|session| session.read(cx).running_state()),
|
||||
|
@ -679,6 +683,7 @@ impl DebugPanel {
|
|||
let capabilities = running_state.read(cx).capabilities(cx);
|
||||
let supports_detach =
|
||||
running_state.read(cx).session().read(cx).is_attached();
|
||||
|
||||
this.map(|this| {
|
||||
if thread_status == ThreadStatus::Running {
|
||||
this.child(
|
||||
|
@ -686,8 +691,7 @@ impl DebugPanel {
|
|||
"debug-pause",
|
||||
IconName::DebugPause,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, _window, cx| {
|
||||
|
@ -698,7 +702,7 @@ impl DebugPanel {
|
|||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Pause program",
|
||||
"Pause Program",
|
||||
&Pause,
|
||||
&focus_handle,
|
||||
window,
|
||||
|
@ -713,8 +717,7 @@ impl DebugPanel {
|
|||
"debug-continue",
|
||||
IconName::DebugContinue,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, _window, cx| this.continue_thread(cx),
|
||||
|
@ -724,7 +727,7 @@ impl DebugPanel {
|
|||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Continue program",
|
||||
"Continue Program",
|
||||
&Continue,
|
||||
&focus_handle,
|
||||
window,
|
||||
|
@ -737,8 +740,7 @@ impl DebugPanel {
|
|||
})
|
||||
.child(
|
||||
IconButton::new("debug-step-over", IconName::ArrowRight)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, _window, cx| {
|
||||
|
@ -750,7 +752,7 @@ impl DebugPanel {
|
|||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Step over",
|
||||
"Step Over",
|
||||
&StepOver,
|
||||
&focus_handle,
|
||||
window,
|
||||
|
@ -764,8 +766,7 @@ impl DebugPanel {
|
|||
"debug-step-into",
|
||||
IconName::ArrowDownRight,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, _window, cx| {
|
||||
|
@ -777,7 +778,7 @@ impl DebugPanel {
|
|||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Step in",
|
||||
"Step In",
|
||||
&StepInto,
|
||||
&focus_handle,
|
||||
window,
|
||||
|
@ -789,7 +790,6 @@ impl DebugPanel {
|
|||
.child(
|
||||
IconButton::new("debug-step-out", IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, _window, cx| {
|
||||
|
@ -801,7 +801,7 @@ impl DebugPanel {
|
|||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Step out",
|
||||
"Step Out",
|
||||
&StepOut,
|
||||
&focus_handle,
|
||||
window,
|
||||
|
@ -813,7 +813,7 @@ impl DebugPanel {
|
|||
.child(Divider::vertical())
|
||||
.child(
|
||||
IconButton::new("debug-restart", IconName::RotateCcw)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, window, cx| {
|
||||
|
@ -835,7 +835,7 @@ impl DebugPanel {
|
|||
)
|
||||
.child(
|
||||
IconButton::new("debug-stop", IconName::Power)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, _window, cx| {
|
||||
|
@ -890,7 +890,7 @@ impl DebugPanel {
|
|||
thread_status != ThreadStatus::Stopped
|
||||
&& thread_status != ThreadStatus::Running,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
&running_state,
|
||||
|this, _, _, cx| {
|
||||
|
@ -915,7 +915,6 @@ impl DebugPanel {
|
|||
},
|
||||
),
|
||||
)
|
||||
.justify_around()
|
||||
.when(is_side, |this| {
|
||||
this.child(new_session_button())
|
||||
.child(logs_button())
|
||||
|
@ -924,7 +923,7 @@ impl DebugPanel {
|
|||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.gap_0p5()
|
||||
.when(is_side, |this| this.justify_between())
|
||||
.child(
|
||||
h_flex().when_some(
|
||||
|
@ -954,12 +953,15 @@ impl DebugPanel {
|
|||
)
|
||||
})
|
||||
})
|
||||
.when(!is_side, |this| this.gap_2().child(Divider::vertical()))
|
||||
.when(!is_side, |this| {
|
||||
this.gap_0p5().child(Divider::vertical())
|
||||
})
|
||||
},
|
||||
),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_0p5()
|
||||
.children(self.render_session_menu(
|
||||
self.active_session(),
|
||||
self.running_state(cx),
|
||||
|
@ -1702,6 +1704,7 @@ impl Render for DebugPanel {
|
|||
this.child(active_session)
|
||||
} else {
|
||||
let docked_to_bottom = self.position(window, cx) == DockPosition::Bottom;
|
||||
|
||||
let welcome_experience = v_flex()
|
||||
.when_else(
|
||||
docked_to_bottom,
|
||||
|
@ -1767,54 +1770,58 @@ impl Render for DebugPanel {
|
|||
);
|
||||
}),
|
||||
);
|
||||
let breakpoint_list =
|
||||
v_flex()
|
||||
.group("base-breakpoint-list")
|
||||
.items_start()
|
||||
.when_else(
|
||||
docked_to_bottom,
|
||||
|this| this.min_w_1_3().h_full(),
|
||||
|this| this.w_full().h_2_3(),
|
||||
)
|
||||
.p_1()
|
||||
.child(
|
||||
h_flex()
|
||||
.pl_1()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.child(Label::new("Breakpoints").size(LabelSize::Small))
|
||||
.child(h_flex().visible_on_hover("base-breakpoint-list").child(
|
||||
|
||||
let breakpoint_list = v_flex()
|
||||
.group("base-breakpoint-list")
|
||||
.when_else(
|
||||
docked_to_bottom,
|
||||
|this| this.min_w_1_3().h_full(),
|
||||
|this| this.size_full().h_2_3(),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.track_focus(&self.breakpoint_list.focus_handle(cx))
|
||||
.h(Tab::container_height(cx))
|
||||
.p_1p5()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.child(Label::new("Breakpoints").size(LabelSize::Small))
|
||||
.child(
|
||||
h_flex().visible_on_hover("base-breakpoint-list").child(
|
||||
self.breakpoint_list.read(cx).render_control_strip(),
|
||||
))
|
||||
.track_focus(&self.breakpoint_list.focus_handle(cx)),
|
||||
)
|
||||
.child(Divider::horizontal())
|
||||
.child(self.breakpoint_list.clone());
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(self.breakpoint_list.clone());
|
||||
|
||||
this.child(
|
||||
v_flex()
|
||||
.h_full()
|
||||
.size_full()
|
||||
.gap_1()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.child(
|
||||
div()
|
||||
.when_else(docked_to_bottom, Div::h_flex, Div::v_flex)
|
||||
.size_full()
|
||||
.map(|this| {
|
||||
if docked_to_bottom {
|
||||
this.items_start()
|
||||
.child(breakpoint_list)
|
||||
.child(Divider::vertical())
|
||||
.child(welcome_experience)
|
||||
.child(Divider::vertical())
|
||||
} else {
|
||||
this.items_end()
|
||||
.child(welcome_experience)
|
||||
.child(Divider::horizontal())
|
||||
.child(breakpoint_list)
|
||||
}
|
||||
}),
|
||||
),
|
||||
.map(|this| {
|
||||
if docked_to_bottom {
|
||||
this.child(
|
||||
h_flex()
|
||||
.size_full()
|
||||
.child(breakpoint_list)
|
||||
.child(Divider::vertical())
|
||||
.child(welcome_experience)
|
||||
.child(Divider::vertical()),
|
||||
)
|
||||
} else {
|
||||
this.child(
|
||||
v_flex()
|
||||
.size_full()
|
||||
.child(welcome_experience)
|
||||
.child(Divider::horizontal())
|
||||
.child(breakpoint_list),
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -48,10 +48,8 @@ use task::{
|
|||
};
|
||||
use terminal_view::TerminalView;
|
||||
use ui::{
|
||||
ActiveTheme, AnyElement, App, ButtonCommon as _, Clickable as _, Context, FluentBuilder,
|
||||
IconButton, IconName, IconSize, InteractiveElement, IntoElement, Label, LabelCommon as _,
|
||||
ParentElement, Render, SharedString, StatefulInteractiveElement, Styled, Tab, Tooltip,
|
||||
VisibleOnHover, VisualContext, Window, div, h_flex, v_flex,
|
||||
FluentBuilder, IntoElement, Render, StatefulInteractiveElement, Tab, Tooltip, VisibleOnHover,
|
||||
VisualContext, prelude::*,
|
||||
};
|
||||
use util::ResultExt;
|
||||
use variable_list::VariableList;
|
||||
|
@ -419,13 +417,14 @@ pub(crate) fn new_debugger_pane(
|
|||
.map_or(false, |item| item.read(cx).hovered);
|
||||
|
||||
h_flex()
|
||||
.group(pane_group_id.clone())
|
||||
.justify_between()
|
||||
.bg(cx.theme().colors().tab_bar_background)
|
||||
.border_b_1()
|
||||
.px_2()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.track_focus(&focus_handle)
|
||||
.group(pane_group_id.clone())
|
||||
.pl_1p5()
|
||||
.pr_1()
|
||||
.justify_between()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.bg(cx.theme().colors().tab_bar_background)
|
||||
.on_action(|_: &menu::Cancel, window, cx| {
|
||||
if cx.stop_active_drag(window) {
|
||||
return;
|
||||
|
@ -514,6 +513,7 @@ pub(crate) fn new_debugger_pane(
|
|||
)
|
||||
.child({
|
||||
let zoomed = pane.is_zoomed();
|
||||
|
||||
h_flex()
|
||||
.visible_on_hover(pane_group_id)
|
||||
.when(is_hovered, |this| this.visible())
|
||||
|
@ -537,7 +537,7 @@ pub(crate) fn new_debugger_pane(
|
|||
IconName::Maximize
|
||||
},
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(cx.listener(move |pane, _, _, cx| {
|
||||
let is_zoomed = pane.is_zoomed();
|
||||
pane.set_zoomed(!is_zoomed, cx);
|
||||
|
@ -592,10 +592,11 @@ impl DebugTerminal {
|
|||
}
|
||||
|
||||
impl gpui::Render for DebugTerminal {
|
||||
fn render(&mut self, _window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
div()
|
||||
.size_full()
|
||||
.track_focus(&self.focus_handle)
|
||||
.size_full()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.children(self.terminal.clone())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,8 @@ use project::{
|
|||
worktree_store::WorktreeStore,
|
||||
};
|
||||
use ui::{
|
||||
ActiveTheme, AnyElement, App, ButtonCommon, Clickable, Color, Context, Disableable, Div,
|
||||
Divider, FluentBuilder as _, Icon, IconButton, IconName, IconSize, InteractiveElement,
|
||||
IntoElement, Label, LabelCommon, LabelSize, ListItem, ParentElement, Render, RenderOnce,
|
||||
Scrollbar, ScrollbarState, SharedString, StatefulInteractiveElement, Styled, Toggleable,
|
||||
Tooltip, Window, div, h_flex, px, v_flex,
|
||||
Divider, DividerColor, FluentBuilder as _, Indicator, IntoElement, ListItem, Render, Scrollbar,
|
||||
ScrollbarState, StatefulInteractiveElement, Tooltip, prelude::*,
|
||||
};
|
||||
use workspace::Workspace;
|
||||
use zed_actions::{ToggleEnableBreakpoint, UnsetBreakpoint};
|
||||
|
@ -569,6 +566,7 @@ impl BreakpointList {
|
|||
.map(|session| SupportedBreakpointProperties::from(session.read(cx).capabilities()))
|
||||
.unwrap_or_else(SupportedBreakpointProperties::empty);
|
||||
let strip_mode = self.strip_mode;
|
||||
|
||||
uniform_list(
|
||||
"breakpoint-list",
|
||||
self.breakpoints.len(),
|
||||
|
@ -591,7 +589,7 @@ impl BreakpointList {
|
|||
}),
|
||||
)
|
||||
.track_scroll(self.scroll_handle.clone())
|
||||
.flex_grow()
|
||||
.flex_1()
|
||||
}
|
||||
|
||||
fn render_vertical_scrollbar(&self, cx: &mut Context<Self>) -> Stateful<Div> {
|
||||
|
@ -630,6 +628,7 @@ impl BreakpointList {
|
|||
pub(crate) fn render_control_strip(&self) -> AnyElement {
|
||||
let selection_kind = self.selection_kind();
|
||||
let focus_handle = self.focus_handle.clone();
|
||||
|
||||
let remove_breakpoint_tooltip = selection_kind.map(|(kind, _)| match kind {
|
||||
SelectedBreakpointKind::Source => "Remove breakpoint from a breakpoint list",
|
||||
SelectedBreakpointKind::Exception => {
|
||||
|
@ -637,6 +636,7 @@ impl BreakpointList {
|
|||
}
|
||||
SelectedBreakpointKind::Data => "Remove data breakpoint from a breakpoint list",
|
||||
});
|
||||
|
||||
let toggle_label = selection_kind.map(|(_, is_enabled)| {
|
||||
if is_enabled {
|
||||
(
|
||||
|
@ -649,13 +649,12 @@ impl BreakpointList {
|
|||
});
|
||||
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(
|
||||
IconButton::new(
|
||||
"disable-breakpoint-breakpoint-list",
|
||||
IconName::DebugDisabledBreakpoint,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_size(IconSize::Small)
|
||||
.when_some(toggle_label, |this, (label, meta)| {
|
||||
this.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
|
@ -681,9 +680,8 @@ impl BreakpointList {
|
|||
}),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("remove-breakpoint-breakpoint-list", IconName::Close)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(ui::Color::Error)
|
||||
IconButton::new("remove-breakpoint-breakpoint-list", IconName::Trash)
|
||||
.icon_size(IconSize::Small)
|
||||
.when_some(remove_breakpoint_tooltip, |this, tooltip| {
|
||||
this.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
|
@ -710,7 +708,6 @@ impl BreakpointList {
|
|||
}
|
||||
}),
|
||||
)
|
||||
.mr_2()
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
@ -791,6 +788,7 @@ impl Render for BreakpointList {
|
|||
.chain(data_breakpoints)
|
||||
.chain(exception_breakpoints),
|
||||
);
|
||||
|
||||
v_flex()
|
||||
.id("breakpoint-list")
|
||||
.key_context("BreakpointList")
|
||||
|
@ -806,35 +804,33 @@ impl Render for BreakpointList {
|
|||
.on_action(cx.listener(Self::next_breakpoint_property))
|
||||
.on_action(cx.listener(Self::previous_breakpoint_property))
|
||||
.size_full()
|
||||
.m_0p5()
|
||||
.child(
|
||||
v_flex()
|
||||
.size_full()
|
||||
.child(self.render_list(cx))
|
||||
.child(self.render_vertical_scrollbar(cx)),
|
||||
)
|
||||
.pt_1()
|
||||
.child(self.render_list(cx))
|
||||
.child(self.render_vertical_scrollbar(cx))
|
||||
.when_some(self.strip_mode, |this, _| {
|
||||
this.child(Divider::horizontal()).child(
|
||||
h_flex()
|
||||
// .w_full()
|
||||
.m_0p5()
|
||||
.p_0p5()
|
||||
.border_1()
|
||||
.rounded_sm()
|
||||
.when(
|
||||
self.input.focus_handle(cx).contains_focused(window, cx),
|
||||
|this| {
|
||||
let colors = cx.theme().colors();
|
||||
let border = if self.input.read(cx).read_only(cx) {
|
||||
colors.border_disabled
|
||||
} else {
|
||||
colors.border_focused
|
||||
};
|
||||
this.border_color(border)
|
||||
},
|
||||
)
|
||||
.child(self.input.clone()),
|
||||
)
|
||||
this.child(Divider::horizontal().color(DividerColor::Border))
|
||||
.child(
|
||||
h_flex()
|
||||
.p_1()
|
||||
.rounded_sm()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.border_1()
|
||||
.when(
|
||||
self.input.focus_handle(cx).contains_focused(window, cx),
|
||||
|this| {
|
||||
let colors = cx.theme().colors();
|
||||
|
||||
let border_color = if self.input.read(cx).read_only(cx) {
|
||||
colors.border_disabled
|
||||
} else {
|
||||
colors.border_transparent
|
||||
};
|
||||
|
||||
this.border_color(border_color)
|
||||
},
|
||||
)
|
||||
.child(self.input.clone()),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -865,12 +861,17 @@ impl LineBreakpoint {
|
|||
let path = self.breakpoint.path.clone();
|
||||
let row = self.breakpoint.row;
|
||||
let is_enabled = self.breakpoint.state.is_enabled();
|
||||
|
||||
let indicator = div()
|
||||
.id(SharedString::from(format!(
|
||||
"breakpoint-ui-toggle-{:?}/{}:{}",
|
||||
self.dir, self.name, self.line
|
||||
)))
|
||||
.cursor_pointer()
|
||||
.child(
|
||||
Icon::new(icon_name)
|
||||
.color(Color::Debugger)
|
||||
.size(IconSize::XSmall),
|
||||
)
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
|
@ -902,17 +903,14 @@ impl LineBreakpoint {
|
|||
.ok();
|
||||
}
|
||||
})
|
||||
.child(
|
||||
Icon::new(icon_name)
|
||||
.color(Color::Debugger)
|
||||
.size(IconSize::XSmall),
|
||||
)
|
||||
.on_mouse_down(MouseButton::Left, move |_, _, _| {});
|
||||
|
||||
ListItem::new(SharedString::from(format!(
|
||||
"breakpoint-ui-item-{:?}/{}:{}",
|
||||
self.dir, self.name, self.line
|
||||
)))
|
||||
.toggle_state(is_selected)
|
||||
.inset(true)
|
||||
.on_click({
|
||||
let weak = weak.clone();
|
||||
move |_, window, cx| {
|
||||
|
@ -922,23 +920,20 @@ impl LineBreakpoint {
|
|||
.ok();
|
||||
}
|
||||
})
|
||||
.start_slot(indicator)
|
||||
.rounded()
|
||||
.on_secondary_mouse_down(|_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.start_slot(indicator)
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.mr_4()
|
||||
.py_0p5()
|
||||
.gap_1()
|
||||
.min_h(px(26.))
|
||||
.justify_between()
|
||||
.id(SharedString::from(format!(
|
||||
"breakpoint-ui-on-click-go-to-line-{:?}/{}:{}",
|
||||
self.dir, self.name, self.line
|
||||
)))
|
||||
.w_full()
|
||||
.gap_1()
|
||||
.min_h(rems_from_px(26.))
|
||||
.justify_between()
|
||||
.on_click({
|
||||
let weak = weak.clone();
|
||||
move |_, window, cx| {
|
||||
|
@ -949,9 +944,9 @@ impl LineBreakpoint {
|
|||
.ok();
|
||||
}
|
||||
})
|
||||
.cursor_pointer()
|
||||
.child(
|
||||
h_flex()
|
||||
.id("label-container")
|
||||
.gap_0p5()
|
||||
.child(
|
||||
Label::new(format!("{}:{}", self.name, self.line))
|
||||
|
@ -971,11 +966,13 @@ impl LineBreakpoint {
|
|||
.line_height_style(ui::LineHeightStyle::UiLabel)
|
||||
.truncate(),
|
||||
)
|
||||
})),
|
||||
}))
|
||||
.when_some(self.dir.as_ref(), |this, parent_dir| {
|
||||
this.tooltip(Tooltip::text(format!(
|
||||
"Worktree parent path: {parent_dir}"
|
||||
)))
|
||||
}),
|
||||
)
|
||||
.when_some(self.dir.as_ref(), |this, parent_dir| {
|
||||
this.tooltip(Tooltip::text(format!("Worktree parent path: {parent_dir}")))
|
||||
})
|
||||
.child(BreakpointOptionsStrip {
|
||||
props,
|
||||
breakpoint: BreakpointEntry {
|
||||
|
@ -988,15 +985,16 @@ impl LineBreakpoint {
|
|||
index: ix,
|
||||
}),
|
||||
)
|
||||
.toggle_state(is_selected)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ExceptionBreakpoint {
|
||||
id: String,
|
||||
data: ExceptionBreakpointsFilter,
|
||||
is_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct DataBreakpoint(project::debugger::session::DataBreakpointState);
|
||||
|
||||
|
@ -1017,17 +1015,24 @@ impl DataBreakpoint {
|
|||
};
|
||||
let is_enabled = self.0.is_enabled;
|
||||
let id = self.0.dap.data_id.clone();
|
||||
|
||||
ListItem::new(SharedString::from(format!(
|
||||
"data-breakpoint-ui-item-{}",
|
||||
self.0.dap.data_id
|
||||
)))
|
||||
.rounded()
|
||||
.toggle_state(is_selected)
|
||||
.inset(true)
|
||||
.start_slot(
|
||||
div()
|
||||
.id(SharedString::from(format!(
|
||||
"data-breakpoint-ui-item-{}-click-handler",
|
||||
self.0.dap.data_id
|
||||
)))
|
||||
.child(
|
||||
Icon::new(IconName::Binary)
|
||||
.color(color)
|
||||
.size(IconSize::Small),
|
||||
)
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
|
@ -1052,25 +1057,18 @@ impl DataBreakpoint {
|
|||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.cursor_pointer()
|
||||
.child(
|
||||
Icon::new(IconName::Binary)
|
||||
.color(color)
|
||||
.size(IconSize::Small),
|
||||
),
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.mr_4()
|
||||
.py_0p5()
|
||||
.gap_1()
|
||||
.min_h(rems_from_px(26.))
|
||||
.justify_between()
|
||||
.child(
|
||||
v_flex()
|
||||
.py_1()
|
||||
.gap_1()
|
||||
.min_h(px(26.))
|
||||
.justify_center()
|
||||
.id(("data-breakpoint-label", ix))
|
||||
.child(
|
||||
|
@ -1091,7 +1089,6 @@ impl DataBreakpoint {
|
|||
index: ix,
|
||||
}),
|
||||
)
|
||||
.toggle_state(is_selected)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1113,10 +1110,13 @@ impl ExceptionBreakpoint {
|
|||
let id = SharedString::from(&self.id);
|
||||
let is_enabled = self.is_enabled;
|
||||
let weak = list.clone();
|
||||
|
||||
ListItem::new(SharedString::from(format!(
|
||||
"exception-breakpoint-ui-item-{}",
|
||||
self.id
|
||||
)))
|
||||
.toggle_state(is_selected)
|
||||
.inset(true)
|
||||
.on_click({
|
||||
let list = list.clone();
|
||||
move |_, window, cx| {
|
||||
|
@ -1124,7 +1124,6 @@ impl ExceptionBreakpoint {
|
|||
.ok();
|
||||
}
|
||||
})
|
||||
.rounded()
|
||||
.on_secondary_mouse_down(|_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
|
@ -1134,6 +1133,11 @@ impl ExceptionBreakpoint {
|
|||
"exception-breakpoint-ui-item-{}-click-handler",
|
||||
self.id
|
||||
)))
|
||||
.child(
|
||||
Icon::new(IconName::Flame)
|
||||
.color(color)
|
||||
.size(IconSize::Small),
|
||||
)
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
|
@ -1158,25 +1162,18 @@ impl ExceptionBreakpoint {
|
|||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.cursor_pointer()
|
||||
.child(
|
||||
Icon::new(IconName::Flame)
|
||||
.color(color)
|
||||
.size(IconSize::Small),
|
||||
),
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.mr_4()
|
||||
.py_0p5()
|
||||
.gap_1()
|
||||
.min_h(rems_from_px(26.))
|
||||
.justify_between()
|
||||
.child(
|
||||
v_flex()
|
||||
.py_1()
|
||||
.gap_1()
|
||||
.min_h(px(26.))
|
||||
.justify_center()
|
||||
.id(("exception-breakpoint-label", ix))
|
||||
.child(
|
||||
|
@ -1200,7 +1197,6 @@ impl ExceptionBreakpoint {
|
|||
index: ix,
|
||||
}),
|
||||
)
|
||||
.toggle_state(is_selected)
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -1302,6 +1298,7 @@ impl BreakpointEntry {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SupportedBreakpointProperties: u32 {
|
||||
|
@ -1360,6 +1357,7 @@ impl BreakpointOptionsStrip {
|
|||
fn is_toggled(&self, expected_mode: ActiveBreakpointStripMode) -> bool {
|
||||
self.is_selected && self.strip_mode == Some(expected_mode)
|
||||
}
|
||||
|
||||
fn on_click_callback(
|
||||
&self,
|
||||
mode: ActiveBreakpointStripMode,
|
||||
|
@ -1379,7 +1377,8 @@ impl BreakpointOptionsStrip {
|
|||
.ok();
|
||||
}
|
||||
}
|
||||
fn add_border(
|
||||
|
||||
fn add_focus_styles(
|
||||
&self,
|
||||
kind: ActiveBreakpointStripMode,
|
||||
available: bool,
|
||||
|
@ -1388,22 +1387,25 @@ impl BreakpointOptionsStrip {
|
|||
) -> impl Fn(Div) -> Div {
|
||||
move |this: Div| {
|
||||
// Avoid layout shifts in case there's no colored border
|
||||
let this = this.border_2().rounded_sm();
|
||||
let this = this.border_1().rounded_sm();
|
||||
let color = cx.theme().colors();
|
||||
|
||||
if self.is_selected && self.strip_mode == Some(kind) {
|
||||
let theme = cx.theme().colors();
|
||||
if self.focus_handle.is_focused(window) {
|
||||
this.border_color(theme.border_selected)
|
||||
this.bg(color.editor_background)
|
||||
.border_color(color.border_focused)
|
||||
} else {
|
||||
this.border_color(theme.border_disabled)
|
||||
this.border_color(color.border)
|
||||
}
|
||||
} else if !available {
|
||||
this.border_color(cx.theme().colors().border_disabled)
|
||||
this.border_color(color.border_transparent)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for BreakpointOptionsStrip {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let id = self.breakpoint.id();
|
||||
|
@ -1426,73 +1428,117 @@ impl RenderOnce for BreakpointOptionsStrip {
|
|||
};
|
||||
let color_for_toggle = |is_enabled| {
|
||||
if is_enabled {
|
||||
ui::Color::Default
|
||||
Color::Default
|
||||
} else {
|
||||
ui::Color::Muted
|
||||
Color::Muted
|
||||
}
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.gap_px()
|
||||
.mr_3() // Space to avoid overlapping with the scrollbar
|
||||
.child(
|
||||
div().map(self.add_border(ActiveBreakpointStripMode::Log, supports_logs, window, cx))
|
||||
div()
|
||||
.map(self.add_focus_styles(
|
||||
ActiveBreakpointStripMode::Log,
|
||||
supports_logs,
|
||||
window,
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
IconButton::new(
|
||||
SharedString::from(format!("{id}-log-toggle")),
|
||||
IconName::Notepad,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.style(style_for_toggle(ActiveBreakpointStripMode::Log, has_logs))
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(color_for_toggle(has_logs))
|
||||
.when(has_logs, |this| this.indicator(Indicator::dot().color(Color::Info)))
|
||||
.disabled(!supports_logs)
|
||||
.toggle_state(self.is_toggled(ActiveBreakpointStripMode::Log))
|
||||
.on_click(self.on_click_callback(ActiveBreakpointStripMode::Log)).tooltip(|window, cx| Tooltip::with_meta("Set Log Message", None, "Set log message to display (instead of stopping) when a breakpoint is hit", window, cx))
|
||||
.on_click(self.on_click_callback(ActiveBreakpointStripMode::Log))
|
||||
.tooltip(|window, cx| {
|
||||
Tooltip::with_meta(
|
||||
"Set Log Message",
|
||||
None,
|
||||
"Set log message to display (instead of stopping) when a breakpoint is hit.",
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.when(!has_logs && !self.is_selected, |this| this.invisible()),
|
||||
)
|
||||
.child(
|
||||
div().map(self.add_border(
|
||||
ActiveBreakpointStripMode::Condition,
|
||||
supports_condition,
|
||||
window, cx
|
||||
))
|
||||
div()
|
||||
.map(self.add_focus_styles(
|
||||
ActiveBreakpointStripMode::Condition,
|
||||
supports_condition,
|
||||
window,
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
IconButton::new(
|
||||
SharedString::from(format!("{id}-condition-toggle")),
|
||||
IconName::SplitAlt,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.style(style_for_toggle(
|
||||
ActiveBreakpointStripMode::Condition,
|
||||
has_condition
|
||||
has_condition,
|
||||
))
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(color_for_toggle(has_condition))
|
||||
.when(has_condition, |this| this.indicator(Indicator::dot().color(Color::Info)))
|
||||
.disabled(!supports_condition)
|
||||
.toggle_state(self.is_toggled(ActiveBreakpointStripMode::Condition))
|
||||
.on_click(self.on_click_callback(ActiveBreakpointStripMode::Condition))
|
||||
.tooltip(|window, cx| Tooltip::with_meta("Set Condition", None, "Set condition to evaluate when a breakpoint is hit. Program execution will stop only when the condition is met", window, cx))
|
||||
.tooltip(|window, cx| {
|
||||
Tooltip::with_meta(
|
||||
"Set Condition",
|
||||
None,
|
||||
"Set condition to evaluate when a breakpoint is hit. Program execution will stop only when the condition is met.",
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.when(!has_condition && !self.is_selected, |this| this.invisible()),
|
||||
)
|
||||
.child(
|
||||
div().map(self.add_border(
|
||||
ActiveBreakpointStripMode::HitCondition,
|
||||
supports_hit_condition,window, cx
|
||||
))
|
||||
div()
|
||||
.map(self.add_focus_styles(
|
||||
ActiveBreakpointStripMode::HitCondition,
|
||||
supports_hit_condition,
|
||||
window,
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
IconButton::new(
|
||||
SharedString::from(format!("{id}-hit-condition-toggle")),
|
||||
IconName::ArrowDown10,
|
||||
)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.style(style_for_toggle(
|
||||
ActiveBreakpointStripMode::HitCondition,
|
||||
has_hit_condition,
|
||||
))
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(color_for_toggle(has_hit_condition))
|
||||
.when(has_hit_condition, |this| this.indicator(Indicator::dot().color(Color::Info)))
|
||||
.disabled(!supports_hit_condition)
|
||||
.toggle_state(self.is_toggled(ActiveBreakpointStripMode::HitCondition))
|
||||
.on_click(self.on_click_callback(ActiveBreakpointStripMode::HitCondition)).tooltip(|window, cx| Tooltip::with_meta("Set Hit Condition", None, "Set expression that controls how many hits of the breakpoint are ignored.", window, cx))
|
||||
.on_click(self.on_click_callback(ActiveBreakpointStripMode::HitCondition))
|
||||
.tooltip(|window, cx| {
|
||||
Tooltip::with_meta(
|
||||
"Set Hit Condition",
|
||||
None,
|
||||
"Set expression that controls how many hits of the breakpoint are ignored.",
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.when(!has_hit_condition && !self.is_selected, |this| {
|
||||
this.invisible()
|
||||
|
|
|
@ -367,7 +367,7 @@ impl Console {
|
|||
.when_some(keybinding_target.clone(), |el, keybinding_target| {
|
||||
el.context(keybinding_target.clone())
|
||||
})
|
||||
.action("Watch expression", WatchExpression.boxed_clone())
|
||||
.action("Watch Expression", WatchExpression.boxed_clone())
|
||||
}))
|
||||
})
|
||||
},
|
||||
|
@ -452,18 +452,22 @@ impl Render for Console {
|
|||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let query_focus_handle = self.query_bar.focus_handle(cx);
|
||||
self.update_output(window, cx);
|
||||
|
||||
v_flex()
|
||||
.track_focus(&self.focus_handle)
|
||||
.key_context("DebugConsole")
|
||||
.on_action(cx.listener(Self::evaluate))
|
||||
.on_action(cx.listener(Self::watch_expression))
|
||||
.size_full()
|
||||
.border_2()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(self.render_console(cx))
|
||||
.when(self.is_running(cx), |this| {
|
||||
this.child(Divider::horizontal()).child(
|
||||
h_flex()
|
||||
.on_action(cx.listener(Self::previous_query))
|
||||
.on_action(cx.listener(Self::next_query))
|
||||
.p_1()
|
||||
.gap_1()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(self.render_query_bar(cx))
|
||||
|
@ -474,6 +478,9 @@ impl Render for Console {
|
|||
.on_click(move |_, window, cx| {
|
||||
window.dispatch_action(Box::new(Confirm), cx)
|
||||
})
|
||||
.layer(ui::ElevationIndex::ModalSurface)
|
||||
.size(ui::ButtonSize::Compact)
|
||||
.child(Label::new("Evaluate"))
|
||||
.tooltip({
|
||||
let query_focus_handle = query_focus_handle.clone();
|
||||
|
||||
|
@ -486,10 +493,7 @@ impl Render for Console {
|
|||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.layer(ui::ElevationIndex::ModalSurface)
|
||||
.size(ui::ButtonSize::Compact)
|
||||
.child(Label::new("Evaluate")),
|
||||
}),
|
||||
self.render_submit_menu(
|
||||
ElementId::Name("split-button-right-confirm-button".into()),
|
||||
Some(query_focus_handle.clone()),
|
||||
|
@ -499,7 +503,6 @@ impl Render for Console {
|
|||
)),
|
||||
)
|
||||
})
|
||||
.border_2()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,8 @@ use project::debugger::{MemoryCell, dap_command::DataBreakpointContext, session:
|
|||
use settings::Settings;
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
ActiveTheme, AnyElement, App, Color, Context, ContextMenu, Div, Divider, DropdownMenu, Element,
|
||||
FluentBuilder, Icon, IconName, InteractiveElement, IntoElement, Label, LabelCommon,
|
||||
ParentElement, Pixels, PopoverMenuHandle, Render, Scrollbar, ScrollbarState, SharedString,
|
||||
StatefulInteractiveElement, Styled, TextSize, Tooltip, Window, div, h_flex, px, v_flex,
|
||||
ContextMenu, Divider, DropdownMenu, FluentBuilder, IntoElement, PopoverMenuHandle, Render,
|
||||
Scrollbar, ScrollbarState, StatefulInteractiveElement, Tooltip, prelude::*,
|
||||
};
|
||||
use workspace::Workspace;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue