diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index e27ec974e..0f0c2ac16 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -1333,6 +1333,7 @@ in
A new module is available: 'wayland.windowManager.sway'
'';
}
+
{
time = "2020-03-04T18:55:03+00:00";
condition = hostPlatform.isLinux;
@@ -1340,6 +1341,16 @@ in
A new module is available: 'programs.abook'
'';
}
+
+ {
+ time = "2020-03-07T11:43:26+00:00";
+ condition = config.programs.zsh.enable;
+ message = ''
+ The option 'programs.fish.functions' has been reworked in
+ order to support all available flags, such as
+ '--description', '--on-event', and more.
+ '';
+ }
];
};
}
diff --git a/modules/programs/fish.nix b/modules/programs/fish.nix
index 2c1d5c3e7..ffcc566a8 100644
--- a/modules/programs/fish.nix
+++ b/modules/programs/fish.nix
@@ -29,6 +29,115 @@ let
};
});
+ functionModule = types.submodule {
+ options = {
+ body = mkOption {
+ type = types.lines;
+ description = ''
+ The function body.
+ '';
+ };
+
+ argumentNames = mkOption {
+ type = with types; nullOr (either str (listOf str));
+ default = null;
+ description = ''
+ Assigns the value of successive command line arguments to the names
+ given.
+ '';
+ };
+
+ description = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ A description of what the function does, suitable as a completion
+ description.
+ '';
+ };
+
+ wraps = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ Causes the function to inherit completions from the given wrapped
+ command.
+ '';
+ };
+
+ onEvent = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ Tells fish to run this function when the specified named event is
+ emitted. Fish internally generates named events e.g. when showing the
+ prompt.
+ '';
+ };
+
+ onVariable = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ Tells fish to run this function when the specified variable changes
+ value.
+ '';
+ };
+
+ onJobExit = mkOption {
+ type = with types; nullOr (either str int);
+ default = null;
+ description = ''
+ Tells fish to run this function when the job with the specified group
+ ID exits. Instead of a PID, the stringer caller can
+ be specified. This is only legal when in a command substitution, and
+ will result in the handler being triggered by the exit of the job
+ which created this command substitution.
+ '';
+ };
+
+ onProcessExit = mkOption {
+ type = with types; nullOr (either str int);
+ default = null;
+ example = "$fish_pid";
+ description = ''
+ Tells fish to run this function when the fish child process with the
+ specified process ID exits. Instead of a PID, for backwards
+ compatibility, %self can be specified as an alias
+ for $fish_pid, and the function will be run when
+ the current fish instance exits.
+ '';
+ };
+
+ onSignal = mkOption {
+ type = with types; nullOr (either str int);
+ default = null;
+ example = [ "SIGHUP" "HUP" 1 ];
+ description = ''
+ Tells fish to run this function when the specified signal is
+ delievered. The signal can be a signal number or signal name.
+ '';
+ };
+
+ noScopeShadowing = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Allows the function to access the variables of calling functions.
+ '';
+ };
+
+ inheritVariable = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ Snapshots the value of the specified variable and defines a local
+ variable with that same name and value when the function is defined.
+ '';
+ };
+ };
+ };
+
abbrsStr = concatStringsSep "\n"
(mapAttrsToList (k: v: "abbr --add --global -- ${k} ${escapeShellArg v}")
cfg.shellAbbrs);
@@ -150,12 +259,21 @@ in {
};
programs.fish.functions = mkOption {
- type = types.attrsOf types.lines;
+ type = with types; attrsOf (either lines functionModule);
default = { };
- example = { gitignore = "curl -sL https://www.gitignore.io/api/$argv"; };
+ example = literalExample ''
+ {
+ __fish_command_not_found_handler = {
+ body = "__fish_default_command_not_found_handler $argv[1]";
+ onEvent = "fish_command_not_found";
+ };
+
+ gitignore = "curl -sL https://www.gitignore.io/api/$argv";
+ }
+ '';
description = ''
Basic functions to add to fish. For more information see
- .
+ .
'';
};
@@ -274,12 +392,30 @@ in {
'';
}
{
- xdg.configFile = mapAttrs' (fName: fBody: {
- name = "fish/functions/${fName}.fish";
+ xdg.configFile = mapAttrs' (name: def: {
+ name = "fish/functions/${name}.fish";
value = {
- "text" = ''
- function ${fName}
- ${fBody}
+ text = let
+ modifierStr = n: v: optional (v != null) ''--${n}="${toString v}"'';
+ modifierStrs = n: v: optional (v != null) "--${n}=${toString v}";
+ modifierBool = n: v: optional (v != null && v) "--${n}";
+
+ mods = with def;
+ modifierStr "description" description ++ modifierStr "wraps" wraps
+ ++ modifierStr "on-event" onEvent
+ ++ modifierStr "on-variable" onVariable
+ ++ modifierStr "on-job-exit" onJobExit
+ ++ modifierStr "on-process-exit" onProcessExit
+ ++ modifierStr "on-signal" onSignal
+ ++ modifierBool "no-scope-shadowing" noScopeShadowing
+ ++ modifierStr "inherit-variable" inheritVariable
+ ++ modifierStrs "argument-names" argumentNames;
+
+ modifiers = if isAttrs def then " ${toString mods}" else "";
+ body = if isAttrs def then def.body else def;
+ in ''
+ function ${name}${modifiers}
+ ${body}
end
'';
};
diff --git a/tests/modules/programs/fish/functions.nix b/tests/modules/programs/fish/functions.nix
index b939a2086..424d0a288 100644
--- a/tests/modules/programs/fish/functions.nix
+++ b/tests/modules/programs/fish/functions.nix
@@ -10,12 +10,24 @@ let
end
'';
+ funcEvent = pkgs.writeText "func-event.fish" ''
+ function func-event --on-event="fish_command_not_found"
+ echo "Not found!"
+ end
+ '';
+
in {
config = {
programs.fish = {
enable = true;
- functions = { func = ''echo "Hello"''; };
+ functions = {
+ func = ''echo "Hello"'';
+ func-event = {
+ body = ''echo "Not found!"'';
+ onEvent = "fish_command_not_found";
+ };
+ };
};
nmt = {
@@ -25,6 +37,10 @@ in {
assertFileExists home-files/.config/fish/functions/func.fish
echo ${func}
assertFileContent home-files/.config/fish/functions/func.fish ${func}
+
+ assertFileExists home-files/.config/fish/functions/func-event.fish
+ echo ${funcEvent}
+ assertFileContent home-files/.config/fish/functions/func-event.fish ${funcEvent}
'';
};