debugger_ui: Improve some elements of the UI (#43344)
- In the launch tab of the new session mode, I've switched it to use the `InputField` component instead given that had all that we needed already. Allows for removing a good chunk of editor-related code - Also in the launch tab, added support for keyboard navigation between all of the elements there (dropdown, inputs, and switch component) - Added some simple an empty state treatment for the breakpoint column when there are none set https://github.com/user-attachments/assets/a441aa8a-360b-4e38-839f-786315a8a235 Release Notes: - debugger: Made the input elements within the launch tab in the new session modal keyboard navigable˙.
This commit is contained in:
Generated
+1
@@ -4770,6 +4770,7 @@ dependencies = [
|
||||
"tree-sitter-go",
|
||||
"tree-sitter-json",
|
||||
"ui",
|
||||
"ui_input",
|
||||
"unindent",
|
||||
"util",
|
||||
"workspace",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<Self>,
|
||||
) -> 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<Editor>, 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<Editor>,
|
||||
cwd: Entity<Editor>,
|
||||
program: Entity<InputField>,
|
||||
cwd: Entity<InputField>,
|
||||
stop_on_entry: ToggleState,
|
||||
save_to_debug_json: ToggleState,
|
||||
}
|
||||
|
||||
impl ConfigureMode {
|
||||
pub(super) fn new(window: &mut Window, cx: &mut App) -> Entity<Self> {
|
||||
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<Self>) {
|
||||
window.focus_next();
|
||||
}
|
||||
|
||||
fn on_tab_prev(
|
||||
&mut self,
|
||||
_: &menu::SelectPrevious,
|
||||
window: &mut Window,
|
||||
_: &mut Context<Self>,
|
||||
) {
|
||||
window.focus_prev();
|
||||
}
|
||||
|
||||
fn render(
|
||||
&mut self,
|
||||
adapter_menu: DropdownMenu,
|
||||
window: &mut Window,
|
||||
_: &mut Window,
|
||||
cx: &mut ui::Context<Self>,
|
||||
) -> 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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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<Arc<str>>, 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<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> 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))
|
||||
|
||||
Reference in New Issue
Block a user