Load all keybindings from JSON file

Max Brunsfeld created

Change summary

crates/chat_panel/src/chat_panel.rs       |  3 -
crates/diagnostics/src/diagnostics.rs     |  6 -
crates/journal/src/journal.rs             |  3 
crates/project_panel/src/project_panel.rs |  7 --
crates/vim/src/insert.rs                  |  8 --
crates/vim/src/normal.rs                  | 23 -------
crates/vim/src/normal/g_prefix.rs         |  8 --
crates/zed/assets/keymaps/default.json    | 67 ++++++++++++++++++++++++
crates/zed/src/keymap_file.rs             |  9 ++
9 files changed, 81 insertions(+), 53 deletions(-)

Detailed changes

crates/chat_panel/src/chat_panel.rs 🔗

@@ -6,7 +6,6 @@ use editor::Editor;
 use gpui::{
     actions,
     elements::*,
-    keymap::Binding,
     platform::CursorStyle,
     views::{ItemType, Select, SelectStyle},
     AppContext, Entity, ModelHandle, MutableAppContext, RenderContext, Subscription, Task, View,
@@ -38,8 +37,6 @@ actions!(chat_panel, [Send, LoadMoreMessages]);
 pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(ChatPanel::send);
     cx.add_action(ChatPanel::load_more_messages);
-
-    cx.add_bindings(vec![Binding::new("enter", Send, Some("ChatPanel"))]);
 }
 
 impl ChatPanel {

crates/diagnostics/src/diagnostics.rs 🔗

@@ -8,9 +8,8 @@ use editor::{
     highlight_diagnostic_message, Editor, ExcerptId, MultiBuffer, ToOffset,
 };
 use gpui::{
-    actions, elements::*, fonts::TextStyle, keymap::Binding, AnyViewHandle, AppContext, Entity,
-    ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    actions, elements::*, fonts::TextStyle, AnyViewHandle, AppContext, Entity, ModelHandle,
+    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::{
     Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal,
@@ -33,7 +32,6 @@ actions!(diagnostics, [Deploy]);
 const CONTEXT_LINE_COUNT: u32 = 1;
 
 pub fn init(cx: &mut MutableAppContext) {
-    cx.add_bindings([Binding::new("alt-shift-D", Deploy, Some("Workspace"))]);
     cx.add_action(ProjectDiagnosticsEditor::deploy);
 }
 

crates/journal/src/journal.rs 🔗

@@ -1,6 +1,6 @@
 use chrono::{Datelike, Local, Timelike};
 use editor::{Autoscroll, Editor};
-use gpui::{actions, keymap::Binding, MutableAppContext};
+use gpui::{actions, MutableAppContext};
 use std::{fs::OpenOptions, sync::Arc};
 use util::TryFutureExt as _;
 use workspace::AppState;
@@ -8,7 +8,6 @@ use workspace::AppState;
 actions!(journal, [NewJournalEntry]);
 
 pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
-    cx.add_bindings(vec![Binding::new("ctrl-alt-cmd-j", NewJournalEntry, None)]);
     cx.add_global_action(move |_: &NewJournalEntry, cx| new_journal_entry(app_state.clone(), cx));
 }
 

crates/project_panel/src/project_panel.rs 🔗

@@ -4,8 +4,7 @@ use gpui::{
         Align, ConstrainedBox, Empty, Flex, Label, MouseEventHandler, ParentElement, ScrollTarget,
         Svg, UniformList, UniformListState,
     },
-    impl_internal_actions,
-    keymap::{self, Binding},
+    impl_internal_actions, keymap,
     platform::CursorStyle,
     AppContext, Element, ElementBox, Entity, ModelHandle, MutableAppContext, View, ViewContext,
     ViewHandle, WeakViewHandle,
@@ -63,10 +62,6 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(ProjectPanel::select_prev);
     cx.add_action(ProjectPanel::select_next);
     cx.add_action(ProjectPanel::open_entry);
-    cx.add_bindings([
-        Binding::new("right", ExpandSelectedEntry, Some("ProjectPanel")),
-        Binding::new("left", CollapseSelectedEntry, Some("ProjectPanel")),
-    ]);
 }
 
 pub enum Event {

crates/vim/src/insert.rs 🔗

@@ -1,18 +1,12 @@
 use crate::{mode::Mode, SwitchMode, VimState};
 use editor::Bias;
-use gpui::{actions, keymap::Binding, MutableAppContext, ViewContext};
+use gpui::{actions, MutableAppContext, ViewContext};
 use language::SelectionGoal;
 use workspace::Workspace;
 
 actions!(vim, [NormalBefore]);
 
 pub fn init(cx: &mut MutableAppContext) {
-    let context = Some("Editor && vim_mode == insert");
-    cx.add_bindings(vec![
-        Binding::new("escape", NormalBefore, context),
-        Binding::new("ctrl-c", NormalBefore, context),
-    ]);
-
     cx.add_action(normal_before);
 }
 

crates/vim/src/normal.rs 🔗

@@ -1,8 +1,8 @@
 mod g_prefix;
 
-use crate::{mode::NormalState, Mode, SwitchMode, VimState};
+use crate::VimState;
 use editor::{char_kind, movement, Bias};
-use gpui::{actions, impl_actions, keymap::Binding, MutableAppContext, ViewContext};
+use gpui::{actions, impl_actions, MutableAppContext, ViewContext};
 use language::SelectionGoal;
 use serde::Deserialize;
 use workspace::Workspace;
@@ -40,26 +40,7 @@ actions!(
 );
 
 pub fn init(cx: &mut MutableAppContext) {
-    let context = Some("Editor && vim_mode == normal");
-    cx.add_bindings(vec![
-        Binding::new("i", SwitchMode(Mode::Insert), context),
-        Binding::new("g", SwitchMode(Mode::Normal(NormalState::GPrefix)), context),
-        Binding::new("h", MoveLeft, context),
-        Binding::new("j", MoveDown, context),
-        Binding::new("k", MoveUp, context),
-        Binding::new("l", MoveRight, context),
-        Binding::new("0", MoveToStartOfLine, context),
-        Binding::new("shift-$", MoveToEndOfLine, context),
-        Binding::new("shift-G", MoveToEnd, context),
-        Binding::new("w", MoveToNextWordStart(false), context),
-        Binding::new("shift-W", MoveToNextWordStart(true), context),
-        Binding::new("e", MoveToNextWordEnd(false), context),
-        Binding::new("shift-E", MoveToNextWordEnd(true), context),
-        Binding::new("b", MoveToPreviousWordStart(false), context),
-        Binding::new("shift-B", MoveToPreviousWordStart(true), context),
-    ]);
     g_prefix::init(cx);
-
     cx.add_action(move_left);
     cx.add_action(move_down);
     cx.add_action(move_up);

crates/vim/src/normal/g_prefix.rs 🔗

@@ -1,16 +1,10 @@
 use crate::{mode::Mode, SwitchMode, VimState};
-use gpui::{actions, keymap::Binding, MutableAppContext, ViewContext};
+use gpui::{actions, MutableAppContext, ViewContext};
 use workspace::Workspace;
 
 actions!(vim, [MoveToStart]);
 
 pub fn init(cx: &mut MutableAppContext) {
-    let context = Some("Editor && vim_mode == normal && vim_submode == g");
-    cx.add_bindings(vec![
-        Binding::new("g", MoveToStart, context),
-        Binding::new("escape", SwitchMode(Mode::normal()), context),
-    ]);
-
     cx.add_action(move_to_start);
 }
 

crates/zed/assets/keymaps/default.json 🔗

@@ -51,7 +51,9 @@
         "cmd-k cmd-t": "theme_selector::Toggle",
         "cmd-k t": "theme_selector::Reload",
         "cmd-t": "project_symbols::Toggle",
-        "cmd-p": "file_finder::Toggle"
+        "cmd-p": "file_finder::Toggle",
+        "alt-shift-D": "diagnostics::Deploy",
+        "ctrl-alt-cmd-j": "journal::NewJournalEntry"
     },
     "ProjectSearchBar": {
         "enter": "project_search::Search",
@@ -246,5 +248,68 @@
     },
     "FileFinder": {
         "escape": "file_finder::Toggle"
+    },
+    "ChatPanel": {
+        "enter": "chat_panel::Send"
+    },
+    "ProjectPanel": {
+        "left": "project_panel::CollapseSelectedEntry",
+        "right": "project_panel::ExpandSelectedEntry"
+    },
+    "Editor && vim_mode == insert": {
+        "escape": "vim::NormalBefore",
+        "ctrl-c": "vim::NormalBefore"
+    },
+    "Editor && vim_mode == normal && vim_submode == g": {
+        "g": "vim::MoveToStart",
+        "escape": [
+            "vim::SwitchMode",
+            {
+                "Normal": "None"
+            }
+        ]
+    },
+    "Editor && vim_mode == normal": {
+        "i": [
+            "vim::SwitchMode",
+            "Insert"
+        ],
+        "g": [
+            "vim::SwitchMode",
+            {
+                "Normal": "GPrefix"
+            }
+        ],
+        "h": "vim::MoveLeft",
+        "j": "vim::MoveDown",
+        "k": "vim::MoveUp",
+        "l": "vim::MoveRight",
+        "0": "vim::MoveToStartOfLine",
+        "shift-$": "vim::MoveToEndOfLine",
+        "shift-G": "vim::MoveToEnd",
+        "w": [
+            "vim::MoveToNextWordStart",
+            false
+        ],
+        "shift-W": [
+            "vim::MoveToNextWordStart",
+            true
+        ],
+        "e": [
+            "vim::MoveToNextWordEnd",
+            false
+        ],
+        "shift-E": [
+            "vim::MoveToNextWordEnd",
+            true
+        ],
+        "b": [
+            "vim::MoveToPreviousWordStart",
+            false
+        ],
+        "shift-B": [
+            "vim::MoveToPreviousWordStart",
+            true
+        ]
     }
 }

crates/zed/src/keymap_file.rs 🔗

@@ -1,4 +1,4 @@
-use anyhow::Result;
+use anyhow::{Context, Result};
 use collections::BTreeMap;
 use gpui::{keymap::Binding, MutableAppContext};
 use serde::Deserialize;
@@ -28,7 +28,12 @@ pub fn load_keymap(cx: &mut MutableAppContext, content: &str) -> Result<()> {
                     } else {
                         let name = serde_json::from_str(action)?;
                         cx.deserialize_action(name, None)
-                    }?;
+                    }
+                    .with_context(|| {
+                        format!(
+                            "invalid binding value for keystroke {keystroke}, context {context:?}"
+                        )
+                    })?;
                     Binding::load(keystroke, action, context)
                 })
                 .collect::<Result<Vec<_>>>()?,