diff --git a/source/tutorials/module-system/module-system.md b/source/tutorials/module-system/module-system.md index 47f776353..095ccbd76 100644 --- a/source/tutorials/module-system/module-system.md +++ b/source/tutorials/module-system/module-system.md @@ -49,8 +49,8 @@ The simplest module is just a function that takes any attributes and returns an Write the following into a file called `default.nix`: -```nix -# default.nix +```{code-block} nix +:caption: default.nix { ... }: { @@ -62,8 +62,8 @@ Write the following into a file called `default.nix`: We will need some helper functions, which will come from the Nixpkgs library. Start by changing the first line in `default.nix`: -```diff -# default.nix +```{code-block} diff +:caption: default.nix - { ... }: + { lib, ... }: { @@ -91,8 +91,8 @@ In this section, you will define the `scripts.output` option. Change `default.nix` to include the following declaration: -```diff -# default.nix +```{code-block} diff +:caption: default.nix { lib, ... }: { + options = { @@ -118,8 +118,8 @@ Here we use `scripts`, because we will add another script later, and call this o Write a new file, `eval.nix`, which you will use to evaluate `default.nix`: -```nix -# eval.nix +```{code-block} nix +:caption: eval.nix let nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-22.11"; pkgs = import nixpkgs { config = {}; overlays = []; }; @@ -163,8 +163,8 @@ What happens if you instead try to assign an integer to the option? Add the following lines to `default.nix`: -```diff -# default.nix +```{code-block} diff +:caption: default.nix { lib, ... }: { options = { @@ -201,8 +201,8 @@ The output is passed on to display it with [`feh`](https://feh.finalrewind.org/) Update `default.nix` by changing the value of `scripts.output` to the following string: -```diff -# default.nix +```{code-block} diff +:caption: default.nix config = { - scripts.output = 42; + scripts.output = '' @@ -218,8 +218,8 @@ We can solve this by packaging the raw {download}`map ` script with ` First, make available a `pkgs` argument in your module evaluation by adding a module that sets `config._module.args`: -```diff -# eval.nix +```{code-block} diff +:caption: eval.nix pkgs.lib.evalModules { modules = [ + ({ config, ... }: { config._module.args = { inherit pkgs; }; }) @@ -234,8 +234,8 @@ This mechanism is currently only [documented in the module system code](https:// Then change `default.nix` to have the following contents: -```nix -# default.nix +```{code-block} nix +:caption: default.nix { pkgs, lib, ... }: { options = { @@ -304,8 +304,8 @@ Module option types not only check for valid values, but also specify how multip Make the following additions to your `default.nix` file: -```diff -# default.nix +```{code-block} diff +:caption: default.nix scripts.output = lib.mkOption { type = lib.types.package; }; @@ -346,8 +346,8 @@ To make option values available to a module, the arguments of the function decla Update `default.nix` to add the `config` attribute: -```diff -# default.nix +```{code-block} diff +:caption: default.nix -{ pkgs, lib, ... }: { +{ pkgs, lib, config, ... }: { ``` @@ -369,8 +369,8 @@ The `config` *argument* is **not** the same as the `config` *attribute*: Now make the following changes to `default.nix`: -```diff -# default.nix +```{code-block} diff +:caption: default.nix config = { scripts.output = pkgs.writeShellApplication { name = "map"; @@ -399,8 +399,8 @@ You will define a new option, `map.zoom`, to control the zoom level of the map. Add the `map` attribute set with the `zoom` option into the top-level `options` declaration, like so: -```diff -# default.nix +```{code-block} diff +:caption: default.nix requestParams = lib.mkOption { type = lib.types.listOf lib.types.str; }; @@ -416,8 +416,8 @@ Add the `map` attribute set with the `zoom` option into the top-level `options` To make use of this, use the `mkIf ` function, which only adds the definition if the condition evaluates to `true`. Make the following additions to the `requestParams` list in the `config` block: -```diff -# default.nix +```{code-block} diff +:caption: default.nix requestParams = [ "size=640x640" "scale=2" @@ -438,8 +438,8 @@ Its value will be used if the value of the option declaring it is not specified Add the corresponding line: -```diff -# default.nix +```{code-block} diff +:caption: default.nix map = { zoom = lib.mkOption { type = lib.types.nullOr lib.types.int; @@ -455,8 +455,8 @@ You have now declared options controlling the map dimensions and zoom level, but Add the `center` option now, possibly with your own location as default value: -```diff -# default.nix +```{code-block} diff +:caption: default.nix type = lib.types.nullOr lib.types.int; default = 2; }; @@ -475,8 +475,8 @@ There are multiple ways of making a new package accessible, but as an exercise, First, add a new option to accommodate the package: -```diff -# default.nix +```{code-block} diff +:caption: default.nix options = { scripts.output = lib.mkOption { type = lib.types.package; @@ -489,8 +489,8 @@ First, add a new option to accommodate the package: Then define the value for that option where you make the raw script reproducible by wrapping a call to it in `writeShellApplication`: -```diff -# default.nix +```{code-block} diff +:caption: default.nix config = { + scripts.geocode = pkgs.writeShellApplication { + name = "geocode"; @@ -505,8 +505,8 @@ Then define the value for that option where you make the raw script reproducible Add another `mkIf` call to the list of `requestParams` now where you access the wrapped package through `config.scripts.geocode`, and run the executable `/bin/geocode` inside: -```diff -# default.nix +```{code-block} diff +:caption: default.nix "scale=2" (lib.mkIf (config.map.zoom != null) "zoom=${toString config.map.zoom}") @@ -530,8 +530,8 @@ In particular, this allows you to separate option declarations from where they a Create a new module, `marker.nix`, where you can declare options for defining location pins and other markers on the map: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix { lib, config, ... }: { } @@ -539,8 +539,8 @@ Create a new module, `marker.nix`, where you can declare options for defining lo Reference this new file in `default.nix` using the `imports` attribute: -```diff -# default.nix +```{code-block} diff +:caption: default.nix { pkgs, lib, config ... }: { + imports = [ @@ -563,8 +563,8 @@ Each assignment of markers will be type-checked during evaluation of the top-lev Make the following changes to `marker.nix`: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix -{ pkgs, lib, config, ... }: { +{ pkgs, lib, config, ... }: +let @@ -593,8 +593,8 @@ In this case, you will use the `map.markers` option to produce and add new eleme To implement this behavior, add the following `config` block to `marker.nix`: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix + config = { + + map.markers = [ @@ -631,8 +631,8 @@ When defining multiple markers, determining an appropriate center or zoom level To achieve this, make the following additions to `marker.nix`, above the `requestParams` declaration: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix + map.center = lib.mkIf + (lib.length config.map.markers >= 1) + null; @@ -662,8 +662,8 @@ To propagate marker definitions from `users` to the `map.markers` option, make t In the `let` block: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix + userType = lib.types.submodule { + options = { + departure = lib.mkOption { @@ -680,8 +680,8 @@ This defines a submodule type for a user, with a `departure` option of type `mar In the `options` block, above `map.markers`: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix + users = lib.mkOption { + type = lib.types.attrsOf userType; + }; @@ -691,8 +691,8 @@ That allows adding a `users` attribute set to `config` in any submodule that imp In the `config` block, above `map.center`: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix config = { - map.markers = [ @@ -730,8 +730,8 @@ You can implement this with the `strMatching ""` type, where `` is In the `let` block: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix type = lib.types.nullOr lib.types.str; default = null; }; @@ -749,8 +749,8 @@ Again, `types.nullOr` allows for `null` values, and the default has been set to In the `paramForMarker` function: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix paramForMarker = marker: let attributes = @@ -773,8 +773,8 @@ But since every `users` attribute has a name, we could use that as an automatic This `firstUpperAlnum` function allows you to retrieve the first character of the username, with the correct type for passing to `departure.style.label`: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix { lib, config, ... }: let + # Returns the uppercased first letter @@ -792,8 +792,8 @@ By transforming the argument to `lib.types.submodule` into a function, you can a One special argument automatically available to submodules is `name`, which when used in `attrsOf`, gives you the name of the attribute the submodule is defined under: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix - userType = lib.types.submodule { + userType = lib.types.submodule ({ name, ... }: { options = { @@ -809,8 +809,8 @@ In this case, you don't easily have access to the name from the marker submodule Instead you can use the `config` section of the `user` submodule to set a default, like so: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix + + config = { + departure.style.label = lib.mkDefault @@ -841,8 +841,8 @@ Here you will use two new type-functions for this: In the `let` block, add the following `colorType` option, which can hold strings containing either some given color names or an RGB value add the new compound type: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix ... (builtins.match "[^A-Z0-9]*([A-Z0-9]).*" (lib.toUpper str)); @@ -863,8 +863,8 @@ This allows either strings that matche a 24-bit hexadecimal number or are equal At the bottom of the `let` block, add the `style.color` option and specify a default value: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix (lib.types.strMatching "[A-Z0-9]"); default = null; }; @@ -879,8 +879,8 @@ At the bottom of the `let` block, add the `style.color` option and specify a def Now add an entry to the `paramForMarker` list which makes use of the new option: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix (marker.style.label != null) "label:${marker.style.label}" ++ [ @@ -896,8 +896,8 @@ In case you set many different markers, it would be helpful to have the ability Add a new `style.size` option to `marker.nix`, allowing you to choose from the set of pre-defined sizes: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix type = colorType; default = "red"; }; @@ -913,8 +913,8 @@ Add a new `style.size` option to `marker.nix`, allowing you to choose from the s Now add a mapping for the size parameter in `paramForMarker`, which selects an appropriate string to pass to the API: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix requestParams = let paramForMarker = marker: let @@ -930,7 +930,7 @@ Now add a mapping for the size parameter in `paramForMarker`, which selects an a Finally, add another `lib.optional` call to the `attributes` string, making use of the selected size: ``` -# marker.nix +:caption: marker.nix attributes = lib.optional (marker.style.label != null) @@ -953,8 +953,8 @@ The new option defined in the next section will allow you to set an *arrival* ma To start, create a new `path.nix` file with the following contents: -```nix -# path.nix +```{code-block} nix +:caption: path.nix { lib, config, ... }: let pathType = lib.types.submodule { @@ -994,8 +994,8 @@ In the `config` attribute we augment the API call by setting the `requestParams` Now import this new `path.nix` module from your `marker.nix` module: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix in { + imports = [ @@ -1011,8 +1011,8 @@ Now import this new `path.nix` module from your `marker.nix` module: Copy the `departure` option declaration to a new `arrival` option in `marker.nix`, to complete the initial path implementation: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix type = markerType; default = {}; }; @@ -1026,8 +1026,8 @@ Copy the `departure` option declaration to a new `arrival` option in `marker.nix Next, add an `arrival.style.label` attribute to the `config` block, mirroring the `departure.style.label`: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix config = { departure.style.label = lib.mkDefault (firstUpperAlnum name); @@ -1039,8 +1039,8 @@ Next, add an `arrival.style.label` attribute to the `config` block, mirroring th Finally, update the return list in the function passed to `concatMap` in `map.markers` to also include the `arrival` marker for each user: -```diff -# marker.nix +```{code-block} diff +:caption: marker.nix map.markers = lib.filter (marker: marker.location != null) (lib.concatMap (user: [ @@ -1057,8 +1057,8 @@ Now you have the basesis to define paths on the map, connecting pairs of departu In the path module, define a path connecting every user's departure and arrival locations: -```diff -# path.nix +```{code-block} diff +:caption: path.nix config = { + + map.paths = builtins.map (user: { @@ -1089,8 +1089,8 @@ As before, you'll now declare a new submodule for the path style. While you could also directly declare the `style.weight` option, in this case you should use the submodule to be able reuse the path style type later. Add the `pathStyleType` submodule option to the `let` block in `path.nix`: -```diff -# path.nix +```{code-block} diff +:caption: path.nix { lib, config, ... }: let + @@ -1114,8 +1114,8 @@ The path weight will default to 5, but can be set to any integer value in the 1 Now add a `style` option to the `options` set further down the file: -```diff -# path.nix +```{code-block} diff +:caption: path.nix options = { locations = lib.mkOption { type = lib.types.listOf lib.types.str; @@ -1132,8 +1132,8 @@ Now add a `style` option to the `options` set further down the file: Finally, update the `attributes` list in `paramForPath`: -```diff -# path.nix +```{code-block} diff +:caption: path.nix paramForPath = path: let attributes = @@ -1156,8 +1156,8 @@ The module system allows you to declare values for an option multiple times, and This makes it possible to have a definition for the `user` option in the `marker.nix` module, as well as a `user` definition in `path.nix`: -```diff -# path.nix +```{code-block} diff +:caption: path.nix in { options = { + @@ -1177,8 +1177,8 @@ This makes it possible to have a definition for the `user` option in the `marker Then add a line using the `user.pathStyle` option in `map.paths` where each user's paths are processed: -```diff -# path.nix +```{code-block} diff +:caption: path.nix user.departure.location user.arrival.location ]; @@ -1196,8 +1196,8 @@ You can accomplish this using types you've already encountered by now. Add a new `colorType` block to `path.nix`, specifying the allowed color names and RGB/RGBA hexadecimal values: -```diff -# path.nix +```{code-block} diff +:caption: path.nix { lib, config, ... }: let @@ -1214,8 +1214,8 @@ Add a new `colorType` block to `path.nix`, specifying the allowed color names an Under the `weight` option, add a new `color` option to use the new `colorType` value: -```diff -# path.nix +```{code-block} diff +:caption: path.nix type = lib.types.ints.between 1 20; default = 5; }; @@ -1230,8 +1230,8 @@ Under the `weight` option, add a new `color` option to use the new `colorType` v Finally, add a line using the `color` option to the `attributes` list: -```diff -# path.nix +```{code-block} diff +:caption: path.nix attributes = [ "weight:${toString path.style.weight}" @@ -1249,8 +1249,8 @@ Since this feature can be turned on or off, you can do this using the `bool` typ Make the following changes to `path.nix` now: -```diff -# path.nix +```{code-block} diff +:caption: path.nix type = colorType; default = "blue"; }; @@ -1265,8 +1265,8 @@ Make the following changes to `path.nix` now: Make sure to also add a line to use that value in `attributes` list, so the option value is included in the API call: -```diff -# path.nix +```{code-block} diff +:caption: path.nix [ "weight:${toString path.style.weight}" "color:${path.style.color}"