Add KeyBindings to CommandPalette
This commit is contained in:
parent
b918c27cf9
commit
25bc898807
7 changed files with 116 additions and 273 deletions
|
@ -11,7 +11,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
use theme::ActiveTheme;
|
||||
use ui::{v_stack, HighlightedLabel, StyledExt};
|
||||
use ui::{h_stack, v_stack, HighlightedLabel, KeyBinding, StyledExt};
|
||||
use util::{
|
||||
channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
|
||||
ResultExt,
|
||||
|
@ -318,66 +318,16 @@ impl PickerDelegate for CommandPaletteDelegate {
|
|||
.rounded_md()
|
||||
.when(selected, |this| this.bg(colors.ghost_element_selected))
|
||||
.hover(|this| this.bg(colors.ghost_element_hover))
|
||||
.child(HighlightedLabel::new(
|
||||
command.name.clone(),
|
||||
r#match.positions.clone(),
|
||||
))
|
||||
.child(
|
||||
h_stack()
|
||||
.justify_between()
|
||||
.child(HighlightedLabel::new(
|
||||
command.name.clone(),
|
||||
r#match.positions.clone(),
|
||||
))
|
||||
.children(KeyBinding::for_action(&*command.action, cx)),
|
||||
)
|
||||
}
|
||||
|
||||
// fn render_match(
|
||||
// &self,
|
||||
// ix: usize,
|
||||
// mouse_state: &mut MouseState,
|
||||
// selected: bool,
|
||||
// cx: &gpui::AppContext,
|
||||
// ) -> AnyElement<Picker<Self>> {
|
||||
// let mat = &self.matches[ix];
|
||||
// let command = &self.actions[mat.candidate_id];
|
||||
// let theme = theme::current(cx);
|
||||
// let style = theme.picker.item.in_state(selected).style_for(mouse_state);
|
||||
// let key_style = &theme.command_palette.key.in_state(selected);
|
||||
// let keystroke_spacing = theme.command_palette.keystroke_spacing;
|
||||
|
||||
// Flex::row()
|
||||
// .with_child(
|
||||
// Label::new(mat.string.clone(), style.label.clone())
|
||||
// .with_highlights(mat.positions.clone()),
|
||||
// )
|
||||
// .with_children(command.keystrokes.iter().map(|keystroke| {
|
||||
// Flex::row()
|
||||
// .with_children(
|
||||
// [
|
||||
// (keystroke.ctrl, "^"),
|
||||
// (keystroke.alt, "⌥"),
|
||||
// (keystroke.cmd, "⌘"),
|
||||
// (keystroke.shift, "⇧"),
|
||||
// ]
|
||||
// .into_iter()
|
||||
// .filter_map(|(modifier, label)| {
|
||||
// if modifier {
|
||||
// Some(
|
||||
// Label::new(label, key_style.label.clone())
|
||||
// .contained()
|
||||
// .with_style(key_style.container),
|
||||
// )
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }),
|
||||
// )
|
||||
// .with_child(
|
||||
// Label::new(keystroke.key.clone(), key_style.label.clone())
|
||||
// .contained()
|
||||
// .with_style(key_style.container),
|
||||
// )
|
||||
// .contained()
|
||||
// .with_margin_left(keystroke_spacing)
|
||||
// .flex_float()
|
||||
// }))
|
||||
// .contained()
|
||||
// .with_style(style.container)
|
||||
// .into_any()
|
||||
// }
|
||||
}
|
||||
|
||||
fn humanize_action_name(name: &str) -> String {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
build_action_from_type, Action, Bounds, DispatchPhase, Element, FocusEvent, FocusHandle,
|
||||
FocusId, KeyContext, KeyMatch, Keymap, Keystroke, KeystrokeMatcher, MouseDownEvent, Pixels,
|
||||
Style, StyleRefinement, ViewContext, WindowContext,
|
||||
FocusId, KeyBinding, KeyContext, KeyMatch, Keymap, Keystroke, KeystrokeMatcher, MouseDownEvent,
|
||||
Pixels, Style, StyleRefinement, ViewContext, WindowContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
|
@ -145,6 +145,15 @@ impl DispatchTree {
|
|||
actions
|
||||
}
|
||||
|
||||
pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
|
||||
self.keymap
|
||||
.lock()
|
||||
.bindings_for_action(action.type_id())
|
||||
.filter(|candidate| candidate.action.partial_eq(action))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn dispatch_key(
|
||||
&mut self,
|
||||
keystroke: &Keystroke,
|
||||
|
|
|
@ -3,9 +3,19 @@ use anyhow::Result;
|
|||
use smallvec::SmallVec;
|
||||
|
||||
pub struct KeyBinding {
|
||||
action: Box<dyn Action>,
|
||||
pub(super) keystrokes: SmallVec<[Keystroke; 2]>,
|
||||
pub(super) context_predicate: Option<KeyBindingContextPredicate>,
|
||||
pub(crate) action: Box<dyn Action>,
|
||||
pub(crate) keystrokes: SmallVec<[Keystroke; 2]>,
|
||||
pub(crate) context_predicate: Option<KeyBindingContextPredicate>,
|
||||
}
|
||||
|
||||
impl Clone for KeyBinding {
|
||||
fn clone(&self) -> Self {
|
||||
KeyBinding {
|
||||
action: self.action.boxed_clone(),
|
||||
keystrokes: self.keystrokes.clone(),
|
||||
context_predicate: self.context_predicate.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyBinding {
|
||||
|
|
|
@ -3,13 +3,13 @@ use crate::{
|
|||
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
|
||||
DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId,
|
||||
EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
|
||||
InputEvent, IsZero, KeyContext, KeyDownEvent, LayoutId, Model, ModelContext, Modifiers,
|
||||
MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
|
||||
PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
|
||||
PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
|
||||
SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription,
|
||||
TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
|
||||
WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, LayoutId, Model, ModelContext,
|
||||
Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path,
|
||||
Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
||||
PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams,
|
||||
RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet,
|
||||
Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext,
|
||||
WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::HashMap;
|
||||
|
@ -1377,6 +1377,13 @@ impl<'a> WindowContext<'a> {
|
|||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
|
||||
self.window
|
||||
.current_frame
|
||||
.dispatch_tree
|
||||
.bindings_for_action(action)
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for WindowContext<'_> {
|
||||
|
|
|
@ -1,50 +1,42 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use strum::{EnumIter, IntoEnumIterator};
|
||||
use gpui::Action;
|
||||
use strum::EnumIter;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Keybinding {
|
||||
pub struct KeyBinding {
|
||||
/// A keybinding consists of a key and a set of modifier keys.
|
||||
/// More then one keybinding produces a chord.
|
||||
///
|
||||
/// This should always contain at least one element.
|
||||
keybinding: Vec<(String, ModifierKeys)>,
|
||||
key_binding: gpui::KeyBinding,
|
||||
}
|
||||
|
||||
impl Keybinding {
|
||||
pub fn new(key: String, modifiers: ModifierKeys) -> Self {
|
||||
Self {
|
||||
keybinding: vec![(key, modifiers)],
|
||||
}
|
||||
impl KeyBinding {
|
||||
pub fn for_action(action: &dyn Action, cx: &mut WindowContext) -> Option<Self> {
|
||||
// todo! this last is arbitrary, we want to prefer users key bindings over defaults,
|
||||
// and vim over normal (in vim mode), etc.
|
||||
let key_binding = cx.bindings_for_action(action).last().cloned()?;
|
||||
Some(Self::new(key_binding))
|
||||
}
|
||||
|
||||
pub fn new_chord(
|
||||
first_note: (String, ModifierKeys),
|
||||
second_note: (String, ModifierKeys),
|
||||
) -> Self {
|
||||
Self {
|
||||
keybinding: vec![first_note, second_note],
|
||||
}
|
||||
pub fn new(key_binding: gpui::KeyBinding) -> Self {
|
||||
Self { key_binding }
|
||||
}
|
||||
|
||||
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
|
||||
div()
|
||||
.flex()
|
||||
.gap_2()
|
||||
.children(self.keybinding.iter().map(|(key, modifiers)| {
|
||||
.children(self.key_binding.keystrokes().iter().map(|keystroke| {
|
||||
div()
|
||||
.flex()
|
||||
.gap_1()
|
||||
.children(ModifierKey::iter().filter_map(|modifier| {
|
||||
if modifiers.0.contains(&modifier) {
|
||||
Some(Key::new(modifier.glyph().to_string()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}))
|
||||
.child(Key::new(key.clone()))
|
||||
.when(keystroke.modifiers.control, |el| el.child(Key::new("^")))
|
||||
.when(keystroke.modifiers.alt, |el| el.child(Key::new("⌥")))
|
||||
.when(keystroke.modifiers.command, |el| el.child(Key::new("⌘")))
|
||||
.when(keystroke.modifiers.shift, |el| el.child(Key::new("⇧")))
|
||||
.child(Key::new(keystroke.key.clone()))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -81,76 +73,6 @@ pub enum ModifierKey {
|
|||
Shift,
|
||||
}
|
||||
|
||||
impl ModifierKey {
|
||||
/// Returns the glyph for the [`ModifierKey`].
|
||||
pub fn glyph(&self) -> char {
|
||||
match self {
|
||||
Self::Control => '^',
|
||||
Self::Alt => '⌥',
|
||||
Self::Command => '⌘',
|
||||
Self::Shift => '⇧',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ModifierKeys(HashSet<ModifierKey>);
|
||||
|
||||
impl ModifierKeys {
|
||||
pub fn new() -> Self {
|
||||
Self(HashSet::new())
|
||||
}
|
||||
|
||||
pub fn all() -> Self {
|
||||
Self(HashSet::from_iter(ModifierKey::iter()))
|
||||
}
|
||||
|
||||
pub fn add(mut self, modifier: ModifierKey) -> Self {
|
||||
self.0.insert(modifier);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn control(mut self, control: bool) -> Self {
|
||||
if control {
|
||||
self.0.insert(ModifierKey::Control);
|
||||
} else {
|
||||
self.0.remove(&ModifierKey::Control);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn alt(mut self, alt: bool) -> Self {
|
||||
if alt {
|
||||
self.0.insert(ModifierKey::Alt);
|
||||
} else {
|
||||
self.0.remove(&ModifierKey::Alt);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn command(mut self, command: bool) -> Self {
|
||||
if command {
|
||||
self.0.insert(ModifierKey::Command);
|
||||
} else {
|
||||
self.0.remove(&ModifierKey::Command);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn shift(mut self, shift: bool) -> Self {
|
||||
if shift {
|
||||
self.0.insert(ModifierKey::Shift);
|
||||
} else {
|
||||
self.0.remove(&ModifierKey::Shift);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stories")]
|
||||
pub use stories::*;
|
||||
|
||||
|
@ -158,29 +80,38 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{action, Div, Render};
|
||||
use itertools::Itertools;
|
||||
|
||||
pub struct KeybindingStory;
|
||||
|
||||
#[action]
|
||||
struct NoAction {}
|
||||
|
||||
pub fn binding(key: &str) -> gpui::KeyBinding {
|
||||
gpui::KeyBinding::new(key, NoAction {}, None)
|
||||
}
|
||||
|
||||
impl Render for KeybindingStory {
|
||||
type Element = Div<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let all_modifier_permutations = ModifierKey::iter().permutations(2);
|
||||
let all_modifier_permutations =
|
||||
["ctrl", "alt", "cmd", "shift"].into_iter().permutations(2);
|
||||
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<_, Keybinding>(cx))
|
||||
.child(Story::title_for::<_, KeyBinding>(cx))
|
||||
.child(Story::label(cx, "Single Key"))
|
||||
.child(Keybinding::new("Z".to_string(), ModifierKeys::new()))
|
||||
.child(KeyBinding::new(binding("Z")))
|
||||
.child(Story::label(cx, "Single Key with Modifier"))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.gap_3()
|
||||
.children(ModifierKey::iter().map(|modifier| {
|
||||
Keybinding::new("C".to_string(), ModifierKeys::new().add(modifier))
|
||||
})),
|
||||
.child(KeyBinding::new(binding("ctrl-c")))
|
||||
.child(KeyBinding::new(binding("alt-c")))
|
||||
.child(KeyBinding::new(binding("cmd-c")))
|
||||
.child(KeyBinding::new(binding("shift-c"))),
|
||||
)
|
||||
.child(Story::label(cx, "Single Key with Modifier (Permuted)"))
|
||||
.child(
|
||||
|
@ -194,29 +125,17 @@ mod stories {
|
|||
.gap_4()
|
||||
.py_3()
|
||||
.children(chunk.map(|permutation| {
|
||||
let mut modifiers = ModifierKeys::new();
|
||||
|
||||
for modifier in permutation {
|
||||
modifiers = modifiers.add(modifier);
|
||||
}
|
||||
|
||||
Keybinding::new("X".to_string(), modifiers)
|
||||
KeyBinding::new(binding(&*(permutation.join("-") + "-x")))
|
||||
}))
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(Story::label(cx, "Single Key with All Modifiers"))
|
||||
.child(Keybinding::new("Z".to_string(), ModifierKeys::all()))
|
||||
.child(KeyBinding::new(binding("ctrl-alt-cmd-shift-z")))
|
||||
.child(Story::label(cx, "Chord"))
|
||||
.child(Keybinding::new_chord(
|
||||
("A".to_string(), ModifierKeys::new()),
|
||||
("Z".to_string(), ModifierKeys::new()),
|
||||
))
|
||||
.child(KeyBinding::new(binding("a z")))
|
||||
.child(Story::label(cx, "Chord with Modifier"))
|
||||
.child(Keybinding::new_chord(
|
||||
("A".to_string(), ModifierKeys::new().control(true)),
|
||||
("Z".to_string(), ModifierKeys::new().shift(true)),
|
||||
))
|
||||
.child(KeyBinding::new(binding("ctrl-a shift-z")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{h_stack, v_stack, Keybinding, Label, LabelColor};
|
||||
use crate::{h_stack, v_stack, KeyBinding, Label, LabelColor};
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Palette {
|
||||
|
@ -108,7 +108,7 @@ impl Palette {
|
|||
pub struct PaletteItem {
|
||||
pub label: SharedString,
|
||||
pub sublabel: Option<SharedString>,
|
||||
pub keybinding: Option<Keybinding>,
|
||||
pub keybinding: Option<KeyBinding>,
|
||||
}
|
||||
|
||||
impl PaletteItem {
|
||||
|
@ -132,7 +132,7 @@ impl PaletteItem {
|
|||
|
||||
pub fn keybinding<K>(mut self, keybinding: K) -> Self
|
||||
where
|
||||
K: Into<Option<Keybinding>>,
|
||||
K: Into<Option<KeyBinding>>,
|
||||
{
|
||||
self.keybinding = keybinding.into();
|
||||
self
|
||||
|
@ -161,7 +161,7 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
|
||||
use crate::{ModifierKeys, Story};
|
||||
use crate::{binding, Story};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -181,46 +181,24 @@ mod stories {
|
|||
Palette::new("palette-2")
|
||||
.placeholder("Execute a command...")
|
||||
.items(vec![
|
||||
PaletteItem::new("theme selector: toggle").keybinding(
|
||||
Keybinding::new_chord(
|
||||
("k".to_string(), ModifierKeys::new().command(true)),
|
||||
("t".to_string(), ModifierKeys::new().command(true)),
|
||||
),
|
||||
),
|
||||
PaletteItem::new("assistant: inline assist").keybinding(
|
||||
Keybinding::new(
|
||||
"enter".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
),
|
||||
),
|
||||
PaletteItem::new("assistant: quote selection").keybinding(
|
||||
Keybinding::new(
|
||||
">".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
),
|
||||
),
|
||||
PaletteItem::new("assistant: toggle focus").keybinding(
|
||||
Keybinding::new(
|
||||
"?".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
),
|
||||
),
|
||||
PaletteItem::new("theme selector: toggle")
|
||||
.keybinding(KeyBinding::new(binding("cmd-k cmd-t"))),
|
||||
PaletteItem::new("assistant: inline assist")
|
||||
.keybinding(KeyBinding::new(binding("cmd-enter"))),
|
||||
PaletteItem::new("assistant: quote selection")
|
||||
.keybinding(KeyBinding::new(binding("cmd-<"))),
|
||||
PaletteItem::new("assistant: toggle focus")
|
||||
.keybinding(KeyBinding::new(binding("cmd-?"))),
|
||||
PaletteItem::new("auto update: check"),
|
||||
PaletteItem::new("auto update: view release notes"),
|
||||
PaletteItem::new("branches: open recent").keybinding(
|
||||
Keybinding::new(
|
||||
"b".to_string(),
|
||||
ModifierKeys::new().command(true).alt(true),
|
||||
),
|
||||
),
|
||||
PaletteItem::new("branches: open recent")
|
||||
.keybinding(KeyBinding::new(binding("cmd-alt-b"))),
|
||||
PaletteItem::new("chat panel: toggle focus"),
|
||||
PaletteItem::new("cli: install"),
|
||||
PaletteItem::new("client: sign in"),
|
||||
PaletteItem::new("client: sign out"),
|
||||
PaletteItem::new("editor: cancel").keybinding(Keybinding::new(
|
||||
"escape".to_string(),
|
||||
ModifierKeys::new(),
|
||||
)),
|
||||
PaletteItem::new("editor: cancel")
|
||||
.keybinding(KeyBinding::new(binding("escape"))),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ use gpui::{AppContext, ViewContext};
|
|||
use rand::Rng;
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
use crate::HighlightedText;
|
||||
use crate::{binding, HighlightedText};
|
||||
use crate::{
|
||||
Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus,
|
||||
HighlightedLine, Icon, Keybinding, Label, LabelColor, ListEntry, ListEntrySize, Livestream,
|
||||
MicStatus, ModifierKeys, Notification, PaletteItem, Player, PlayerCallStatus,
|
||||
PlayerWithCallStatus, PublicPlayer, ScreenShareStatus, Symbol, Tab, Toggle, VideoStatus,
|
||||
HighlightedLine, Icon, KeyBinding, Label, LabelColor, ListEntry, ListEntrySize, Livestream,
|
||||
MicStatus, Notification, PaletteItem, Player, PlayerCallStatus, PlayerWithCallStatus,
|
||||
PublicPlayer, ScreenShareStatus, Symbol, Tab, Toggle, VideoStatus,
|
||||
};
|
||||
use crate::{ListItem, NotificationAction};
|
||||
|
||||
|
@ -701,46 +701,16 @@ pub fn static_collab_panel_channels() -> Vec<ListItem> {
|
|||
|
||||
pub fn example_editor_actions() -> Vec<PaletteItem> {
|
||||
vec![
|
||||
PaletteItem::new("New File").keybinding(Keybinding::new(
|
||||
"N".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Open File").keybinding(Keybinding::new(
|
||||
"O".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Save File").keybinding(Keybinding::new(
|
||||
"S".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Cut").keybinding(Keybinding::new(
|
||||
"X".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Copy").keybinding(Keybinding::new(
|
||||
"C".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Paste").keybinding(Keybinding::new(
|
||||
"V".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Undo").keybinding(Keybinding::new(
|
||||
"Z".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Redo").keybinding(Keybinding::new(
|
||||
"Z".to_string(),
|
||||
ModifierKeys::new().command(true).shift(true),
|
||||
)),
|
||||
PaletteItem::new("Find").keybinding(Keybinding::new(
|
||||
"F".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("Replace").keybinding(Keybinding::new(
|
||||
"R".to_string(),
|
||||
ModifierKeys::new().command(true),
|
||||
)),
|
||||
PaletteItem::new("New File").keybinding(KeyBinding::new(binding("cmd-n"))),
|
||||
PaletteItem::new("Open File").keybinding(KeyBinding::new(binding("cmd-o"))),
|
||||
PaletteItem::new("Save File").keybinding(KeyBinding::new(binding("cmd-s"))),
|
||||
PaletteItem::new("Cut").keybinding(KeyBinding::new(binding("cmd-x"))),
|
||||
PaletteItem::new("Copy").keybinding(KeyBinding::new(binding("cmd-c"))),
|
||||
PaletteItem::new("Paste").keybinding(KeyBinding::new(binding("cmd-v"))),
|
||||
PaletteItem::new("Undo").keybinding(KeyBinding::new(binding("cmd-z"))),
|
||||
PaletteItem::new("Redo").keybinding(KeyBinding::new(binding("cmd-shift-z"))),
|
||||
PaletteItem::new("Find").keybinding(KeyBinding::new(binding("cmd-f"))),
|
||||
PaletteItem::new("Replace").keybinding(KeyBinding::new(binding("cmd-r"))),
|
||||
PaletteItem::new("Jump to Line"),
|
||||
PaletteItem::new("Select All"),
|
||||
PaletteItem::new("Deselect All"),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue