fish: allow arguments to functions

This allows the ability to provide arguments to a function, such as
`--on-event` in order to trigger a function on the
`fish_command_not_found` event, for example.

PR #1063
This commit is contained in:
Cole Helbling 2020-03-01 13:20:44 -08:00 committed by Robert Helgesson
parent 9a1feb5b10
commit a11cf1decd
No known key found for this signature in database
GPG key ID: 36BDAA14C2797E89
3 changed files with 172 additions and 9 deletions

View file

@ -1333,6 +1333,7 @@ in
A new module is available: 'wayland.windowManager.sway' A new module is available: 'wayland.windowManager.sway'
''; '';
} }
{ {
time = "2020-03-04T18:55:03+00:00"; time = "2020-03-04T18:55:03+00:00";
condition = hostPlatform.isLinux; condition = hostPlatform.isLinux;
@ -1340,6 +1341,16 @@ in
A new module is available: 'programs.abook' 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.
'';
}
]; ];
}; };
} }

View file

@ -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 <literal>caller</literal> 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, <literal>%self</literal> can be specified as an alias
for <literal>$fish_pid</literal>, 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" abbrsStr = concatStringsSep "\n"
(mapAttrsToList (k: v: "abbr --add --global -- ${k} ${escapeShellArg v}") (mapAttrsToList (k: v: "abbr --add --global -- ${k} ${escapeShellArg v}")
cfg.shellAbbrs); cfg.shellAbbrs);
@ -150,12 +259,21 @@ in {
}; };
programs.fish.functions = mkOption { programs.fish.functions = mkOption {
type = types.attrsOf types.lines; type = with types; attrsOf (either lines functionModule);
default = { }; 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 = '' description = ''
Basic functions to add to fish. For more information see Basic functions to add to fish. For more information see
<link xlink:href="https://fishshell.com/docs/current/commands.html#function"/>. <link xlink:href="https://fishshell.com/docs/current/cmds/function.html"/>.
''; '';
}; };
@ -274,12 +392,30 @@ in {
''; '';
} }
{ {
xdg.configFile = mapAttrs' (fName: fBody: { xdg.configFile = mapAttrs' (name: def: {
name = "fish/functions/${fName}.fish"; name = "fish/functions/${name}.fish";
value = { value = {
"text" = '' text = let
function ${fName} modifierStr = n: v: optional (v != null) ''--${n}="${toString v}"'';
${fBody} 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 end
''; '';
}; };

View file

@ -10,12 +10,24 @@ let
end end
''; '';
funcEvent = pkgs.writeText "func-event.fish" ''
function func-event --on-event="fish_command_not_found"
echo "Not found!"
end
'';
in { in {
config = { config = {
programs.fish = { programs.fish = {
enable = true; enable = true;
functions = { func = ''echo "Hello"''; }; functions = {
func = ''echo "Hello"'';
func-event = {
body = ''echo "Not found!"'';
onEvent = "fish_command_not_found";
};
};
}; };
nmt = { nmt = {
@ -25,6 +37,10 @@ in {
assertFileExists home-files/.config/fish/functions/func.fish assertFileExists home-files/.config/fish/functions/func.fish
echo ${func} echo ${func}
assertFileContent home-files/.config/fish/functions/func.fish ${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}
''; '';
}; };