Skip to content

Commit 58aa6a8

Browse files
committed
fish: add functions to fish module
restructure shellFunctions to use a submodule
1 parent b387bac commit 58aa6a8

1 file changed

Lines changed: 186 additions & 23 deletions

File tree

nixos/modules/programs/fish.nix

Lines changed: 186 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,63 @@ let
2121

2222
fishFunctions = lib.mapAttrs' (
2323
name: value:
24+
assert !(lib.hasInfix " " name) || throw "Function names cannot have spaces: '${name}'";
25+
assert
26+
!(lib.elem name [
27+
"["
28+
"_"
29+
"and"
30+
"argparse"
31+
"begin"
32+
"break"
33+
"builtin"
34+
"case"
35+
"command"
36+
"continue"
37+
"else"
38+
"end"
39+
"eval"
40+
"exec"
41+
"for"
42+
"function"
43+
"if"
44+
"not"
45+
"or"
46+
"read"
47+
"return"
48+
"set"
49+
"status"
50+
"string"
51+
"switch"
52+
"test"
53+
"time"
54+
"while"
55+
])
56+
|| throw "Cannot set function name to reserved name: '${name}'";
2457
let
25-
fileName = lib.elemAt (lib.splitString " " name) 0;
26-
body = if lib.isPath value then lib.readFile value else value;
58+
optStr = n: lib.optionalString (n != null);
59+
optPair = n: v: optStr n ''--${v}="${n}"'';
60+
61+
modifiers =
62+
with value;
63+
lib.join " " [
64+
(lib.optionalString noScopeShadowing "--no-scope-shadowing")
65+
(optPair description "description")
66+
(optPair wraps "wraps")
67+
(optPair onVariable "on-variable")
68+
(optPair onJobExit "on-job-exit")
69+
(optPair onProcessExit "on-process-exit")
70+
(optPair onSignal "on-signal")
71+
(optPair inheritVariable "inherit-variable")
72+
(optStr onEvent (lib.concatMapStringsSep " " (ev: "--on-event=${ev}") onEvent))
73+
(optStr argumentNames "--argument-names=${toString argumentNames}")
74+
];
2775
in
2876
{
29-
name = "fish/functions/${fileName}.fish";
30-
value.source = indentFishFile "${fileName}.fish" ''
31-
function ${name}
32-
${lib.removeSuffix "\n" body}
77+
name = "fish/functions/${name}.fish";
78+
value.source = indentFishFile "${name}.fish" ''
79+
function ${name}${modifiers}
80+
${lib.removeSuffix "\n" value.body}
3381
end
3482
'';
3583
}
@@ -148,26 +196,141 @@ in
148196
};
149197

150198
shellFunctions = lib.mkOption {
151-
default = { };
152-
type = with lib.types; attrsOf (either str path);
153199
description = ''
154-
Set of custom fish functions.
200+
The function name. Function names cannot be reserved words or have spaces. These are elements of fish
201+
syntax or builtin commands which are essential for the operations of the shell. Current reserved
202+
words are [, _, and, argparse, begin, break, builtin, case, command, continue, else, end, eval, exec, for, function, if, not, or, read, return, set, status, string, switch, test, time, and while.
203+
204+
See the documentation for [fish functions](https://fishshell.com/docs/current/cmds/function.html) for further information
155205
'';
156-
example = lib.literalExpression ''
157-
"ll" = "ls -l $argv";
158-
"mcd -d 'Create a directory and set CWD'" = '''
159-
command mkdir $argv
160-
if test $status = 0
161-
switch $argv[(count $argv)]
162-
case '-*'
163-
164-
case '*'
165-
cd $argv[(count $argv)]
166-
return
206+
example = {
207+
ll.body = "ls -l $argv";
208+
mcd = {
209+
description = "Create a directory and set CWD";
210+
body = ''
211+
command mkdir $argv
212+
if test $status = 0
213+
switch $argv[(count $argv)]
214+
case '-*'
215+
216+
case '*'
217+
cd $argv[(count $argv)]
218+
return
219+
end
167220
end
168-
end
169-
''';
170-
'';
221+
'';
222+
};
223+
};
224+
type = lib.types.attrsOf (
225+
lib.types.submodule {
226+
options = {
227+
body = lib.mkOption {
228+
type = lib.types.str;
229+
description = ''
230+
The function body. You may provide a path or a string containing the fish function body.
231+
'';
232+
};
233+
234+
argumentNames = lib.mkOption {
235+
type = with lib.types; nullOr (listOf str);
236+
description = ''
237+
Assigns the value of successive command-line arguments to the values in names.
238+
These are the same arguments given in [argv](https://fishshell.com/docs/current/language.html#envvar-argv), and are still available there
239+
(unless --inherit-variable argv was used or one of the given NAMES is argv).
240+
See also [Argument Handling](https://fishshell.com/docs/current/language.html#variables-argv).
241+
'';
242+
};
243+
244+
description = lib.mkOption {
245+
type = with lib.types; nullOr str;
246+
description = ''
247+
A description of what the function does, suitable as a completion description.
248+
'';
249+
};
250+
251+
wraps = lib.mkOption {
252+
type = with lib.types; nullOr str;
253+
description = ''
254+
Inherit completions from the given wraps value. This is used to say that this function completes
255+
like that command, for example if you’re creating an alias. See the documentation for [complete](https://fishshell.com/docs/current/cmds/complete.html) for more information.
256+
257+
If the wrapped command is the same as the function name, this will be ignored.
258+
'';
259+
};
260+
261+
onEvent = lib.mkOption {
262+
type = with lib.types; nullOr (listOf str);
263+
description = ''
264+
Run this function when one of the specified named event is emitted. fish internally generates named
265+
events, for example, when showing the prompt. Custom events can be emitted using the [emit](https://fishshell.com/docs/current/cmds/emit.html) command.
266+
'';
267+
};
268+
269+
onVariable = lib.mkOption {
270+
type = with lib.types; nullOr str;
271+
description = ''
272+
Run this function when the variable name changes value. Note that fish makes no guarantees on any
273+
particular timing or even that the function will be run for every single set. Rather it will be run
274+
when the variable has been set at least once, possibly skipping some values or being run when the
275+
variable has been set to the same value (except for universal variables set in other shells - only
276+
changes in the value will be picked up for those)
277+
'';
278+
};
279+
280+
onJobExit = lib.mkOption {
281+
type = with lib.types; nullOr str;
282+
description = ''
283+
Run this function when the job containing a child process with the given process ID exits. Instead of
284+
a PID, the string ‘caller’ can be specified. This is only allowed when in a command substitution, and
285+
will result in the handler being triggered by the exit of the job which created this command
286+
substitution. This will not trigger for disowned jobs.
287+
'';
288+
};
289+
290+
onProcessExit = lib.mkOption {
291+
type = with lib.types; nullOr str;
292+
description = ''
293+
Run this function when the fish child process with the specified PID exits. Instead of a PID, for
294+
backward compatibility, “%self” can be specified as an alias for $fish_pid, and the function will be
295+
run when the current fish instance exits. This will not trigger for [disowned](https://fishshell.com/docs/current/cmds/disown.html) jobs.
296+
'';
297+
};
298+
299+
onSignal = lib.mkOption {
300+
type = with lib.types; nullOr str;
301+
description = ''
302+
Run this function when the signal is delivered. The signal can be a signal number, or the signal name,
303+
such as SIGHUP (or just HUP). Note that the signal must have been delivered to fish; for example,
304+
ctrl-c sends SIGINT to the foreground process group, which will not be fish if you are running another
305+
command at the time. Observing a signal will prevent fish from exiting in response to that signal.
306+
'';
307+
};
308+
309+
noScopeShadowing = lib.mkOption {
310+
type = lib.types.bool;
311+
default = false;
312+
description = ''
313+
Allows the function to access the variables of calling functions. Normally, any variables inside the
314+
function that have the same name as variables from the calling function are “shadowed”, and their
315+
contents are independent of the calling function.
316+
'';
317+
};
318+
319+
inheritVariable = lib.mkOption {
320+
type = with lib.types; nullOr str;
321+
description = ''
322+
Snapshots the value of the given variable and defines a local variable with that same name and value
323+
when the function is defined. This is similar to a closure in other languages like Python but a bit
324+
different. Note the word “snapshot” in the first sentence. If you change the value of the variable
325+
after defining the function, even if you do so in the same scope (typically another function) the new
326+
value will not be used by the function you just created using this option. See the function notify
327+
example below for how this might be used.
328+
'';
329+
};
330+
};
331+
332+
}
333+
);
171334
};
172335

173336
shellInit = lib.mkOption {

0 commit comments

Comments
 (0)