debugger: Add refinements to the UI (#35940)

Danilo Leal created

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

Change summary

assets/icons/debug_disabled_log_breakpoint.svg            |   4 
assets/icons/debug_ignore_breakpoints.svg                 |   4 
assets/icons/debug_log_breakpoint.svg                     |   2 
crates/debugger_ui/src/debugger_panel.rs                  | 143 ++--
crates/debugger_ui/src/session/running.rs                 |  21 
crates/debugger_ui/src/session/running/breakpoint_list.rs | 266 +++++---
crates/debugger_ui/src/session/running/console.rs         |  15 
crates/debugger_ui/src/session/running/memory_view.rs     |   6 
8 files changed, 260 insertions(+), 201 deletions(-)

Detailed changes

assets/icons/debug_disabled_log_breakpoint.svg 🔗

@@ -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>

assets/icons/debug_ignore_breakpoints.svg 🔗

@@ -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>

assets/icons/debug_log_breakpoint.svg 🔗

@@ -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>

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -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),
+                                    )
+                                }
+                            }),
                     )
                 }
             })

crates/debugger_ui/src/session/running.rs 🔗

@@ -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()
+                    .track_focus(&focus_handle)
                     .group(pane_group_id.clone())
+                    .pl_1p5()
+                    .pr_1()
                     .justify_between()
-                    .bg(cx.theme().colors().tab_bar_background)
                     .border_b_1()
-                    .px_2()
                     .border_color(cx.theme().colors().border)
-                    .track_focus(&focus_handle)
+                    .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())
     }
 }

crates/debugger_ui/src/session/running/breakpoint_list.rs 🔗

@@ -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()

crates/debugger_ui/src/session/running/console.rs 🔗

@@ -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()
     }
 }
 

crates/debugger_ui/src/session/running/memory_view.rs 🔗

@@ -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;