keymap editor: Add some adjustments to the UI (#37819)

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

<img width="600" height="552" alt="Screenshot 2025-09-09 at 1  02@2x"
src="https://github.com/user-attachments/assets/9825a129-2c5a-4852-9837-c586b88e9332"
/>


Release Notes:

- N/A
This commit is contained in:
Danilo Leal
2025-09-09 09:36:12 -03:00
committed by GitHub
parent adf43d691a
commit 136468a4df
6 changed files with 178 additions and 148 deletions
+158 -125
View File
@@ -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))
},
)
.tooltip({
let filter_state = self.filter_state;
let focus_handle = focus_handle.clone();
.icon_size(IconSize::Small)
.tooltip({
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,
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,
);
}),
)
.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),
)
},
)
}
})
.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,
);
}),
),
),
)
)
},
),
@@ -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);
})),
+1 -4
View File
@@ -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,
+2 -2
View File
@@ -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(
+1 -1
View File
@@ -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(),
+1 -1
View File
@@ -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)