Skip to content

feat: add support for fish-like abbreviations#1060

Open
casedami wants to merge 3 commits intonushell:mainfrom
casedami:feat/abbreviations
Open

feat: add support for fish-like abbreviations#1060
casedami wants to merge 3 commits intonushell:mainfrom
casedami:feat/abbreviations

Conversation

@casedami
Copy link
Copy Markdown

@casedami casedami commented Apr 21, 2026

Following up on my comment in #556 i figured i would go ahead and get something working. This would be the initial step to getting abbreviations in nushell and would require a parsing implementation abbreviations to be stored in nushell config and then passed to reedline. Open to any comments or opinions as far as implementation goes but this is a feature that i would personally love to have in nushell.

I've essentially added a check during the following events that will check if the word before the cursor is an abbreviation and expand it if true:

  • Submit and SubmitOrNewline
  • Enter
  • Edit if the first command in the event is to insert a space

As for adding this to nushell, here's a simple example of how this might look in the nushell config:

diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs
index c1fea4150..239153226 100644
--- a/crates/nu-cli/src/repl.rs
+++ b/crates/nu-cli/src/repl.rs
@@ -414,6 +414,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
         )))
         .with_quick_completions(config.completions.quick)
         .with_partial_completions(config.completions.partial)
+        .with_abbreviations(config.abbreviations)
         .with_ansi_colors(config.use_ansi_coloring.get(engine_state))
         .with_cwd(Some(
             engine_state
diff --git a/crates/nu-protocol/src/config/mod.rs b/crates/nu-protocol/src/config/mod.rs
index 37fa177a5..9769160e9 100644
--- a/crates/nu-protocol/src/config/mod.rs
+++ b/crates/nu-protocol/src/config/mod.rs
@@ -63,6 +63,7 @@ pub struct Config {
     pub hinter: HinterConfig,
     pub history: HistoryConfig,
     pub keybindings: Vec<ParsedKeybinding>,
+    pub abbreviations: HashMap<String, String>,
     pub menus: Vec<ParsedMenu>,
     pub hooks: Hooks,
     pub rm: RmConfig,
@@ -135,6 +136,8 @@ impl Default for Config {

             keybindings: Vec::new(),

+            abbreviations: HashMap::new(),
+
             error_style: ErrorStyle::default(),
             error_lines: 1,
             display_errors: DisplayErrors::default(),
@@ -218,6 +221,10 @@ impl UpdateFromValue for Config {
                     Ok(keybindings) => self.keybindings = keybindings,
                     Err(err) => errors.error(err.into()),
                 },
+                "abbreviations" => match HashMap::from_value(val.clone()) {
+                    Ok(abbreviations) => self.abbreviations = abbreviations,
+                    Err(err) => errors.error(err.into()),
+                },
                 "hooks" => self.hooks.update(val, path, errors),
                 "datetime_format" => self.datetime_format.update(val, path, errors),
                 "error_style" => self.error_style.update(val, path, errors),

Note, that the is_inside_string_literal function could potentially be used for a bug fix for

As an aside, here's how im currently getting abbreviations with this hacky solution

let abbrevs = {
    ga: 'git add'
    gb: 'git branch'
    gc: 'git commit -v'
    gd: 'git diff'
    gdt: 'git difftool -d'
    gm: 'git merge'
    gr: 'git rebase'
    gR: 'git restore'
    gwa: 'git worktree add'
    gwr: 'git worktree remove'
    gwl: 'git worktree list'
    gx: 'git switch'
    la: 'ls -a'
    ll: 'ls -l'
    fg: 'job unfreeze'
    ou: 'overlay use'
    oh: 'overlay hide'
    ol: 'overlay list'
}

$env.config = {
    menus: [
        {
            name: abbr_menu
            only_buffer_difference: false
            marker: none
            type: {
                layout: columnar
                columns: 1
                col_width: 20
                col_padding: 2
            }
            style: {text: green, selected_text: green_reverse, description_text: yellow}
            source: {|buffer, position|
                let match = $abbrevs | columns | where $it == $buffer
                if ($match | is-empty) {
                    {value: $buffer}
                } else {
                    {
                        value: ($abbrevs | get $match.0)
                    }
                }
            }
        }
    ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant