Convert keymap context to use generics and Cow<'static> so we don't have to add .to_string() and .into() for each usage

This commit is contained in:
Mikayla Maki 2023-02-23 14:10:55 -08:00
parent ffe53bed87
commit 9004640586
13 changed files with 97 additions and 93 deletions

View File

@ -456,7 +456,7 @@
} }
}, },
{ {
"context": "Dock", "context": "Dock > Pane",
"bindings": { "bindings": {
"shift-escape": "dock::HideDock", "shift-escape": "dock::HideDock",
"cmd-escape": "dock::RemoveTabFromDock" "cmd-escape": "dock::RemoveTabFromDock"
@ -475,17 +475,6 @@
"backspace": "project_panel::Delete" "backspace": "project_panel::Delete"
} }
}, },
{
"context": "ProjectPanel > Editor",
"bindings": {
"left": "editor::MoveLeft",
"right": "editor::MoveRight",
"backspace": "editor::Backspace",
"cmd-x": "editor::Cut",
"cmd-c": "editor::Copy",
"cmd-v": "editor::Paste"
}
},
{ {
"context": "Terminal", "context": "Terminal",
"bindings": { "bindings": {

View File

@ -1294,7 +1294,7 @@ impl View for ContactList {
fn keymap_context(&self, _: &AppContext) -> KeymapContext { fn keymap_context(&self, _: &AppContext) -> KeymapContext {
let mut cx = Self::default_keymap_context(); let mut cx = Self::default_keymap_context();
cx.set.insert("menu".into()); cx.add_identifier("menu");
cx cx
} }

View File

@ -82,7 +82,7 @@ impl View for ContextMenu {
fn keymap_context(&self, _: &AppContext) -> KeymapContext { fn keymap_context(&self, _: &AppContext) -> KeymapContext {
let mut cx = Self::default_keymap_context(); let mut cx = Self::default_keymap_context();
cx.set.insert("menu".into()); cx.add_identifier("menu");
cx cx
} }

View File

@ -6433,17 +6433,13 @@ impl View for Editor {
EditorMode::AutoHeight { .. } => "auto_height", EditorMode::AutoHeight { .. } => "auto_height",
EditorMode::Full => "full", EditorMode::Full => "full",
}; };
context.map.insert("mode".into(), mode.into()); context.add_key("mode", mode);
if self.pending_rename.is_some() { if self.pending_rename.is_some() {
context.set.insert("renaming".into()); context.add_identifier("renaming");
} }
match self.context_menu.as_ref() { match self.context_menu.as_ref() {
Some(ContextMenu::Completions(_)) => { Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
context.set.insert("showing_completions".into()); Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
}
Some(ContextMenu::CodeActions(_)) => {
context.set.insert("showing_code_actions".into());
}
None => {} None => {}
} }

View File

@ -86,7 +86,7 @@ pub trait View: Entity + Sized {
} }
fn default_keymap_context() -> keymap_matcher::KeymapContext { fn default_keymap_context() -> keymap_matcher::KeymapContext {
let mut cx = keymap_matcher::KeymapContext::default(); let mut cx = keymap_matcher::KeymapContext::default();
cx.set.insert(Self::ui_name().into()); cx.add_identifier(Self::ui_name());
cx cx
} }
fn debug_json(&self, _: &AppContext) -> serde_json::Value { fn debug_json(&self, _: &AppContext) -> serde_json::Value {
@ -6639,12 +6639,12 @@ mod tests {
let mut view_1 = View::new(1); let mut view_1 = View::new(1);
let mut view_2 = View::new(2); let mut view_2 = View::new(2);
let mut view_3 = View::new(3); let mut view_3 = View::new(3);
view_1.keymap_context.set.insert("a".into()); view_1.keymap_context.add_identifier("a");
view_2.keymap_context.set.insert("a".into()); view_2.keymap_context.add_identifier("a");
view_2.keymap_context.set.insert("b".into()); view_2.keymap_context.add_identifier("b");
view_3.keymap_context.set.insert("a".into()); view_3.keymap_context.add_identifier("a");
view_3.keymap_context.set.insert("b".into()); view_3.keymap_context.add_identifier("b");
view_3.keymap_context.set.insert("c".into()); view_3.keymap_context.add_identifier("c");
let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1); let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1);
let view_2 = cx.add_view(&view_1, |_| view_2); let view_2 = cx.add_view(&view_1, |_| view_2);

View File

@ -89,6 +89,7 @@ impl KeymapMatcher {
self.contexts self.contexts
.extend(dispatch_path.iter_mut().map(|e| std::mem::take(&mut e.1))); .extend(dispatch_path.iter_mut().map(|e| std::mem::take(&mut e.1)));
dbg!(&self.contexts);
// Find the bindings which map the pending keystrokes and current context // Find the bindings which map the pending keystrokes and current context
for (i, (view_id, _)) in dispatch_path.iter().enumerate() { for (i, (view_id, _)) in dispatch_path.iter().enumerate() {
// Don't require pending view entry if there are no pending keystrokes // Don't require pending view entry if there are no pending keystrokes
@ -234,10 +235,10 @@ mod tests {
actions!(test, [EditorAction, ProjectPanelAction]); actions!(test, [EditorAction, ProjectPanelAction]);
let mut editor = KeymapContext::default(); let mut editor = KeymapContext::default();
editor.set.insert("Editor".into()); editor.add_identifier("Editor");
let mut project_panel = KeymapContext::default(); let mut project_panel = KeymapContext::default();
project_panel.set.insert("ProjectPanel".into()); project_panel.add_identifier("ProjectPanel");
// Editor 'deeper' in than project panel // Editor 'deeper' in than project panel
let dispatch_path = vec![(2, editor), (1, project_panel)]; let dispatch_path = vec![(2, editor), (1, project_panel)];
@ -266,10 +267,10 @@ mod tests {
actions!(test, [B, AB, C, D, DA, E, EF]); actions!(test, [B, AB, C, D, DA, E, EF]);
let mut context1 = KeymapContext::default(); let mut context1 = KeymapContext::default();
context1.set.insert("1".into()); context1.add_identifier("1");
let mut context2 = KeymapContext::default(); let mut context2 = KeymapContext::default();
context2.set.insert("2".into()); context2.add_identifier("2");
let dispatch_path = vec![(2, context2), (1, context1)]; let dispatch_path = vec![(2, context2), (1, context1)];
@ -403,22 +404,22 @@ mod tests {
let predicate = KeymapContextPredicate::parse("a && b || c == d").unwrap(); let predicate = KeymapContextPredicate::parse("a && b || c == d").unwrap();
let mut context = KeymapContext::default(); let mut context = KeymapContext::default();
context.set.insert("a".into()); context.add_identifier("a");
assert!(!predicate.eval(&[context])); assert!(!predicate.eval(&[context]));
let mut context = KeymapContext::default(); let mut context = KeymapContext::default();
context.set.insert("a".into()); context.add_identifier("a");
context.set.insert("b".into()); context.add_identifier("b");
assert!(predicate.eval(&[context])); assert!(predicate.eval(&[context]));
let mut context = KeymapContext::default(); let mut context = KeymapContext::default();
context.set.insert("a".into()); context.add_identifier("a");
context.map.insert("c".into(), "x".into()); context.add_key("c", "x");
assert!(!predicate.eval(&[context])); assert!(!predicate.eval(&[context]));
let mut context = KeymapContext::default(); let mut context = KeymapContext::default();
context.set.insert("a".into()); context.add_identifier("a");
context.map.insert("c".into(), "d".into()); context.add_key("c", "d");
assert!(predicate.eval(&[context])); assert!(predicate.eval(&[context]));
let predicate = KeymapContextPredicate::parse("!a").unwrap(); let predicate = KeymapContextPredicate::parse("!a").unwrap();
@ -458,10 +459,11 @@ mod tests {
assert!(!predicate.eval(&contexts[6..])); assert!(!predicate.eval(&contexts[6..]));
fn context_set(names: &[&str]) -> KeymapContext { fn context_set(names: &[&str]) -> KeymapContext {
KeymapContext { let mut keymap = KeymapContext::new();
set: names.iter().copied().map(str::to_string).collect(), names
..Default::default() .iter()
} .for_each(|name| keymap.add_identifier(name.to_string()));
keymap
} }
} }
@ -484,10 +486,10 @@ mod tests {
]); ]);
let mut context_a = KeymapContext::default(); let mut context_a = KeymapContext::default();
context_a.set.insert("a".into()); context_a.add_identifier("a");
let mut context_b = KeymapContext::default(); let mut context_b = KeymapContext::default();
context_b.set.insert("b".into()); context_b.add_identifier("b");
let mut matcher = KeymapMatcher::new(keymap); let mut matcher = KeymapMatcher::new(keymap);
@ -532,7 +534,7 @@ mod tests {
matcher.clear_pending(); matcher.clear_pending();
let mut context_c = KeymapContext::default(); let mut context_c = KeymapContext::default();
context_c.set.insert("c".into()); context_c.add_identifier("c");
// Pending keystrokes are maintained per-view // Pending keystrokes are maintained per-view
assert_eq!( assert_eq!(

View File

@ -1,13 +1,22 @@
use std::borrow::Cow;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
#[derive(Clone, Debug, Default, Eq, PartialEq)] #[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct KeymapContext { pub struct KeymapContext {
pub set: HashSet<String>, set: HashSet<Cow<'static, str>>,
pub map: HashMap<String, String>, map: HashMap<Cow<'static, str>, Cow<'static, str>>,
} }
impl KeymapContext { impl KeymapContext {
pub fn new() -> Self {
KeymapContext {
set: HashSet::default(),
map: HashMap::default(),
}
}
pub fn extend(&mut self, other: &Self) { pub fn extend(&mut self, other: &Self) {
for v in &other.set { for v in &other.set {
self.set.insert(v.clone()); self.set.insert(v.clone());
@ -16,6 +25,18 @@ impl KeymapContext {
self.map.insert(k.clone(), v.clone()); self.map.insert(k.clone(), v.clone());
} }
} }
pub fn add_identifier<I: Into<Cow<'static, str>>>(&mut self, identifier: I) {
self.set.insert(identifier.into());
}
pub fn add_key<S1: Into<Cow<'static, str>>, S2: Into<Cow<'static, str>>>(
&mut self,
key: S1,
value: S2,
) {
self.map.insert(key.into(), value.into());
}
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -46,12 +67,12 @@ impl KeymapContextPredicate {
Self::Identifier(name) => (&context.set).contains(name.as_str()), Self::Identifier(name) => (&context.set).contains(name.as_str()),
Self::Equal(left, right) => context Self::Equal(left, right) => context
.map .map
.get(left) .get(left.as_str())
.map(|value| value == right) .map(|value| value == right)
.unwrap_or(false), .unwrap_or(false),
Self::NotEqual(left, right) => context Self::NotEqual(left, right) => context
.map .map
.get(left) .get(left.as_str())
.map(|value| value != right) .map(|value| value != right)
.unwrap_or(true), .unwrap_or(true),
Self::Not(pred) => !pred.eval(contexts), Self::Not(pred) => !pred.eval(contexts),

View File

@ -126,7 +126,7 @@ impl<D: PickerDelegate> View for Picker<D> {
fn keymap_context(&self, _: &AppContext) -> KeymapContext { fn keymap_context(&self, _: &AppContext) -> KeymapContext {
let mut cx = Self::default_keymap_context(); let mut cx = Self::default_keymap_context();
cx.set.insert("menu".into()); cx.add_identifier("menu");
cx cx
} }

View File

@ -1314,7 +1314,7 @@ impl View for ProjectPanel {
fn keymap_context(&self, _: &AppContext) -> KeymapContext { fn keymap_context(&self, _: &AppContext) -> KeymapContext {
let mut cx = Self::default_keymap_context(); let mut cx = Self::default_keymap_context();
cx.set.insert("menu".into()); cx.add_identifier("menu");
cx cx
} }
} }

View File

@ -469,53 +469,52 @@ impl View for TerminalView {
let mut context = Self::default_keymap_context(); let mut context = Self::default_keymap_context();
let mode = self.terminal.read(cx).last_content.mode; let mode = self.terminal.read(cx).last_content.mode;
context.map.insert( context.add_key(
"screen".to_string(), "screen",
(if mode.contains(TermMode::ALT_SCREEN) { if mode.contains(TermMode::ALT_SCREEN) {
"alt" "alt"
} else { } else {
"normal" "normal"
}) },
.to_string(),
); );
if mode.contains(TermMode::APP_CURSOR) { if mode.contains(TermMode::APP_CURSOR) {
context.set.insert("DECCKM".to_string()); context.add_identifier("DECCKM");
} }
if mode.contains(TermMode::APP_KEYPAD) { if mode.contains(TermMode::APP_KEYPAD) {
context.set.insert("DECPAM".to_string()); context.add_identifier("DECPAM");
} }
//Note the ! here //Note the ! here
if !mode.contains(TermMode::APP_KEYPAD) { if !mode.contains(TermMode::APP_KEYPAD) {
context.set.insert("DECPNM".to_string()); context.add_identifier("DECPNM");
} }
if mode.contains(TermMode::SHOW_CURSOR) { if mode.contains(TermMode::SHOW_CURSOR) {
context.set.insert("DECTCEM".to_string()); context.add_identifier("DECTCEM");
} }
if mode.contains(TermMode::LINE_WRAP) { if mode.contains(TermMode::LINE_WRAP) {
context.set.insert("DECAWM".to_string()); context.add_identifier("DECAWM");
} }
if mode.contains(TermMode::ORIGIN) { if mode.contains(TermMode::ORIGIN) {
context.set.insert("DECOM".to_string()); context.add_identifier("DECOM");
} }
if mode.contains(TermMode::INSERT) { if mode.contains(TermMode::INSERT) {
context.set.insert("IRM".to_string()); context.add_identifier("IRM");
} }
//LNM is apparently the name for this. https://vt100.net/docs/vt510-rm/LNM.html //LNM is apparently the name for this. https://vt100.net/docs/vt510-rm/LNM.html
if mode.contains(TermMode::LINE_FEED_NEW_LINE) { if mode.contains(TermMode::LINE_FEED_NEW_LINE) {
context.set.insert("LNM".to_string()); context.add_identifier("LNM");
} }
if mode.contains(TermMode::FOCUS_IN_OUT) { if mode.contains(TermMode::FOCUS_IN_OUT) {
context.set.insert("report_focus".to_string()); context.add_identifier("report_focus");
} }
if mode.contains(TermMode::ALTERNATE_SCROLL) { if mode.contains(TermMode::ALTERNATE_SCROLL) {
context.set.insert("alternate_scroll".to_string()); context.add_identifier("alternate_scroll");
} }
if mode.contains(TermMode::BRACKETED_PASTE) { if mode.contains(TermMode::BRACKETED_PASTE) {
context.set.insert("bracketed_paste".to_string()); context.add_identifier("bracketed_paste");
} }
if mode.intersects(TermMode::MOUSE_MODE) { if mode.intersects(TermMode::MOUSE_MODE) {
context.set.insert("any_mouse_reporting".to_string()); context.add_identifier("any_mouse_reporting");
} }
{ {
let mouse_reporting = if mode.contains(TermMode::MOUSE_REPORT_CLICK) { let mouse_reporting = if mode.contains(TermMode::MOUSE_REPORT_CLICK) {
@ -527,9 +526,7 @@ impl View for TerminalView {
} else { } else {
"off" "off"
}; };
context context.add_key("mouse_reporting", mouse_reporting);
.map
.insert("mouse_reporting".to_string(), mouse_reporting.to_string());
} }
{ {
let format = if mode.contains(TermMode::SGR_MOUSE) { let format = if mode.contains(TermMode::SGR_MOUSE) {
@ -539,9 +536,7 @@ impl View for TerminalView {
} else { } else {
"normal" "normal"
}; };
context context.add_key("mouse_format", format);
.map
.insert("mouse_format".to_string(), format.to_string());
} }
context context
} }

View File

@ -73,34 +73,30 @@ impl VimState {
pub fn keymap_context_layer(&self) -> KeymapContext { pub fn keymap_context_layer(&self) -> KeymapContext {
let mut context = KeymapContext::default(); let mut context = KeymapContext::default();
context.map.insert( context.add_key(
"vim_mode".to_string(), "vim_mode",
match self.mode { match self.mode {
Mode::Normal => "normal", Mode::Normal => "normal",
Mode::Visual { .. } => "visual", Mode::Visual { .. } => "visual",
Mode::Insert => "insert", Mode::Insert => "insert",
} },
.to_string(),
); );
if self.vim_controlled() { if self.vim_controlled() {
context.set.insert("VimControl".to_string()); context.add_identifier("VimControl");
} }
let active_operator = self.operator_stack.last(); let active_operator = self.operator_stack.last();
if let Some(active_operator) = active_operator { if let Some(active_operator) = active_operator {
for context_flag in active_operator.context_flags().into_iter() { for context_flag in active_operator.context_flags().into_iter() {
context.set.insert(context_flag.to_string()); context.add_identifier(*context_flag);
} }
} }
context.map.insert( context.add_key(
"vim_operator".to_string(), "vim_operator",
active_operator active_operator.map(|op| op.id()).unwrap_or_else(|| "none"),
.map(|op| op.id())
.unwrap_or_else(|| "none")
.to_string(),
); );
context context

View File

@ -21,6 +21,7 @@ use gpui::{
vector::{vec2f, Vector2F}, vector::{vec2f, Vector2F},
}, },
impl_actions, impl_internal_actions, impl_actions, impl_internal_actions,
keymap_matcher::KeymapContext,
platform::{CursorStyle, NavigationDirection}, platform::{CursorStyle, NavigationDirection},
Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext, Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext,
ModelHandle, MouseButton, MutableAppContext, PromptLevel, Quad, RenderContext, Task, View, ModelHandle, MouseButton, MutableAppContext, PromptLevel, Quad, RenderContext, Task, View,
@ -1550,6 +1551,14 @@ impl View for Pane {
} }
} }
} }
fn keymap_context(&self, _: &AppContext) -> KeymapContext {
let mut keymap = Self::default_keymap_context();
if self.docked.is_some() {
keymap.add_identifier("docked");
}
keymap
}
} }
fn tab_bar_button<A: Action>( fn tab_bar_button<A: Action>(

View File

@ -2716,11 +2716,7 @@ impl View for Workspace {
} }
fn keymap_context(&self, _: &AppContext) -> KeymapContext { fn keymap_context(&self, _: &AppContext) -> KeymapContext {
let mut keymap = Self::default_keymap_context(); Self::default_keymap_context()
if self.active_pane() == self.dock_pane() {
keymap.set.insert("Dock".into());
}
keymap
} }
} }