diff --git a/modules/programs/fish.nix b/modules/programs/fish.nix index ebcf14d67..20660f545 100644 --- a/modules/programs/fish.nix +++ b/modules/programs/fish.nix @@ -138,9 +138,76 @@ let }; }; - abbrsStr = concatStringsSep "\n" - (mapAttrsToList (k: v: "abbr --add --global -- ${k} ${escapeShellArg v}") - cfg.shellAbbrs); + abbrModule = types.submodule { + options = { + expansion = mkOption { + type = with types; nullOr str; + default = null; + description = '' + The command expanded by an abbreviation. + ''; + }; + + position = mkOption { + type = with types; nullOr str; + default = null; + example = "anywhere"; + description = '' + If the position is "command", the abbreviation expands only if + the position is a command. If it is "anywhere", the abbreviation + expands anywhere. + ''; + }; + + regex = mkOption { + type = with types; nullOr str; + default = null; + description = '' + The regular expression pattern matched instead of the literal name. + ''; + }; + + setCursor = mkOption { + type = with types; (either bool str); + default = false; + description = '' + The marker indicates the position of the cursor when the abbreviation + is expanded. When setCursor is true, the marker is set with a default + value of "%". + ''; + }; + + function = mkOption { + type = with types; nullOr str; + default = null; + description = '' + The fish function expanded instead of a literal string. + ''; + }; + }; + }; + + abbrsStr = concatStringsSep "\n" (mapAttrsToList (name: def: + let + mods = with def; + cli.toGNUCommandLineShell { + mkOption = k: v: + if v == null then + [ ] + else if k == "set-cursor" then + [ "--${k}=${lib.generators.mkValueStringDefault { } v}" ] + else [ + "--${k}" + (lib.generators.mkValueStringDefault { } v) + ]; + } { + inherit position regex function; + set-cursor = setCursor; + }; + modifiers = if isAttrs def then mods else ""; + expansion = if isAttrs def then def.expansion else def; + in "abbr --add ${modifiers} -- ${name}" + + optionalString (expansion != null) " \"${expansion}\"") cfg.shellAbbrs); aliasesStr = concatStringsSep "\n" (mapAttrsToList (k: v: "alias ${k} ${escapeShellArg v}") cfg.shellAliases); @@ -199,12 +266,18 @@ in { }; shellAbbrs = mkOption { - type = with types; attrsOf str; + type = with types; attrsOf (either str abbrModule); default = { }; - example = { - l = "less"; - gco = "git checkout"; - }; + example = literalExpression '' + { + l = "less"; + gco = "git checkout"; + "-C" = { + position = "anywhere"; + expansion = "--color"; + }; + } + ''; description = '' An attribute set that maps aliases (the top level attribute names in this option) to abbreviations. Abbreviations are expanded with diff --git a/tests/modules/programs/fish/abbrs.nix b/tests/modules/programs/fish/abbrs.nix new file mode 100644 index 000000000..681212b80 --- /dev/null +++ b/tests/modules/programs/fish/abbrs.nix @@ -0,0 +1,62 @@ +{ config, ... }: { + config = { + programs.fish = { + enable = true; + + shellAbbrs = { + l = "less"; + gco = "git checkout"; + "-C" = { + position = "anywhere"; + expansion = "--color"; + }; + L = { + position = "anywhere"; + setCursor = true; + expansion = "% | less"; + }; + "!!" = { + position = "anywhere"; + function = "last_history_item"; + }; + vim_edit_texts = { + position = "command"; + regex = ".+\\.txt"; + function = "vim_edit"; + }; + "4DIRS" = { + setCursor = "!"; + expansion = + "$(string join \\n -- 'for dir in */' 'cd $dir' '!' 'cd ..' 'end')"; + }; + dotdot = { + regex = "^\\.\\.+$"; + function = "multicd"; + }; + }; + }; + + nmt = { + description = + "if fish.shellAbbrs is set, check fish.config contains valid abbreviations"; + script = '' + assertFileContains home-files/.config/fish/config.fish \ + 'abbr --add -- l less' + assertFileContains home-files/.config/fish/config.fish \ + 'abbr --add -- gco "git checkout"' + assertFileContains home-files/.config/fish/config.fish \ + 'abbr --add --position anywhere -- -C --color' + assertFileContains home-files/.config/fish/config.fish \ + 'abbr --add --position anywhere --set-cursor -- L "% | less"' + assertFileContains home-files/.config/fish/config.fish \ + 'abbr --add --function last_history_item --position anywhere -- !!' + assertFileContains home-files/.config/fish/config.fish \ + "abbr --add --function vim_edit --position command --regex '.+\.txt' -- vim_edit_texts" + assertFileContains home-files/.config/fish/config.fish \ + 'abbr --add '"'"'--set-cursor=!'"'"' -- 4DIRS "$(string join \n -- '"'"'for dir in */'"'"' '"'"'cd $dir'"'"' '"'"'!'"'"' '"'"'cd ..'"'"' '"'"'end'"'"')' + assertFileContains home-files/.config/fish/config.fish \ + "abbr --add --function multicd --regex '^\.\.+$' -- dotdot" + ''; + }; + }; +} diff --git a/tests/modules/programs/fish/default.nix b/tests/modules/programs/fish/default.nix index 3ed5b9cfe..f81ff971e 100644 --- a/tests/modules/programs/fish/default.nix +++ b/tests/modules/programs/fish/default.nix @@ -1,4 +1,5 @@ { + fish-abbrs = ./abbrs.nix; fish-format-scripts = ./format-scripts.nix; fish-functions = ./functions.nix; fish-no-functions = ./no-functions.nix;