diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 3a2fa5ecb4..4ea6b22f61 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -456,7 +456,7 @@ } }, { - "context": "Dock", + "context": "Dock > Pane", "bindings": { "shift-escape": "dock::HideDock", "cmd-escape": "dock::RemoveTabFromDock" @@ -475,17 +475,6 @@ "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", "bindings": { diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index ba9bc8ad63..3bb036d336 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -1294,7 +1294,7 @@ impl View for ContactList { fn keymap_context(&self, _: &AppContext) -> KeymapContext { let mut cx = Self::default_keymap_context(); - cx.set.insert("menu".into()); + cx.add_identifier("menu"); cx } diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index eb02334c70..e1b9f81c1a 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -82,7 +82,7 @@ impl View for ContextMenu { fn keymap_context(&self, _: &AppContext) -> KeymapContext { let mut cx = Self::default_keymap_context(); - cx.set.insert("menu".into()); + cx.add_identifier("menu"); cx } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index cc028e64fd..4de91fbaf8 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6433,17 +6433,13 @@ impl View for Editor { EditorMode::AutoHeight { .. } => "auto_height", EditorMode::Full => "full", }; - context.map.insert("mode".into(), mode.into()); + context.add_key("mode", mode); if self.pending_rename.is_some() { - context.set.insert("renaming".into()); + context.add_identifier("renaming"); } match self.context_menu.as_ref() { - Some(ContextMenu::Completions(_)) => { - context.set.insert("showing_completions".into()); - } - Some(ContextMenu::CodeActions(_)) => { - context.set.insert("showing_code_actions".into()); - } + Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"), + Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"), None => {} } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index b3bbce289e..35c91f1ff2 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -86,7 +86,7 @@ pub trait View: Entity + Sized { } fn default_keymap_context() -> keymap_matcher::KeymapContext { let mut cx = keymap_matcher::KeymapContext::default(); - cx.set.insert(Self::ui_name().into()); + cx.add_identifier(Self::ui_name()); cx } fn debug_json(&self, _: &AppContext) -> serde_json::Value { @@ -6639,12 +6639,12 @@ mod tests { let mut view_1 = View::new(1); let mut view_2 = View::new(2); let mut view_3 = View::new(3); - view_1.keymap_context.set.insert("a".into()); - view_2.keymap_context.set.insert("a".into()); - view_2.keymap_context.set.insert("b".into()); - view_3.keymap_context.set.insert("a".into()); - view_3.keymap_context.set.insert("b".into()); - view_3.keymap_context.set.insert("c".into()); + view_1.keymap_context.add_identifier("a"); + view_2.keymap_context.add_identifier("a"); + view_2.keymap_context.add_identifier("b"); + view_3.keymap_context.add_identifier("a"); + view_3.keymap_context.add_identifier("b"); + view_3.keymap_context.add_identifier("c"); let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1); let view_2 = cx.add_view(&view_1, |_| view_2); diff --git a/crates/gpui/src/keymap_matcher.rs b/crates/gpui/src/keymap_matcher.rs index 1defe28ef8..ca5b5265ce 100644 --- a/crates/gpui/src/keymap_matcher.rs +++ b/crates/gpui/src/keymap_matcher.rs @@ -89,6 +89,7 @@ impl KeymapMatcher { self.contexts .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 for (i, (view_id, _)) in dispatch_path.iter().enumerate() { // Don't require pending view entry if there are no pending keystrokes @@ -234,10 +235,10 @@ mod tests { actions!(test, [EditorAction, ProjectPanelAction]); let mut editor = KeymapContext::default(); - editor.set.insert("Editor".into()); + editor.add_identifier("Editor"); let mut project_panel = KeymapContext::default(); - project_panel.set.insert("ProjectPanel".into()); + project_panel.add_identifier("ProjectPanel"); // Editor 'deeper' in than 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]); let mut context1 = KeymapContext::default(); - context1.set.insert("1".into()); + context1.add_identifier("1"); let mut context2 = KeymapContext::default(); - context2.set.insert("2".into()); + context2.add_identifier("2"); let dispatch_path = vec![(2, context2), (1, context1)]; @@ -403,22 +404,22 @@ mod tests { let predicate = KeymapContextPredicate::parse("a && b || c == d").unwrap(); let mut context = KeymapContext::default(); - context.set.insert("a".into()); + context.add_identifier("a"); assert!(!predicate.eval(&[context])); let mut context = KeymapContext::default(); - context.set.insert("a".into()); - context.set.insert("b".into()); + context.add_identifier("a"); + context.add_identifier("b"); assert!(predicate.eval(&[context])); let mut context = KeymapContext::default(); - context.set.insert("a".into()); - context.map.insert("c".into(), "x".into()); + context.add_identifier("a"); + context.add_key("c", "x"); assert!(!predicate.eval(&[context])); let mut context = KeymapContext::default(); - context.set.insert("a".into()); - context.map.insert("c".into(), "d".into()); + context.add_identifier("a"); + context.add_key("c", "d"); assert!(predicate.eval(&[context])); let predicate = KeymapContextPredicate::parse("!a").unwrap(); @@ -458,10 +459,11 @@ mod tests { assert!(!predicate.eval(&contexts[6..])); fn context_set(names: &[&str]) -> KeymapContext { - KeymapContext { - set: names.iter().copied().map(str::to_string).collect(), - ..Default::default() - } + let mut keymap = KeymapContext::new(); + names + .iter() + .for_each(|name| keymap.add_identifier(name.to_string())); + keymap } } @@ -484,10 +486,10 @@ mod tests { ]); let mut context_a = KeymapContext::default(); - context_a.set.insert("a".into()); + context_a.add_identifier("a"); let mut context_b = KeymapContext::default(); - context_b.set.insert("b".into()); + context_b.add_identifier("b"); let mut matcher = KeymapMatcher::new(keymap); @@ -532,7 +534,7 @@ mod tests { matcher.clear_pending(); let mut context_c = KeymapContext::default(); - context_c.set.insert("c".into()); + context_c.add_identifier("c"); // Pending keystrokes are maintained per-view assert_eq!( diff --git a/crates/gpui/src/keymap_matcher/keymap_context.rs b/crates/gpui/src/keymap_matcher/keymap_context.rs index b19989b210..bbf6bfc14b 100644 --- a/crates/gpui/src/keymap_matcher/keymap_context.rs +++ b/crates/gpui/src/keymap_matcher/keymap_context.rs @@ -1,13 +1,22 @@ +use std::borrow::Cow; + use anyhow::{anyhow, Result}; use collections::{HashMap, HashSet}; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct KeymapContext { - pub set: HashSet, - pub map: HashMap, + set: HashSet>, + map: HashMap, Cow<'static, str>>, } impl KeymapContext { + pub fn new() -> Self { + KeymapContext { + set: HashSet::default(), + map: HashMap::default(), + } + } + pub fn extend(&mut self, other: &Self) { for v in &other.set { self.set.insert(v.clone()); @@ -16,6 +25,18 @@ impl KeymapContext { self.map.insert(k.clone(), v.clone()); } } + + pub fn add_identifier>>(&mut self, identifier: I) { + self.set.insert(identifier.into()); + } + + pub fn add_key>, S2: Into>>( + &mut self, + key: S1, + value: S2, + ) { + self.map.insert(key.into(), value.into()); + } } #[derive(Debug, Eq, PartialEq)] @@ -46,12 +67,12 @@ impl KeymapContextPredicate { Self::Identifier(name) => (&context.set).contains(name.as_str()), Self::Equal(left, right) => context .map - .get(left) + .get(left.as_str()) .map(|value| value == right) .unwrap_or(false), Self::NotEqual(left, right) => context .map - .get(left) + .get(left.as_str()) .map(|value| value != right) .unwrap_or(true), Self::Not(pred) => !pred.eval(contexts), diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index cf3ca6e994..e4d062d575 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -126,7 +126,7 @@ impl View for Picker { fn keymap_context(&self, _: &AppContext) -> KeymapContext { let mut cx = Self::default_keymap_context(); - cx.set.insert("menu".into()); + cx.add_identifier("menu"); cx } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 2ba920c318..4b3c5b7bc5 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1314,7 +1314,7 @@ impl View for ProjectPanel { fn keymap_context(&self, _: &AppContext) -> KeymapContext { let mut cx = Self::default_keymap_context(); - cx.set.insert("menu".into()); + cx.add_identifier("menu"); cx } } diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 42a924fece..9907a65cdf 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -469,53 +469,52 @@ impl View for TerminalView { let mut context = Self::default_keymap_context(); let mode = self.terminal.read(cx).last_content.mode; - context.map.insert( - "screen".to_string(), - (if mode.contains(TermMode::ALT_SCREEN) { + context.add_key( + "screen", + if mode.contains(TermMode::ALT_SCREEN) { "alt" } else { "normal" - }) - .to_string(), + }, ); if mode.contains(TermMode::APP_CURSOR) { - context.set.insert("DECCKM".to_string()); + context.add_identifier("DECCKM"); } if mode.contains(TermMode::APP_KEYPAD) { - context.set.insert("DECPAM".to_string()); + context.add_identifier("DECPAM"); } //Note the ! here if !mode.contains(TermMode::APP_KEYPAD) { - context.set.insert("DECPNM".to_string()); + context.add_identifier("DECPNM"); } if mode.contains(TermMode::SHOW_CURSOR) { - context.set.insert("DECTCEM".to_string()); + context.add_identifier("DECTCEM"); } if mode.contains(TermMode::LINE_WRAP) { - context.set.insert("DECAWM".to_string()); + context.add_identifier("DECAWM"); } if mode.contains(TermMode::ORIGIN) { - context.set.insert("DECOM".to_string()); + context.add_identifier("DECOM"); } 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 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) { - context.set.insert("report_focus".to_string()); + context.add_identifier("report_focus"); } if mode.contains(TermMode::ALTERNATE_SCROLL) { - context.set.insert("alternate_scroll".to_string()); + context.add_identifier("alternate_scroll"); } if mode.contains(TermMode::BRACKETED_PASTE) { - context.set.insert("bracketed_paste".to_string()); + context.add_identifier("bracketed_paste"); } 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) { @@ -527,9 +526,7 @@ impl View for TerminalView { } else { "off" }; - context - .map - .insert("mouse_reporting".to_string(), mouse_reporting.to_string()); + context.add_key("mouse_reporting", mouse_reporting); } { let format = if mode.contains(TermMode::SGR_MOUSE) { @@ -539,9 +536,7 @@ impl View for TerminalView { } else { "normal" }; - context - .map - .insert("mouse_format".to_string(), format.to_string()); + context.add_key("mouse_format", format); } context } diff --git a/crates/vim/src/state.rs b/crates/vim/src/state.rs index 5734a9222d..e1a06fce59 100644 --- a/crates/vim/src/state.rs +++ b/crates/vim/src/state.rs @@ -73,34 +73,30 @@ impl VimState { pub fn keymap_context_layer(&self) -> KeymapContext { let mut context = KeymapContext::default(); - context.map.insert( - "vim_mode".to_string(), + context.add_key( + "vim_mode", match self.mode { Mode::Normal => "normal", Mode::Visual { .. } => "visual", Mode::Insert => "insert", - } - .to_string(), + }, ); if self.vim_controlled() { - context.set.insert("VimControl".to_string()); + context.add_identifier("VimControl"); } let active_operator = self.operator_stack.last(); if let Some(active_operator) = active_operator { 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( - "vim_operator".to_string(), - active_operator - .map(|op| op.id()) - .unwrap_or_else(|| "none") - .to_string(), + context.add_key( + "vim_operator", + active_operator.map(|op| op.id()).unwrap_or_else(|| "none"), ); context diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 8e51a54178..2e5565ea63 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -21,6 +21,7 @@ use gpui::{ vector::{vec2f, Vector2F}, }, impl_actions, impl_internal_actions, + keymap_matcher::KeymapContext, platform::{CursorStyle, NavigationDirection}, Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext, 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( diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 898e4bd27f..c134c7f68c 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2716,11 +2716,7 @@ impl View for Workspace { } fn keymap_context(&self, _: &AppContext) -> KeymapContext { - let mut keymap = Self::default_keymap_context(); - if self.active_pane() == self.dock_pane() { - keymap.set.insert("Dock".into()); - } - keymap + Self::default_keymap_context() } }