From 136468a4df71d31806276f56f9e0448cea6c13e6 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Tue, 9 Sep 2025 09:36:12 -0300 Subject: [PATCH] keymap editor: Add some adjustments to the UI (#37819) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Makes the keymap editor search container more consistent with the project & file search corresponding elements - Changes the keymap editor menu item in the user menu be called "Keymap Editor", as opposed to "Key Binding", to match with the tab and action name Design note: Still a bit unsure about the extra space on the right for the keymap editor. This makes it way more consistent with the other search views, but it also just feels like space that could be used. On the other hand, though, it's very unlikely anyone will ever use more than 30% of the search bar width as search queries here are likely pretty short; definitely much shorter than project search queries. Screenshot 2025-09-09 at 1  02@2x Release Notes: - N/A --- crates/keymap_editor/src/keymap_editor.rs | 283 ++++++++++-------- .../src/ui_components/keystroke_input.rs | 30 +- crates/search/src/project_search.rs | 5 +- crates/search/src/search_bar.rs | 4 +- crates/title_bar/src/title_bar.rs | 2 +- crates/ui_input/src/ui_input.rs | 2 +- 6 files changed, 178 insertions(+), 148 deletions(-) diff --git a/crates/keymap_editor/src/keymap_editor.rs b/crates/keymap_editor/src/keymap_editor.rs index a8e356276b31e1d6daa79fdf85f6ff3566f9749d..7e0a96d47a52b7051793017a2d5f68d64bfdcd65 100644 --- a/crates/keymap_editor/src/keymap_editor.rs +++ b/crates/keymap_editor/src/keymap_editor.rs @@ -1576,33 +1576,6 @@ impl Render for KeymapEditor { .child( h_flex() .gap_2() - .child( - right_click_menu("open-keymap-menu") - .menu(|window, cx| { - ContextMenu::build(window, cx, |menu, _, _| { - menu.header("Open Keymap JSON") - .action("User", zed_actions::OpenKeymap.boxed_clone()) - .action("Zed Default", zed_actions::OpenDefaultKeymap.boxed_clone()) - .action("Vim Default", vim::OpenDefaultKeymap.boxed_clone()) - }) - }) - .anchor(gpui::Corner::TopLeft) - .trigger(|open, _, _| - IconButton::new( - "OpenKeymapJsonButton", - IconName::Json - ) - .shape(ui::IconButtonShape::Square) - .when(!open, |this| - this.tooltip(move |window, cx| { - Tooltip::with_meta("Open Keymap JSON", Some(&zed_actions::OpenKeymap),"Right click to view more options", window, cx) - }) - ) - .on_click(|_, window, cx| { - window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx); - }) - ) - ) .child( div() .key_context({ @@ -1617,73 +1590,139 @@ impl Render for KeymapEditor { .py_1() .border_1() .border_color(theme.colors().border) - .rounded_lg() + .rounded_md() .child(self.filter_editor.clone()), ) .child( - IconButton::new( - "KeymapEditorToggleFiltersIcon", - IconName::Keyboard, - ) - .shape(ui::IconButtonShape::Square) - .tooltip({ - let focus_handle = focus_handle.clone(); - - move |window, cx| { - Tooltip::for_action_in( - "Search by Keystroke", - &ToggleKeystrokeSearch, - &focus_handle.clone(), - window, - cx, + h_flex() + .gap_1() + .min_w_64() + .child( + IconButton::new( + "KeymapEditorToggleFiltersIcon", + IconName::Keyboard, ) - } - }) - .toggle_state(matches!( - self.search_mode, - SearchMode::KeyStroke { .. } - )) - .on_click(|_, window, cx| { - window.dispatch_action(ToggleKeystrokeSearch.boxed_clone(), cx); - }), - ) - .child( - IconButton::new("KeymapEditorConflictIcon", IconName::Warning) - .shape(ui::IconButtonShape::Square) - .when( - self.keybinding_conflict_state.any_user_binding_conflicts(), - |this| { - this.indicator(Indicator::dot().color(Color::Warning)) - }, + .icon_size(IconSize::Small) + .tooltip({ + let focus_handle = focus_handle.clone(); + + move |window, cx| { + Tooltip::for_action_in( + "Search by Keystroke", + &ToggleKeystrokeSearch, + &focus_handle.clone(), + window, + cx, + ) + } + }) + .toggle_state(matches!( + self.search_mode, + SearchMode::KeyStroke { .. } + )) + .on_click(|_, window, cx| { + window.dispatch_action( + ToggleKeystrokeSearch.boxed_clone(), + cx, + ); + }), ) - .tooltip({ - let filter_state = self.filter_state; - let focus_handle = focus_handle.clone(); - - move |window, cx| { - Tooltip::for_action_in( - match filter_state { - FilterState::All => "Show Conflicts", - FilterState::Conflicts => "Hide Conflicts", + .child( + IconButton::new("KeymapEditorConflictIcon", IconName::Warning) + .icon_size(IconSize::Small) + .when( + self.keybinding_conflict_state + .any_user_binding_conflicts(), + |this| { + this.indicator( + Indicator::dot().color(Color::Warning), + ) }, - &ToggleConflictFilter, - &focus_handle.clone(), - window, - cx, ) - } - }) - .selected_icon_color(Color::Warning) - .toggle_state(matches!( - self.filter_state, - FilterState::Conflicts - )) - .on_click(|_, window, cx| { - window.dispatch_action( - ToggleConflictFilter.boxed_clone(), - cx, - ); - }), + .tooltip({ + let filter_state = self.filter_state; + let focus_handle = focus_handle.clone(); + + move |window, cx| { + Tooltip::for_action_in( + match filter_state { + FilterState::All => "Show Conflicts", + FilterState::Conflicts => { + "Hide Conflicts" + } + }, + &ToggleConflictFilter, + &focus_handle.clone(), + window, + cx, + ) + } + }) + .selected_icon_color(Color::Warning) + .toggle_state(matches!( + self.filter_state, + FilterState::Conflicts + )) + .on_click(|_, window, cx| { + window.dispatch_action( + ToggleConflictFilter.boxed_clone(), + cx, + ); + }), + ) + .child( + div() + .ml_1() + .pl_2() + .border_l_1() + .border_color(cx.theme().colors().border_variant) + .child( + right_click_menu("open-keymap-menu") + .menu(|window, cx| { + ContextMenu::build(window, cx, |menu, _, _| { + menu.header("Open Keymap JSON") + .action( + "User", + zed_actions::OpenKeymap.boxed_clone(), + ) + .action( + "Zed Default", + zed_actions::OpenDefaultKeymap + .boxed_clone(), + ) + .action( + "Vim Default", + vim::OpenDefaultKeymap.boxed_clone(), + ) + }) + }) + .anchor(gpui::Corner::TopLeft) + .trigger(|open, _, _| { + IconButton::new( + "OpenKeymapJsonButton", + IconName::Json, + ) + .icon_size(IconSize::Small) + .when(!open, |this| { + this.tooltip(move |window, cx| { + Tooltip::with_meta( + "Open keymap.json", + Some(&zed_actions::OpenKeymap), + "Right click to view more options", + window, + cx, + ) + }) + }) + .on_click(|_, window, cx| { + window.dispatch_action( + zed_actions::OpenKeymap.boxed_clone(), + cx, + ); + }) + }), + ), + ) ), ) .when_some( @@ -1694,48 +1733,42 @@ impl Render for KeymapEditor { |this, exact_match| { this.child( h_flex() - .map(|this| { - if self - .keybinding_conflict_state - .any_user_binding_conflicts() - { - this.pr(rems_from_px(54.)) - } else { - this.pr_7() - } - }) .gap_2() .child(self.keystroke_editor.clone()) .child( - IconButton::new( - "keystrokes-exact-match", - IconName::CaseSensitive, - ) - .tooltip({ - let keystroke_focus_handle = - self.keystroke_editor.read(cx).focus_handle(cx); - - move |window, cx| { - Tooltip::for_action_in( - "Toggle Exact Match Mode", - &ToggleExactKeystrokeMatching, - &keystroke_focus_handle, - window, - cx, + h_flex() + .min_w_64() + .child( + IconButton::new( + "keystrokes-exact-match", + IconName::CaseSensitive, ) - } - }) - .shape(IconButtonShape::Square) - .toggle_state(exact_match) - .on_click( - cx.listener(|_, _, window, cx| { - window.dispatch_action( - ToggleExactKeystrokeMatching.boxed_clone(), - cx, - ); - }), - ), - ), + .tooltip({ + let keystroke_focus_handle = + self.keystroke_editor.read(cx).focus_handle(cx); + + move |window, cx| { + Tooltip::for_action_in( + "Toggle Exact Match Mode", + &ToggleExactKeystrokeMatching, + &keystroke_focus_handle, + window, + cx, + ) + } + }) + .shape(IconButtonShape::Square) + .toggle_state(exact_match) + .on_click( + cx.listener(|_, _, window, cx| { + window.dispatch_action( + ToggleExactKeystrokeMatching.boxed_clone(), + cx, + ); + }), + ), + ), + ) ) }, ), diff --git a/crates/keymap_editor/src/ui_components/keystroke_input.rs b/crates/keymap_editor/src/ui_components/keystroke_input.rs index e6b2ff710555403048c56bb1f249d71971d0e91b..e264df3b62bc3c5c78acc38ed906e81837dfbf94 100644 --- a/crates/keymap_editor/src/ui_components/keystroke_input.rs +++ b/crates/keymap_editor/src/ui_components/keystroke_input.rs @@ -461,7 +461,7 @@ impl Render for KeystrokeInput { let is_focused = self.outer_focus_handle.contains_focused(window, cx); let is_recording = self.is_recording(window); - let horizontal_padding = rems_from_px(64.); + let width = rems_from_px(64.); let recording_bg_color = colors .editor_background @@ -528,6 +528,9 @@ impl Render for KeystrokeInput { h_flex() .id("keystroke-input") .track_focus(&self.outer_focus_handle) + .key_context(Self::key_context()) + .on_action(cx.listener(Self::start_recording)) + .on_action(cx.listener(Self::clear_keystrokes)) .py_2() .px_3() .gap_2() @@ -535,7 +538,7 @@ impl Render for KeystrokeInput { .w_full() .flex_1() .justify_between() - .rounded_sm() + .rounded_md() .overflow_hidden() .map(|this| { if is_recording { @@ -545,16 +548,16 @@ impl Render for KeystrokeInput { } }) .border_1() - .border_color(colors.border_variant) - .when(is_focused, |parent| { - parent.border_color(colors.border_focused) + .map(|this| { + if is_focused { + this.border_color(colors.border_focused) + } else { + this.border_color(colors.border_variant) + } }) - .key_context(Self::key_context()) - .on_action(cx.listener(Self::start_recording)) - .on_action(cx.listener(Self::clear_keystrokes)) .child( h_flex() - .w(horizontal_padding) + .w(width) .gap_0p5() .justify_start() .flex_none() @@ -573,14 +576,13 @@ impl Render for KeystrokeInput { .id("keystroke-input-inner") .track_focus(&self.inner_focus_handle) .on_modifiers_changed(cx.listener(Self::on_modifiers_changed)) - .size_full() .when(!self.search, |this| { this.focus(|mut style| { style.border_color = Some(colors.border_focused); style }) }) - .w_full() + .size_full() .min_w_0() .justify_center() .flex_wrap() @@ -589,7 +591,7 @@ impl Render for KeystrokeInput { ) .child( h_flex() - .w(horizontal_padding) + .w(width) .gap_0p5() .justify_end() .flex_none() @@ -641,9 +643,7 @@ impl Render for KeystrokeInput { "Clear Keystrokes", &ClearKeystrokes, )) - .when(!is_recording || !is_focused, |this| { - this.icon_color(Color::Muted) - }) + .when(!is_focused, |this| this.icon_color(Color::Muted)) .on_click(cx.listener(|this, _event, window, cx| { this.clear_keystrokes(&ClearKeystrokes, window, cx); })), diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 33458a3a88fb717ba047b57564c8804f7ebea928..80ed0958b747320481636f1d583aed1298d012c0 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -36,10 +36,7 @@ use std::{ pin::pin, sync::Arc, }; -use ui::{ - Icon, IconButton, IconButtonShape, IconName, KeyBinding, Label, LabelCommon, LabelSize, - Toggleable, Tooltip, h_flex, prelude::*, utils::SearchInputWidth, v_flex, -}; +use ui::{IconButtonShape, KeyBinding, Toggleable, Tooltip, prelude::*, utils::SearchInputWidth}; use util::{ResultExt as _, paths::PathMatcher}; use workspace::{ DeploySearch, ItemNavHistory, NewSearch, ToolbarItemEvent, ToolbarItemLocation, diff --git a/crates/search/src/search_bar.rs b/crates/search/src/search_bar.rs index 44f6b3fdd21388f37cfbe2011e5a3e530b0be654..631b96b69f3b9aedd4ed299953edf6e63665ba99 100644 --- a/crates/search/src/search_bar.rs +++ b/crates/search/src/search_bar.rs @@ -41,15 +41,15 @@ pub(super) fn render_action_button( pub(crate) fn input_base_styles(border_color: Hsla, map: impl FnOnce(Div) -> Div) -> Div { h_flex() - .min_w_32() .map(map) + .min_w_32() .h_8() .pl_2() .pr_1() .py_1() .border_1() .border_color(border_color) - .rounded_lg() + .rounded_md() } pub(crate) fn render_text_input( diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index 009092993753f2510cba7da0769eefcf347a499e..e15e7ad46dd18c41a1c15fa927352b44184530f7 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -693,7 +693,7 @@ impl TitleBar { "Settings Profiles", zed_actions::settings_profile_selector::Toggle.boxed_clone(), ) - .action("Key Bindings", Box::new(keymap_editor::OpenKeymapEditor)) + .action("Keymap Editor", Box::new(keymap_editor::OpenKeymapEditor)) .action( "Themes…", zed_actions::theme_selector::Toggle::default().boxed_clone(), diff --git a/crates/ui_input/src/ui_input.rs b/crates/ui_input/src/ui_input.rs index 02f8ef89f3cb76d8ebb8f2468d9619c931ab9b9d..39a701c8e8d5c839204a9df6d33f307cc4214289 100644 --- a/crates/ui_input/src/ui_input.rs +++ b/crates/ui_input/src/ui_input.rs @@ -168,7 +168,7 @@ impl Render for SingleLineInput { .py_1p5() .flex_grow() .text_color(style.text_color) - .rounded_sm() + .rounded_md() .bg(style.background_color) .border_1() .border_color(style.border_color)