diff --git a/Cargo.lock b/Cargo.lock index bfce6ab287c81852f558ea064097443c1131d9a7..bea1424b704eb9e3bc07ddfa2e7b6de817687a72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4770,6 +4770,7 @@ dependencies = [ "tree-sitter-go", "tree-sitter-json", "ui", + "ui_input", "unindent", "util", "workspace", diff --git a/crates/debugger_ui/Cargo.toml b/crates/debugger_ui/Cargo.toml index c1a0657c0ed93508acb330a98dc6d1c1ee91c570..325bcc300ae637ab46c36b7a3e7875e197f7d3d2 100644 --- a/crates/debugger_ui/Cargo.toml +++ b/crates/debugger_ui/Cargo.toml @@ -70,6 +70,7 @@ theme.workspace = true tree-sitter-json.workspace = true tree-sitter.workspace = true ui.workspace = true +ui_input.workspace = true unindent = { workspace = true, optional = true } util.workspace = true workspace.workspace = true diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index f2f8b5be32c696c61a50c71090f130fcf34ef271..0a5dc744cde6ba053a2c5a5100538100a7d6a49b 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -1692,7 +1692,7 @@ impl Render for DebugPanel { .child( Button::new("spawn-new-session-empty-state", "New Session") .icon(IconName::Plus) - .icon_size(IconSize::XSmall) + .icon_size(IconSize::Small) .icon_color(Color::Muted) .icon_position(IconPosition::Start) .on_click(|_, window, cx| { @@ -1702,8 +1702,7 @@ impl Render for DebugPanel { .child( Button::new("edit-debug-settings", "Edit debug.json") .icon(IconName::Code) - .icon_size(IconSize::XSmall) - .color(Color::Muted) + .icon_size(IconSize::Small) .icon_color(Color::Muted) .icon_position(IconPosition::Start) .on_click(|_, window, cx| { @@ -1716,8 +1715,7 @@ impl Render for DebugPanel { .child( Button::new("open-debugger-docs", "Debugger Docs") .icon(IconName::Book) - .color(Color::Muted) - .icon_size(IconSize::XSmall) + .icon_size(IconSize::Small) .icon_color(Color::Muted) .icon_position(IconPosition::Start) .on_click(|_, _, cx| cx.open_url("https://zed.dev/docs/debugger")), @@ -1728,8 +1726,7 @@ impl Render for DebugPanel { "Debugger Extensions", ) .icon(IconName::Blocks) - .color(Color::Muted) - .icon_size(IconSize::XSmall) + .icon_size(IconSize::Small) .icon_color(Color::Muted) .icon_position(IconPosition::Start) .on_click(|_, window, cx| { @@ -1746,6 +1743,15 @@ impl Render for DebugPanel { }), ); + let has_breakpoints = self + .project + .read(cx) + .breakpoint_store() + .read(cx) + .all_source_breakpoints(cx) + .values() + .any(|breakpoints| !breakpoints.is_empty()); + let breakpoint_list = v_flex() .group("base-breakpoint-list") .when_else( @@ -1769,7 +1775,18 @@ impl Render for DebugPanel { ), ), ) - .child(self.breakpoint_list.clone()); + .when(has_breakpoints, |this| { + this.child(self.breakpoint_list.clone()) + }) + .when(!has_breakpoints, |this| { + this.child( + v_flex().size_full().items_center().justify_center().child( + Label::new("No Breakpoints Set") + .size(LabelSize::Small) + .color(Color::Muted), + ), + ) + }); this.child( v_flex() diff --git a/crates/debugger_ui/src/new_process_modal.rs b/crates/debugger_ui/src/new_process_modal.rs index 4460284fadc8f43c86400d1f47d3e9d68c42b39b..40187cef9cc55cb4192a3cea773f42dca15a2571 100644 --- a/crates/debugger_ui/src/new_process_modal.rs +++ b/crates/debugger_ui/src/new_process_modal.rs @@ -12,23 +12,22 @@ use tasks_ui::{TaskOverrides, TasksModal}; use dap::{ DapRegistry, DebugRequest, TelemetrySpawnLocation, adapters::DebugAdapterName, send_telemetry, }; -use editor::{Editor, EditorElement, EditorStyle}; +use editor::Editor; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ Action, App, AppContext, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, - KeyContext, Render, Subscription, Task, TextStyle, WeakEntity, + KeyContext, Render, Subscription, Task, WeakEntity, }; use itertools::Itertools as _; use picker::{Picker, PickerDelegate, highlighted_match_with_paths::HighlightedMatch}; use project::{DebugScenarioContext, Project, TaskContexts, TaskSourceKind, task_store::TaskStore}; -use settings::Settings; use task::{DebugScenario, RevealTarget, VariableName, ZedDebugConfig}; -use theme::ThemeSettings; use ui::{ ContextMenu, DropdownMenu, FluentBuilder, IconWithIndicator, Indicator, KeyBinding, ListItem, ListItemSpacing, Switch, SwitchLabelPosition, ToggleButtonGroup, ToggleButtonSimple, ToggleState, Tooltip, prelude::*, }; +use ui_input::InputField; use util::{ResultExt, debug_panic, rel_path::RelPath, shell::ShellKind}; use workspace::{ModalView, Workspace, notifications::DetachAndPromptErr, pane}; @@ -448,7 +447,7 @@ impl NewProcessModal { &mut self, window: &mut Window, cx: &mut Context, - ) -> ui::DropdownMenu { + ) -> DropdownMenu { let workspace = self.workspace.clone(); let weak = cx.weak_entity(); let active_buffer = self.task_contexts(cx).and_then(|tc| { @@ -508,6 +507,13 @@ impl NewProcessModal { menu }), ) + .style(ui::DropdownStyle::Outlined) + .tab_index(0) + .attach(gpui::Corner::BottomLeft) + .offset(gpui::Point { + x: px(0.0), + y: px(2.0), + }) } } @@ -540,44 +546,6 @@ impl Focusable for NewProcessMode { } } -fn render_editor(editor: &Entity, window: &mut Window, cx: &App) -> impl IntoElement { - let settings = ThemeSettings::get_global(cx); - let theme = cx.theme(); - - let text_style = TextStyle { - color: cx.theme().colors().text, - font_family: settings.buffer_font.family.clone(), - font_features: settings.buffer_font.features.clone(), - font_size: settings.buffer_font_size(cx).into(), - font_weight: settings.buffer_font.weight, - line_height: relative(settings.buffer_line_height.value()), - background_color: Some(theme.colors().editor_background), - ..Default::default() - }; - - let element = EditorElement::new( - editor, - EditorStyle { - background: theme.colors().editor_background, - local_player: theme.players().local(), - text: text_style, - ..Default::default() - }, - ); - - div() - .rounded_md() - .p_1() - .border_1() - .border_color(theme.colors().border_variant) - .when( - editor.focus_handle(cx).contains_focused(window, cx), - |this| this.border_color(theme.colors().border_focused), - ) - .child(element) - .bg(theme.colors().editor_background) -} - impl Render for NewProcessModal { fn render( &mut self, @@ -788,22 +756,26 @@ impl RenderOnce for AttachMode { #[derive(Clone)] pub(super) struct ConfigureMode { - program: Entity, - cwd: Entity, + program: Entity, + cwd: Entity, stop_on_entry: ToggleState, save_to_debug_json: ToggleState, } impl ConfigureMode { pub(super) fn new(window: &mut Window, cx: &mut App) -> Entity { - let program = cx.new(|cx| Editor::single_line(window, cx)); - program.update(cx, |this, cx| { - this.set_placeholder_text("ENV=Zed ~/bin/program --option", window, cx); + let program = cx.new(|cx| { + InputField::new(window, cx, "ENV=Zed ~/bin/program --option") + .label("Program") + .tab_stop(true) + .tab_index(1) }); - let cwd = cx.new(|cx| Editor::single_line(window, cx)); - cwd.update(cx, |this, cx| { - this.set_placeholder_text("Ex: $ZED_WORKTREE_ROOT", window, cx); + let cwd = cx.new(|cx| { + InputField::new(window, cx, "Ex: $ZED_WORKTREE_ROOT") + .label("Working Directory") + .tab_stop(true) + .tab_index(2) }); cx.new(|_| Self { @@ -815,9 +787,9 @@ impl ConfigureMode { } fn load(&mut self, cwd: PathBuf, window: &mut Window, cx: &mut App) { - self.cwd.update(cx, |editor, cx| { - if editor.is_empty(cx) { - editor.set_text(cwd.to_string_lossy(), window, cx); + self.cwd.update(cx, |input_field, cx| { + if input_field.is_empty(cx) { + input_field.set_text(cwd.to_string_lossy(), window, cx); } }); } @@ -868,49 +840,44 @@ impl ConfigureMode { } } + fn on_tab(&mut self, _: &menu::SelectNext, window: &mut Window, _: &mut Context) { + window.focus_next(); + } + + fn on_tab_prev( + &mut self, + _: &menu::SelectPrevious, + window: &mut Window, + _: &mut Context, + ) { + window.focus_prev(); + } + fn render( &mut self, adapter_menu: DropdownMenu, - window: &mut Window, + _: &mut Window, cx: &mut ui::Context, ) -> impl IntoElement { v_flex() + .tab_group() + .track_focus(&self.program.focus_handle(cx)) + .on_action(cx.listener(Self::on_tab)) + .on_action(cx.listener(Self::on_tab_prev)) .p_2() .w_full() - .gap_2() - .track_focus(&self.program.focus_handle(cx)) + .gap_3() .child( h_flex() - .gap_2() - .child( - Label::new("Debugger") - .size(LabelSize::Small) - .color(Color::Muted), - ) + .gap_1() + .child(Label::new("Debugger:").color(Color::Muted)) .child(adapter_menu), ) - .child( - v_flex() - .gap_0p5() - .child( - Label::new("Program") - .size(LabelSize::Small) - .color(Color::Muted), - ) - .child(render_editor(&self.program, window, cx)), - ) - .child( - v_flex() - .gap_0p5() - .child( - Label::new("Working Directory") - .size(LabelSize::Small) - .color(Color::Muted), - ) - .child(render_editor(&self.cwd, window, cx)), - ) + .child(self.program.clone()) + .child(self.cwd.clone()) .child( Switch::new("debugger-stop-on-entry", self.stop_on_entry) + .tab_index(3_isize) .label("Stop on Entry") .label_position(SwitchLabelPosition::Start) .label_size(LabelSize::Default) diff --git a/crates/debugger_ui/src/session/running/breakpoint_list.rs b/crates/debugger_ui/src/session/running/breakpoint_list.rs index 0a02a5a8e4197bf6b959a592b6e3d3da92c00846..ca50f67c9236d19a9f04f327091eb383ab72e122 100644 --- a/crates/debugger_ui/src/session/running/breakpoint_list.rs +++ b/crates/debugger_ui/src/session/running/breakpoint_list.rs @@ -1407,7 +1407,6 @@ impl RenderOnce for BreakpointOptionsStrip { h_flex() .gap_px() - .mr_3() // Space to avoid overlapping with the scrollbar .justify_end() .when(has_logs || self.is_selected, |this| { this.child( diff --git a/crates/ui_input/src/input_field.rs b/crates/ui_input/src/input_field.rs index 9e8c519ca9acc68c0d968f099f62ad336ee0754a..2bae8c172dcecbc94aa591297831c4f43279197b 100644 --- a/crates/ui_input/src/input_field.rs +++ b/crates/ui_input/src/input_field.rs @@ -120,6 +120,11 @@ impl InputField { self.editor().read(cx).text(cx) } + pub fn clear(&self, window: &mut Window, cx: &mut App) { + self.editor() + .update(cx, |editor, cx| editor.clear(window, cx)) + } + pub fn set_text(&self, text: impl Into>, window: &mut Window, cx: &mut App) { self.editor() .update(cx, |editor, cx| editor.set_text(text, window, cx)) @@ -127,7 +132,8 @@ impl InputField { } impl Render for InputField { - fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + let editor = self.editor.clone(); let settings = ThemeSettings::get_global(cx); let theme_color = cx.theme().colors(); @@ -206,6 +212,10 @@ impl Render for InputField { .bg(style.background_color) .border_1() .border_color(style.border_color) + .when( + editor.focus_handle(cx).contains_focused(window, cx), + |this| this.border_color(theme_color.border_focused), + ) .when_some(self.start_icon, |this, icon| { this.gap_1() .child(Icon::new(icon).size(IconSize::Small).color(Color::Muted))