Compare commits

...
Sign in to create a new pull request.

5 commits

Author SHA1 Message Date
Junkui Zhang
0c96bcd572 fix 2025-07-09 19:37:46 +08:00
Junkui Zhang
1610d05526 checkpoint 2025-07-09 19:29:32 +08:00
Junkui Zhang
fa1632bc09 wip 2025-07-09 19:03:17 +08:00
Junkui Zhang
1e4d953fa3 parse KeybindKeystroke 2025-07-09 17:14:39 +08:00
Junkui Zhang
ae625acad6 init 2025-07-09 17:08:16 +08:00
11 changed files with 305 additions and 68 deletions

View file

@ -9000,7 +9000,7 @@ impl Editor {
max_width: Pixels,
cursor_point: Point,
style: &EditorStyle,
accept_keystroke: Option<&gpui::Keystroke>,
accept_keystroke: Option<&gpui::KeybindingKeystroke>,
_window: &Window,
cx: &mut Context<Editor>,
) -> Option<AnyElement> {

View file

@ -42,7 +42,7 @@ use gpui::{
Action, Along, AnyElement, App, AppContext, AvailableSpace, Axis as ScrollbarAxis, BorderStyle,
Bounds, ClickEvent, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase, Edges,
Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox,
HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero, Keystroke, Length,
HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero, KeybindingKeystroke, Length,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
ParentElement, Pixels, ScrollDelta, ScrollHandle, ScrollWheelEvent, ShapedLine, SharedString,
Size, StatefulInteractiveElement, Style, Styled, TextRun, TextStyleRefinement, WeakEntity,
@ -6994,7 +6994,7 @@ fn header_jump_data(
pub struct AcceptEditPredictionBinding(pub(crate) Option<gpui::KeyBinding>);
impl AcceptEditPredictionBinding {
pub fn keystroke(&self) -> Option<&Keystroke> {
pub fn keystroke(&self) -> Option<&KeybindingKeystroke> {
if let Some(binding) = self.0.as_ref() {
match &binding.keystrokes() {
[keystroke, ..] => Some(keystroke),

View file

@ -51,7 +51,7 @@
///
use crate::{
Action, ActionRegistry, App, BindingIndex, DispatchPhase, EntityId, FocusId, KeyBinding,
KeyContext, Keymap, Keystroke, ModifiersChangedEvent, Window,
KeyContext, KeybindingKeystroke, Keymap, Keystroke, ModifiersChangedEvent, Window,
};
use collections::FxHashMap;
use smallvec::SmallVec;
@ -444,10 +444,11 @@ impl DispatchTree {
fn binding_matches_predicate_and_not_shadowed(
keymap: &Keymap,
binding_index: BindingIndex,
keystrokes: &[Keystroke],
keystrokes: &[KeybindingKeystroke],
context_stack: &[KeyContext],
) -> bool {
let (bindings, _) = keymap.bindings_for_input_with_indices(&keystrokes, context_stack);
let (bindings, _) =
keymap.bindings_for_keybinding_keystroke_with_indices(&keystrokes, context_stack);
if let Some((highest_precedence_index, _)) = bindings.iter().next() {
binding_index == *highest_precedence_index
} else {

View file

@ -4,7 +4,7 @@ mod context;
pub use binding::*;
pub use context::*;
use crate::{Action, Keystroke, is_no_action};
use crate::{Action, KeybindingKeystroke, Keystroke, is_no_action};
use collections::HashMap;
use smallvec::SmallVec;
use std::any::TypeId;
@ -177,10 +177,37 @@ impl Keymap {
.map(|pending| (BindingIndex(ix), binding, pending))
});
self.bindings_for_keystrokes_with_indices_inner(possibilities, context_stack)
}
/// TODO:
pub fn bindings_for_keybinding_keystroke_with_indices(
&self,
input: &[KeybindingKeystroke],
context_stack: &[KeyContext],
) -> (SmallVec<[(BindingIndex, KeyBinding); 1]>, bool) {
let possibilities = self
.bindings()
.enumerate()
.rev()
.filter_map(|(ix, binding)| {
binding
.match_keybinding_keystrokes(input)
.map(|pending| (BindingIndex(ix), binding, pending))
});
self.bindings_for_keystrokes_with_indices_inner(possibilities, context_stack)
}
fn bindings_for_keystrokes_with_indices_inner<'a>(
&'a self,
possibilities: impl Iterator<Item = (BindingIndex, &'a KeyBinding, bool)>,
context_stack: &[KeyContext],
) -> (SmallVec<[(BindingIndex, KeyBinding); 1]>, bool) {
let mut bindings: SmallVec<[(BindingIndex, KeyBinding, usize); 1]> = SmallVec::new();
// (pending, is_no_action, depth, keystrokes)
let mut pending_info_opt: Option<(bool, bool, usize, &[Keystroke])> = None;
let mut pending_info_opt: Option<(bool, bool, usize, &[KeybindingKeystroke])> = None;
'outer: for (binding_index, binding, pending) in possibilities {
for depth in (0..=context_stack.len()).rev() {

View file

@ -2,13 +2,16 @@ use std::rc::Rc;
use collections::HashMap;
use crate::{Action, InvalidKeystrokeError, KeyBindingContextPredicate, Keystroke, SharedString};
use crate::{
Action, InvalidKeystrokeError, KeyBindingContextPredicate, KeybindingKeystroke, Keystroke,
SharedString,
};
use smallvec::SmallVec;
/// A keybinding and its associated metadata, from the keymap.
pub struct KeyBinding {
pub(crate) action: Box<dyn Action>,
pub(crate) keystrokes: SmallVec<[Keystroke; 2]>,
pub(crate) keystrokes: SmallVec<[KeybindingKeystroke; 2]>,
pub(crate) context_predicate: Option<Rc<KeyBindingContextPredicate>>,
pub(crate) meta: Option<KeyBindingMetaIndex>,
/// The json input string used when building the keybinding, if any
@ -46,16 +49,17 @@ impl KeyBinding {
key_equivalents: Option<&HashMap<char, char>>,
action_input: Option<SharedString>,
) -> std::result::Result<Self, InvalidKeystrokeError> {
let mut keystrokes: SmallVec<[Keystroke; 2]> = keystrokes
let mut keystrokes: SmallVec<[KeybindingKeystroke; 2]> = keystrokes
.split_whitespace()
.map(Keystroke::parse)
.map(KeybindingKeystroke::parse)
.collect::<std::result::Result<_, _>>()?;
if let Some(equivalents) = key_equivalents {
for keystroke in keystrokes.iter_mut() {
if keystroke.key.chars().count() == 1 {
if let Some(key) = equivalents.get(&keystroke.key.chars().next().unwrap()) {
keystroke.key = key.to_string();
if keystroke.inner.key.chars().count() == 1 {
if let Some(key) = equivalents.get(&keystroke.inner.key.chars().next().unwrap())
{
keystroke.inner.key = key.to_string();
}
}
}
@ -96,8 +100,23 @@ impl KeyBinding {
Some(self.keystrokes.len() > typed.len())
}
/// TODO:
pub fn match_keybinding_keystrokes(&self, typed: &[KeybindingKeystroke]) -> Option<bool> {
if self.keystrokes.len() < typed.len() {
return None;
}
for (target, typed) in self.keystrokes.iter().zip(typed.iter()) {
if !typed.inner.should_match(target) {
return None;
}
}
Some(self.keystrokes.len() > typed.len())
}
/// Get the keystrokes associated with this binding
pub fn keystrokes(&self) -> &[Keystroke] {
pub fn keystrokes(&self) -> &[KeybindingKeystroke] {
self.keystrokes.as_slice()
}

View file

@ -21,6 +21,17 @@ pub struct Keystroke {
pub key_char: Option<String>,
}
/// TODO:
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct KeybindingKeystroke {
/// TODO:
pub inner: Keystroke,
/// TODO:
pub modifiers: Modifiers,
/// TODO:
pub key: String,
}
/// Error type for `Keystroke::parse`. This is used instead of `anyhow::Error` so that Zed can use
/// markdown to display it.
#[derive(Debug)]
@ -55,7 +66,7 @@ impl Keystroke {
///
/// This method assumes that `self` was typed and `target' is in the keymap, and checks
/// both possibilities for self against the target.
pub fn should_match(&self, target: &Keystroke) -> bool {
pub fn should_match(&self, target: &KeybindingKeystroke) -> bool {
#[cfg(not(target_os = "windows"))]
if let Some(key_char) = self
.key_char
@ -68,7 +79,7 @@ impl Keystroke {
..Default::default()
};
if &target.key == key_char && target.modifiers == ime_modifiers {
if &target.inner.key == key_char && target.inner.modifiers == ime_modifiers {
return true;
}
}
@ -80,12 +91,12 @@ impl Keystroke {
.filter(|key_char| key_char != &&self.key)
{
// On Windows, if key_char is set, then the typed keystroke produced the key_char
if &target.key == key_char && target.modifiers == Modifiers::none() {
if &target.inner.key == key_char && target.inner.modifiers == Modifiers::none() {
return true;
}
}
target.modifiers == self.modifiers && target.key == self.key
target.inner.modifiers == self.modifiers && target.inner.key == self.key
}
/// key syntax is:
@ -261,6 +272,132 @@ impl Keystroke {
}
self
}
/// TODO:
pub fn into_keybinding_keystroke(self) -> KeybindingKeystroke {
let (key, modifiers) = temp_keyboard_mapper(self.key.clone(), self.modifiers);
KeybindingKeystroke {
inner: self,
modifiers,
key,
}
}
}
impl KeybindingKeystroke {
/// TODO:
pub fn parse(source: &str) -> std::result::Result<Self, InvalidKeystrokeError> {
let keystroke = Keystroke::parse(source)?;
let Keystroke {
mut modifiers, key, ..
} = keystroke.clone();
let (key, modifiers) = temp_keyboard_mapper(key, modifiers);
Ok(KeybindingKeystroke {
inner: keystroke,
modifiers,
key,
})
}
/// TODO:
pub fn to_string(&self) -> String {
let keystroke = Keystroke {
modifiers: self.modifiers,
key: self.key.clone(),
key_char: None,
};
keystroke.to_string()
}
}
fn temp_keyboard_mapper(key: String, mut modifiers: Modifiers) -> (String, Modifiers) {
match key.as_str() {
"~" => {
modifiers.shift = true;
("`".to_string(), modifiers)
}
"!" => {
modifiers.shift = true;
("1".to_string(), modifiers)
}
"@" => {
modifiers.shift = true;
("2".to_string(), modifiers)
}
"#" => {
modifiers.shift = true;
("3".to_string(), modifiers)
}
"$" => {
modifiers.shift = true;
("4".to_string(), modifiers)
}
"%" => {
modifiers.shift = true;
("5".to_string(), modifiers)
}
"^" => {
modifiers.shift = true;
("6".to_string(), modifiers)
}
"&" => {
modifiers.shift = true;
("7".to_string(), modifiers)
}
"*" => {
modifiers.shift = true;
("8".to_string(), modifiers)
}
"(" => {
modifiers.shift = true;
("9".to_string(), modifiers)
}
")" => {
modifiers.shift = true;
("0".to_string(), modifiers)
}
"_" => {
modifiers.shift = true;
("-".to_string(), modifiers)
}
"+" => {
modifiers.shift = true;
("=".to_string(), modifiers)
}
"{" => {
modifiers.shift = true;
("[".to_string(), modifiers)
}
"}" => {
modifiers.shift = true;
("]".to_string(), modifiers)
}
"|" => {
modifiers.shift = true;
("\\".to_string(), modifiers)
}
":" => {
modifiers.shift = true;
(";".to_string(), modifiers)
}
"\"" => {
modifiers.shift = true;
("'".to_string(), modifiers)
}
"<" => {
modifiers.shift = true;
(",".to_string(), modifiers)
}
">" => {
modifiers.shift = true;
(">".to_string(), modifiers)
}
"?" => {
modifiers.shift = true;
("/".to_string(), modifiers)
}
_ => (key, modifiers),
}
}
fn is_printable_key(key: &str) -> bool {

View file

@ -3316,7 +3316,7 @@ impl Window {
binding
.keystrokes()
.iter()
.map(ToString::to_string)
.map(|ks| ks.to_string())
.collect::<Vec<_>>()
.join(" ")
})

View file

@ -3,7 +3,8 @@ use collections::{BTreeMap, HashMap, IndexMap};
use fs::Fs;
use gpui::{
Action, ActionBuildError, App, InvalidKeystrokeError, KEYSTROKE_PARSE_EXPECTED_MESSAGE,
KeyBinding, KeyBindingContextPredicate, KeyBindingMetaIndex, Keystroke, NoAction, SharedString,
KeyBinding, KeyBindingContextPredicate, KeyBindingMetaIndex, KeybindingKeystroke, Keystroke,
NoAction, SharedString,
};
use schemars::{JsonSchema, json_schema};
use serde::Deserialize;
@ -787,7 +788,7 @@ pub enum KeybindUpdateOperation<'a> {
pub struct KeybindUpdateTarget<'a> {
pub context: Option<&'a str>,
pub keystrokes: &'a [Keystroke],
pub keystrokes: &'a [KeybindingKeystroke],
pub action_name: &'a str,
pub use_key_equivalents: bool,
pub input: Option<&'a str>,
@ -810,7 +811,7 @@ impl<'a> KeybindUpdateTarget<'a> {
fn keystrokes_unparsed(&self) -> String {
let mut keystrokes = String::with_capacity(self.keystrokes.len() * 8);
for keystroke in self.keystrokes {
keystrokes.push_str(&keystroke.unparse());
keystrokes.push_str(&keystroke.inner.unparse());
keystrokes.push(' ');
}
keystrokes.pop();

View file

@ -11,8 +11,8 @@ use fs::Fs;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
AppContext as _, AsyncApp, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable,
Global, KeyContext, Keystroke, ModifiersChangedEvent, ScrollStrategy, StyledText, Subscription,
WeakEntity, actions, div, transparent_black,
Global, KeyContext, KeybindingKeystroke, Keystroke, ModifiersChangedEvent, ScrollStrategy,
StyledText, Subscription, WeakEntity, actions, div, transparent_black,
};
use language::{Language, LanguageConfig, ToOffset as _};
use settings::{BaseKeymap, KeybindSource, KeymapFile, SettingsAssets};
@ -274,7 +274,7 @@ impl KeymapEditor {
for key_binding in key_bindings {
let source = key_binding.meta().map(settings::KeybindSource::from_meta);
let keystroke_text = ui::text_for_keystrokes(key_binding.keystrokes(), cx);
let keystroke_text = ui::text_for_keybinding_keystrokes(key_binding.keystrokes(), cx);
let ui_key_binding = Some(
ui::KeyBinding::new_from_gpui(key_binding.clone(), cx)
.vim_mode(source == Some(settings::KeybindSource::Vim)),
@ -1143,7 +1143,7 @@ async fn load_rust_language(workspace: WeakEntity<Workspace>, cx: &mut AsyncApp)
async fn save_keybinding_update(
existing: ProcessedKeybinding,
new_keystrokes: &[Keystroke],
new_keystrokes: &[KeybindingKeystroke],
new_context: Option<&str>,
fs: &Arc<dyn Fs>,
tab_size: usize,
@ -1202,7 +1202,7 @@ async fn save_keybinding_update(
}
struct KeystrokeInput {
keystrokes: Vec<Keystroke>,
keystrokes: Vec<KeybindingKeystroke>,
focus_handle: FocusHandle,
}
@ -1230,10 +1230,14 @@ impl KeystrokeInput {
last.modifiers = event.modifiers;
}
} else {
self.keystrokes.push(Keystroke {
self.keystrokes.push(KeybindingKeystroke {
inner: Keystroke {
modifiers: event.modifiers,
key: "".to_string(),
key_char: None,
},
modifiers: event.modifiers,
key: "".to_string(),
key_char: None,
});
}
cx.stop_propagation();
@ -1249,12 +1253,13 @@ impl KeystrokeInput {
if event.is_held {
return;
}
let keystroke = event.keystroke.clone().into_keybinding_keystroke();
if let Some(last) = self.keystrokes.last_mut()
&& last.key.is_empty()
{
*last = event.keystroke.clone();
*last = keystroke;
} else {
self.keystrokes.push(event.keystroke.clone());
self.keystrokes.push(keystroke);
}
cx.stop_propagation();
cx.notify();
@ -1266,29 +1271,35 @@ impl KeystrokeInput {
_window: &mut Window,
cx: &mut Context<Self>,
) {
let keystroke = event.keystroke.clone().into_keybinding_keystroke();
if let Some(last) = self.keystrokes.last_mut()
&& !last.key.is_empty()
&& last.modifiers == event.keystroke.modifiers
&& last.modifiers == keystroke.modifiers
{
self.keystrokes.push(Keystroke {
modifiers: event.keystroke.modifiers,
self.keystrokes.push(KeybindingKeystroke {
inner: Keystroke {
modifiers: event.keystroke.modifiers,
key: "".to_string(),
key_char: None,
},
modifiers: keystroke.modifiers,
key: "".to_string(),
key_char: None,
});
}
cx.stop_propagation();
cx.notify();
}
fn keystrokes(&self) -> &[Keystroke] {
fn keystrokes(&self) -> &[KeybindingKeystroke] {
if self
.keystrokes
.last()
.map_or(false, |last| last.key.is_empty())
{
return &self.keystrokes[..self.keystrokes.len() - 1];
&self.keystrokes[..self.keystrokes.len() - 1]
} else {
&self.keystrokes
}
return &self.keystrokes;
}
}
@ -1332,7 +1343,8 @@ impl Render for KeystrokeInput {
.gap(ui::DynamicSpacing::Base04.rems(cx))
.children(self.keystrokes.iter().map(|keystroke| {
h_flex().children(ui::render_keystroke(
keystroke,
&keystroke.modifiers,
&keystroke.key,
None,
Some(rems(0.875).into()),
ui::PlatformStyle::platform(),

View file

@ -1,8 +1,8 @@
use crate::PlatformStyle;
use crate::{Icon, IconName, IconSize, h_flex, prelude::*};
use gpui::{
Action, AnyElement, App, FocusHandle, Global, IntoElement, Keystroke, Modifiers, Window,
relative,
Action, AnyElement, App, FocusHandle, Global, IntoElement, KeybindingKeystroke, Keystroke,
Modifiers, Window, relative,
};
use itertools::Itertools;
@ -13,7 +13,7 @@ pub struct KeyBinding {
/// More than one keystroke produces a chord.
///
/// This should always contain at least one keystroke.
pub keystrokes: Vec<Keystroke>,
pub keystrokes: Vec<KeybindingKeystroke>,
/// The [`PlatformStyle`] to use when displaying this keybinding.
platform_style: PlatformStyle,
@ -59,7 +59,7 @@ impl KeyBinding {
cx.try_global::<VimStyle>().is_some_and(|g| g.0)
}
pub fn new(keystrokes: Vec<Keystroke>, cx: &App) -> Self {
pub fn new(keystrokes: Vec<KeybindingKeystroke>, cx: &App) -> Self {
Self {
keystrokes,
platform_style: PlatformStyle::platform(),
@ -99,16 +99,16 @@ impl KeyBinding {
}
fn render_key(
keystroke: &Keystroke,
key: &str,
color: Option<Color>,
platform_style: PlatformStyle,
size: impl Into<Option<AbsoluteLength>>,
) -> AnyElement {
let key_icon = icon_for_key(keystroke, platform_style);
let key_icon = icon_for_key(key, platform_style);
match key_icon {
Some(icon) => KeyIcon::new(icon, color).size(size).into_any_element(),
None => {
let key = util::capitalize(&keystroke.key);
let key = util::capitalize(key);
Key::new(&key, color).size(size).into_any_element()
}
}
@ -138,7 +138,8 @@ impl RenderOnce for KeyBinding {
.rounded_xs()
.text_color(cx.theme().colors().text_muted)
.children(render_keystroke(
keystroke,
&keystroke.modifiers,
&keystroke.key,
color,
self.size,
self.platform_style,
@ -149,7 +150,8 @@ impl RenderOnce for KeyBinding {
}
pub fn render_keystroke(
keystroke: &Keystroke,
modifiers: &Modifiers,
key: &str,
color: Option<Color>,
size: impl Into<Option<AbsoluteLength>>,
platform_style: PlatformStyle,
@ -163,26 +165,29 @@ pub fn render_keystroke(
let size = size.into();
if use_text {
let element = Key::new(keystroke_text(&keystroke, platform_style, vim_mode), color)
.size(size)
.into_any_element();
let element = Key::new(
keystroke_text(modifiers, key, platform_style, vim_mode),
color,
)
.size(size)
.into_any_element();
vec![element]
} else {
let mut elements = Vec::new();
elements.extend(render_modifiers(
&keystroke.modifiers,
modifiers,
platform_style,
color,
size,
true,
));
elements.push(render_key(&keystroke, color, platform_style, size));
elements.push(render_key(key, color, platform_style, size));
elements
}
}
fn icon_for_key(keystroke: &Keystroke, platform_style: PlatformStyle) -> Option<IconName> {
match keystroke.key.as_str() {
fn icon_for_key(key: &str, platform_style: PlatformStyle) -> Option<IconName> {
match key {
"left" => Some(IconName::ArrowLeft),
"right" => Some(IconName::ArrowRight),
"up" => Some(IconName::ArrowUp),
@ -379,7 +384,23 @@ impl KeyIcon {
/// Returns a textual representation of the key binding for the given [`Action`].
pub fn text_for_action(action: &dyn Action, window: &Window, cx: &App) -> Option<String> {
let key_binding = window.highest_precedence_binding_for_action(action)?;
Some(text_for_keystrokes(key_binding.keystrokes(), cx))
Some(text_for_keybinding_keystrokes(key_binding.keystrokes(), cx))
}
pub fn text_for_keybinding_keystrokes(keystrokes: &[KeybindingKeystroke], cx: &App) -> String {
let platform_style = PlatformStyle::platform();
let vim_enabled = cx.try_global::<VimStyle>().is_some();
keystrokes
.iter()
.map(|keystroke| {
keystroke_text(
&keystroke.modifiers,
&keystroke.key,
platform_style,
vim_enabled,
)
})
.join(" ")
}
pub fn text_for_keystrokes(keystrokes: &[Keystroke], cx: &App) -> String {
@ -387,22 +408,39 @@ pub fn text_for_keystrokes(keystrokes: &[Keystroke], cx: &App) -> String {
let vim_enabled = cx.try_global::<VimStyle>().is_some();
keystrokes
.iter()
.map(|keystroke| keystroke_text(keystroke, platform_style, vim_enabled))
.map(|keystroke| {
keystroke_text(
&keystroke.modifiers,
&keystroke.key,
platform_style,
vim_enabled,
)
})
.join(" ")
}
pub fn text_for_keystroke(keystroke: &Keystroke, cx: &App) -> String {
let platform_style = PlatformStyle::platform();
let vim_enabled = cx.try_global::<VimStyle>().is_some();
keystroke_text(keystroke, platform_style, vim_enabled)
keystroke_text(
&keystroke.modifiers,
&keystroke.key,
platform_style,
vim_enabled,
)
}
/// Returns a textual representation of the given [`Keystroke`].
fn keystroke_text(keystroke: &Keystroke, platform_style: PlatformStyle, vim_mode: bool) -> String {
fn keystroke_text(
modifiers: &Modifiers,
key: &str,
platform_style: PlatformStyle,
vim_mode: bool,
) -> String {
let mut text = String::new();
let delimiter = '-';
if keystroke.modifiers.function {
if modifiers.function {
match vim_mode {
false => text.push_str("Fn"),
true => text.push_str("fn"),
@ -411,7 +449,7 @@ fn keystroke_text(keystroke: &Keystroke, platform_style: PlatformStyle, vim_mode
text.push(delimiter);
}
if keystroke.modifiers.control {
if modifiers.control {
match (platform_style, vim_mode) {
(PlatformStyle::Mac, false) => text.push_str("Control"),
(PlatformStyle::Linux | PlatformStyle::Windows, false) => text.push_str("Ctrl"),
@ -421,7 +459,7 @@ fn keystroke_text(keystroke: &Keystroke, platform_style: PlatformStyle, vim_mode
text.push(delimiter);
}
if keystroke.modifiers.platform {
if modifiers.platform {
match (platform_style, vim_mode) {
(PlatformStyle::Mac, false) => text.push_str("Command"),
(PlatformStyle::Mac, true) => text.push_str("cmd"),
@ -434,7 +472,7 @@ fn keystroke_text(keystroke: &Keystroke, platform_style: PlatformStyle, vim_mode
text.push(delimiter);
}
if keystroke.modifiers.alt {
if modifiers.alt {
match (platform_style, vim_mode) {
(PlatformStyle::Mac, false) => text.push_str("Option"),
(PlatformStyle::Linux | PlatformStyle::Windows, false) => text.push_str("Alt"),
@ -444,7 +482,7 @@ fn keystroke_text(keystroke: &Keystroke, platform_style: PlatformStyle, vim_mode
text.push(delimiter);
}
if keystroke.modifiers.shift {
if modifiers.shift {
match (platform_style, vim_mode) {
(_, false) => text.push_str("Shift"),
(_, true) => text.push_str("shift"),
@ -453,9 +491,9 @@ fn keystroke_text(keystroke: &Keystroke, platform_style: PlatformStyle, vim_mode
}
if vim_mode {
text.push_str(&keystroke.key)
text.push_str(key)
} else {
let key = match keystroke.key.as_str() {
let key = match key {
"pageup" => "PageUp",
"pagedown" => "PageDown",
key => &util::capitalize(key),

View file

@ -50,6 +50,8 @@ impl ModeIndicator {
}
}
// TODO:
// what's this?
fn update_pending_keys(&mut self, window: &mut Window, cx: &App) {
self.pending_keys = window
.pending_input_keystrokes()