Add command aliases (#14826)

Conrad Irwin created

Co-Authored-By: <tobbe@tlundberg.com>

Release Notes:

- Added `"command_aliases"` setting to let you abbreviate commands

Change summary

assets/settings/default.json                  | 10 +++++++++-
crates/command_palette/src/command_palette.rs |  9 +++++++--
crates/vim/src/test.rs                        | 19 +++++++++++++++++++
crates/workspace/src/workspace_settings.rs    |  7 +++++++
docs/src/vim.md                               |  5 +++++
5 files changed, 47 insertions(+), 3 deletions(-)

Detailed changes

assets/settings/default.json πŸ”—

@@ -936,5 +936,13 @@
   // Examples:
   //   - "proxy": "socks5://localhost:10808"
   //   - "proxy": "http://127.0.0.1:10809"
-  "proxy": null
+  "proxy": null,
+  // Set to configure aliases for the command palette.
+  // When typing a query which is a key of this object, the value will be used instead.
+  //
+  // Examples:
+  // {
+  //   "W": "workspace::Save"
+  // }
+  "command_aliases": {}
 }

crates/command_palette/src/command_palette.rs πŸ”—

@@ -17,9 +17,10 @@ use gpui::{
 use picker::{Picker, PickerDelegate};
 
 use postage::{sink::Sink, stream::Stream};
+use settings::Settings;
 use ui::{h_flex, prelude::*, v_flex, HighlightedLabel, KeyBinding, ListItem, ListItemSpacing};
 use util::ResultExt;
-use workspace::{ModalView, Workspace};
+use workspace::{ModalView, Workspace, WorkspaceSettings};
 use zed_actions::OpenZedUrl;
 
 actions!(command_palette, [Toggle]);
@@ -248,9 +249,13 @@ impl PickerDelegate for CommandPaletteDelegate {
 
     fn update_matches(
         &mut self,
-        query: String,
+        mut query: String,
         cx: &mut ViewContext<Picker<Self>>,
     ) -> gpui::Task<()> {
+        let settings = WorkspaceSettings::get_global(cx);
+        if let Some(alias) = settings.command_aliases.get(&query) {
+            query = alias.to_string();
+        }
         let (mut tx, mut rx) = postage::dispatch::channel(1);
         let task = cx.background_executor().spawn({
             let mut commands = self.all_commands.clone();

crates/vim/src/test.rs πŸ”—

@@ -4,15 +4,18 @@ mod vim_test_context;
 
 use std::time::Duration;
 
+use collections::HashMap;
 use command_palette::CommandPalette;
 use editor::{display_map::DisplayRow, DisplayPoint};
 use futures::StreamExt;
 use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext};
 pub use neovim_backed_test_context::*;
+use settings::SettingsStore;
 pub use vim_test_context::*;
 
 use indoc::indoc;
 use search::BufferSearchBar;
+use workspace::WorkspaceSettings;
 
 use crate::{insert::NormalBefore, motion, state::Mode, ModeIndicator};
 
@@ -1298,3 +1301,19 @@ async fn test_plus_minus(cx: &mut gpui::TestAppContext) {
     cx.simulate_shared_keystrokes("+").await;
     cx.shared_state().await.assert_matches();
 }
+
+#[gpui::test]
+async fn test_command_alias(cx: &mut gpui::TestAppContext) {
+    let mut cx = VimTestContext::new(cx, true).await;
+    cx.update_global(|store: &mut SettingsStore, cx| {
+        store.update_user_settings::<WorkspaceSettings>(cx, |s| {
+            let mut aliases = HashMap::default();
+            aliases.insert("Q".to_string(), "upper".to_string());
+            s.command_aliases = Some(aliases)
+        });
+    });
+
+    cx.set_state("Λ‡hello world", Mode::Normal);
+    cx.simulate_keystrokes(": Q");
+    cx.set_state("Λ‡Hello world", Mode::Normal);
+}

crates/workspace/src/workspace_settings.rs πŸ”—

@@ -1,4 +1,5 @@
 use anyhow::Result;
+use collections::HashMap;
 use gpui::AppContext;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -15,6 +16,7 @@ pub struct WorkspaceSettings {
     pub drop_target_size: f32,
     pub when_closing_with_no_tabs: CloseWindowWhenNoItems,
     pub use_system_path_prompts: bool,
+    pub command_aliases: HashMap<String, String>,
 }
 
 #[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)]
@@ -89,6 +91,11 @@ pub struct WorkspaceSettingsContent {
     ///
     /// Default: true
     pub use_system_path_prompts: Option<bool>,
+    /// Aliases for the command palette. When you type a key in this map,
+    /// it will be assumed to equal the value.
+    ///
+    /// Default: true
+    pub command_aliases: Option<HashMap<String, String>>,
 }
 
 #[derive(Deserialize)]

docs/src/vim.md πŸ”—

@@ -261,6 +261,11 @@ There are also a few Zed settings that you may also enjoy if you use vim mode:
   "gutter": {
     // disable line numbers completely:
     "line_numbers": false
+  },
+  "command_aliases": {
+    "W": "w",
+    "Wq": "wq",
+    "Q": "q"
   }
 }
 ```