which_key: Fix Windows keybinding display in Which Key (#63349)
On Windows, Zed shows some shortcuts using the keys a person presses. For example, it displays `ctrl-@` as `Ctrl-Shift-2`. Which Key was dropping that Windows-specific label and showing `Ctrl-@`, while the command palette and keymap editor showed `Ctrl-Shift-2`. This PR makes Which Key use the same shortcut labels as the rest of Zed. **Before:** Which Key (Shows `Ctrl-@`): <p> <img height="70" alt="image" src="https://github.com/user-attachments/assets/9272ba29-1ebc-4329-8bd3-ec42937766c8" /> </p> Keymap Editor (Shows `Ctrl-Shift-2` instead of `Ctrl-@`): <p> <img height="50" alt="image" src="https://github.com/user-attachments/assets/3c36d887-2cb8-45fc-9672-6a8ea2ba2f4d" /> </p> Command Palette (Shows `Ctrl-Shift-2` instead of `Ctrl-@`): <p> <img height="70" alt="image" src="https://github.com/user-attachments/assets/2619a84b-341d-4ee4-89fb-4db62c3569dc" /> </p> **After:** <p> <img height="70" alt="image" src="https://github.com/user-attachments/assets/212f4d6e-e07d-4857-a0e7-e526611f2fcb" /> <p> Release Notes: - Fixed inconsistent shortcut labels in Which Key on Windows.
This commit is contained in:
1 parent
0b1f4f4020
commit
0403df17a4
1 file changed
+55
-26
@@ -2,15 +2,15 @@
|
||||
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
App, Context, DismissEvent, EventEmitter, FocusHandle, Focusable, FontWeight, Keystroke,
|
||||
ScrollHandle, Subscription, WeakEntity, Window,
|
||||
App, Context, DismissEvent, EventEmitter, FocusHandle, Focusable, FontWeight,
|
||||
KeybindingKeystroke, ScrollHandle, Subscription, WeakEntity, Window,
|
||||
};
|
||||
use settings::Settings;
|
||||
use std::collections::HashMap;
|
||||
use theme_settings::ThemeSettings;
|
||||
use ui::{
|
||||
Divider, DividerColor, DynamicSpacing, LabelSize, WithScrollbar, prelude::*,
|
||||
text_for_keystrokes,
|
||||
text_for_keybinding_keystrokes, text_for_keystrokes,
|
||||
};
|
||||
use workspace::{ModalView, Workspace};
|
||||
|
||||
@@ -69,30 +69,22 @@ impl WhichKeyModal {
|
||||
|
||||
let mut binding_data = bindings
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
// Map to keystrokes
|
||||
(
|
||||
binding
|
||||
.keystrokes()
|
||||
.iter()
|
||||
.map(|k| k.inner().to_owned())
|
||||
.collect::<Vec<_>>(),
|
||||
binding.action(),
|
||||
)
|
||||
})
|
||||
.map(|binding| (binding.keystrokes().to_vec(), binding.action()))
|
||||
.filter(|(keystrokes, _action)| {
|
||||
// Check if this binding matches any filtered keystroke pattern
|
||||
!FILTERED_KEYSTROKES.iter().any(|filtered| {
|
||||
keystrokes.len() >= filtered.len()
|
||||
&& keystrokes[..filtered.len()] == filtered[..]
|
||||
&& keystrokes[..filtered.len()]
|
||||
.iter()
|
||||
.map(|keystroke| keystroke.inner())
|
||||
.eq(filtered.iter())
|
||||
})
|
||||
})
|
||||
.map(|(keystrokes, action)| {
|
||||
// Map to remaining keystrokes and action name
|
||||
let remaining_keystrokes = keystrokes[pending_keys.len()..].to_vec();
|
||||
.filter_map(|(keystrokes, action)| {
|
||||
let remaining_keystrokes = keystrokes.get(pending_keys.len()..)?.to_vec();
|
||||
let action_name: SharedString =
|
||||
command_palette::humanize_action_name(action.name()).into();
|
||||
(remaining_keystrokes, action_name)
|
||||
Some((remaining_keystrokes, action_name))
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -118,8 +110,8 @@ impl WhichKeyModal {
|
||||
}
|
||||
|
||||
// Finally sort by text length, then lexicographically for full stability
|
||||
let text_a = text_for_keystrokes(keystrokes_a, cx);
|
||||
let text_b = text_for_keystrokes(keystrokes_b, cx);
|
||||
let text_a = text_for_keybinding_keystrokes(keystrokes_a, cx);
|
||||
let text_b = text_for_keybinding_keystrokes(keystrokes_b, cx);
|
||||
let text_len_cmp = text_a.len().cmp(&text_b.len());
|
||||
if text_len_cmp != std::cmp::Ordering::Equal {
|
||||
return text_len_cmp;
|
||||
@@ -130,7 +122,12 @@ impl WhichKeyModal {
|
||||
self.pending_keys = text_for_keystrokes(&pending_keys, cx).into();
|
||||
self.bindings = binding_data
|
||||
.into_iter()
|
||||
.map(|(keystrokes, action)| (text_for_keystrokes(&keystrokes, cx).into(), action))
|
||||
.map(|(keystrokes, action)| {
|
||||
(
|
||||
text_for_keybinding_keystrokes(&keystrokes, cx).into(),
|
||||
action,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
@@ -271,10 +268,12 @@ impl ModalView for WhichKeyModal {
|
||||
}
|
||||
|
||||
fn group_bindings(
|
||||
binding_data: Vec<(Vec<Keystroke>, SharedString)>,
|
||||
) -> Vec<(Vec<Keystroke>, SharedString)> {
|
||||
let mut groups: HashMap<Option<Keystroke>, Vec<(Vec<Keystroke>, SharedString)>> =
|
||||
HashMap::new();
|
||||
binding_data: Vec<(Vec<KeybindingKeystroke>, SharedString)>,
|
||||
) -> Vec<(Vec<KeybindingKeystroke>, SharedString)> {
|
||||
let mut groups: HashMap<
|
||||
Option<KeybindingKeystroke>,
|
||||
Vec<(Vec<KeybindingKeystroke>, SharedString)>,
|
||||
> = HashMap::new();
|
||||
|
||||
// Group bindings by their first keystroke
|
||||
for (remaining_keystrokes, action_name) in binding_data {
|
||||
@@ -306,3 +305,33 @@ fn group_bindings(
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(target_os = "windows")]
|
||||
use gpui::Modifiers;
|
||||
use gpui::{InvalidKeystrokeError, Keystroke};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_group_bindings_preserves_keybinding_keystrokes() -> Result<(), InvalidKeystrokeError> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let keystroke = KeybindingKeystroke::new(
|
||||
Keystroke::parse("ctrl-$")?,
|
||||
Modifiers::control_shift(),
|
||||
"4".to_owned(),
|
||||
);
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let keystroke = KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-x")?);
|
||||
let binding_data = vec![(vec![keystroke.clone()], SharedString::from("test action"))];
|
||||
|
||||
let grouped_bindings = group_bindings(binding_data);
|
||||
|
||||
assert_eq!(
|
||||
grouped_bindings,
|
||||
vec![(vec![keystroke], SharedString::from("test action"))]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user