doc: improve lib.options reference documentation (#316862)

* Doc: lib/options fixup wording and references

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Silvan Mosberger <github@infinisil.com>
This commit is contained in:
Johannes Kirschbauer 2025-01-13 22:02:34 +01:00 committed by GitHub
parent b2ddf2d7d6
commit 77156bcc8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,4 +1,6 @@
/* Nixpkgs/NixOS option handling. */ /**
Module System option handling.
*/
{ lib }: { lib }:
let let
@ -45,66 +47,147 @@ let
in in
rec { rec {
/* Returns true when the given argument is an option /**
Returns true when the given argument `a` is an option
Type: isOption :: a -> bool # Inputs
Example: `a`
: Any value to check whether it is an option
# Examples
:::{.example}
## `lib.options.isOption` usage example
```nix
isOption 1 // => false isOption 1 // => false
isOption (mkOption {}) // => true isOption (mkOption {}) // => true
```
:::
# Type
```
isOption :: a -> Bool
```
*/ */
isOption = lib.isType "option"; isOption = lib.isType "option";
/* Creates an Option attribute set. mkOption accepts an attribute set with the following keys: /**
Creates an Option attribute set. mkOption accepts an attribute set with the following keys:
All keys default to `null` when not given. # Inputs
Example: Structured attribute set
: Attribute set containing none or some of the following attributes.
`default`
: Optional default value used when no definition is given in the configuration.
`defaultText`
: Substitute for documenting the `default`, if evaluating the default value during documentation rendering is not possible.
: Can be any nix value that evaluates.
: Usage with `lib.literalMD` or `lib.literalExpression` is supported
`example`
: Optional example value used in the manual.
: Can be any nix value that evaluates.
: Usage with `lib.literalMD` or `lib.literalExpression` is supported
`description`
: Optional string describing the option. This is required if option documentation is generated.
`relatedPackages`
: Optional related packages used in the manual (see `genRelatedPackages` in `../nixos/lib/make-options-doc/default.nix`).
`type`
: Optional option type, providing type-checking and value merging.
`apply`
: Optional function that converts the option value to something else.
`internal`
: Optional boolean indicating whether the option is for NixOS developers only.
`visible`
: Optional boolean indicating whether the option shows up in the manual. Default: true. Use false to hide the option and any sub-options from submodules. Use "shallow" to hide only sub-options.
`readOnly`
: Optional boolean indicating whether the option can be set only once.
`...` (any other attribute)
: Any other attribute is passed through to the resulting option attribute set.
# Examples
:::{.example}
## `lib.options.mkOption` usage example
```nix
mkOption { } // => { _type = "option"; } mkOption { } // => { _type = "option"; }
mkOption { default = "foo"; } // => { _type = "option"; default = "foo"; } mkOption { default = "foo"; } // => { _type = "option"; default = "foo"; }
```
:::
*/ */
mkOption = mkOption =
{ {
# Default value used when no definition is given in the configuration.
default ? null, default ? null,
# Textual representation of the default, for the manual.
defaultText ? null, defaultText ? null,
# Example value used in the manual.
example ? null, example ? null,
# String describing the option.
description ? null, description ? null,
# Related packages used in the manual (see `genRelatedPackages` in ../nixos/lib/make-options-doc/default.nix).
relatedPackages ? null, relatedPackages ? null,
# Option type, providing type-checking and value merging.
type ? null, type ? null,
# Function that converts the option value to something else.
apply ? null, apply ? null,
# Whether the option is for NixOS developers only.
internal ? null, internal ? null,
# Whether the option shows up in the manual. Default: true. Use false to hide the option and any sub-options from submodules. Use "shallow" to hide only sub-options.
visible ? null, visible ? null,
# Whether the option can be set only once
readOnly ? null, readOnly ? null,
} @ attrs: } @ attrs:
attrs // { _type = "option"; }; attrs // { _type = "option"; };
/* Creates an Option attribute set for a boolean value option i.e an /**
option to be toggled on or off: Creates an option declaration with a default value of ´false´, and can be defined to ´true´.
Example: # Inputs
mkEnableOption "foo"
=> { _type = "option"; default = false; description = "Whether to enable foo."; example = true; type = { ... }; } `name`
: Name for the created option
# Examples
:::{.example}
## `lib.options.mkEnableOption` usage example
```nix
# module
let
eval = lib.evalModules {
modules = [
{
options.foo.enable = mkEnableOption "foo";
config.foo.enable = true;
}
]:
}
in
eval.config
=> { foo.enable = true; }
```
:::
*/ */
mkEnableOption = mkEnableOption = name: mkOption {
# Name for the created option
name: mkOption {
default = false; default = false;
example = true; example = true;
description = "Whether to enable ${name}."; description = "Whether to enable ${name}.";
type = lib.types.bool; type = lib.types.bool;
}; };
/* Creates an Option attribute set for an option that specifies the /**
Creates an Option attribute set for an option that specifies the
package a module should use for some purpose. package a module should use for some purpose.
The package is specified in the third argument under `default` as a list of strings The package is specified in the third argument under `default` as a list of strings
@ -137,66 +220,99 @@ rec {
If you want users to be able to set no package, pass `nullable = true`. If you want users to be able to set no package, pass `nullable = true`.
In this mode a `default = null` will not be interpreted as no default and is interpreted literally. In this mode a `default = null` will not be interpreted as no default and is interpreted literally.
Type: mkPackageOption :: pkgs -> (string|[string]) -> { nullable? :: bool, default? :: string|[string], example? :: null|string|[string], extraDescription? :: string, pkgsText? :: string } -> option
Example: # Inputs
`pkgs`
: Package set (an instantiation of nixpkgs such as pkgs in modules or another package set)
`name`
: Name for the package, shown in option description
Structured function argument
: Attribute set containing the following attributes.
`nullable`
: Optional whether the package can be null, for example to disable installing a package altogether. Default: `false`
`default`
: Optional attribute path where the default package is located. Default: `name`
If omitted will be copied from `name`
`example`
: Optional string or an attribute path to use as an example. Default: `null`
`extraDescription`
: Optional additional text to include in the option description. Default: `""`
`pkgsText`
: Optional representation of the package set passed as pkgs. Default: `"pkgs"`
# Type
```
mkPackageOption :: pkgs -> (string|[string]) -> { nullable? :: bool, default? :: string|[string], example? :: null|string|[string], extraDescription? :: string, pkgsText? :: string } -> option
```
# Examples
:::{.example}
## `lib.options.mkPackageOption` usage example
```nix
mkPackageOption pkgs "hello" { } mkPackageOption pkgs "hello" { }
=> { ...; default = pkgs.hello; defaultText = literalExpression "pkgs.hello"; description = "The hello package to use."; type = package; } => { ...; default = pkgs.hello; defaultText = literalExpression "pkgs.hello"; description = "The hello package to use."; type = package; }
Example:
mkPackageOption pkgs "GHC" { mkPackageOption pkgs "GHC" {
default = [ "ghc" ]; default = [ "ghc" ];
example = "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])"; example = "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])";
} }
=> { ...; default = pkgs.ghc; defaultText = literalExpression "pkgs.ghc"; description = "The GHC package to use."; example = literalExpression "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])"; type = package; } => { ...; default = pkgs.ghc; defaultText = literalExpression "pkgs.ghc"; description = "The GHC package to use."; example = literalExpression "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])"; type = package; }
Example:
mkPackageOption pkgs [ "python3Packages" "pytorch" ] { mkPackageOption pkgs [ "python3Packages" "pytorch" ] {
extraDescription = "This is an example and doesn't actually do anything."; extraDescription = "This is an example and doesn't actually do anything.";
} }
=> { ...; default = pkgs.python3Packages.pytorch; defaultText = literalExpression "pkgs.python3Packages.pytorch"; description = "The pytorch package to use. This is an example and doesn't actually do anything."; type = package; } => { ...; default = pkgs.python3Packages.pytorch; defaultText = literalExpression "pkgs.python3Packages.pytorch"; description = "The pytorch package to use. This is an example and doesn't actually do anything."; type = package; }
Example:
mkPackageOption pkgs "nushell" { mkPackageOption pkgs "nushell" {
nullable = true; nullable = true;
} }
=> { ...; default = pkgs.nushell; defaultText = literalExpression "pkgs.nushell"; description = "The nushell package to use."; type = nullOr package; } => { ...; default = pkgs.nushell; defaultText = literalExpression "pkgs.nushell"; description = "The nushell package to use."; type = nullOr package; }
Example:
mkPackageOption pkgs "coreutils" { mkPackageOption pkgs "coreutils" {
default = null; default = null;
} }
=> { ...; description = "The coreutils package to use."; type = package; } => { ...; description = "The coreutils package to use."; type = package; }
Example:
mkPackageOption pkgs "dbus" { mkPackageOption pkgs "dbus" {
nullable = true; nullable = true;
default = null; default = null;
} }
=> { ...; default = null; description = "The dbus package to use."; type = nullOr package; } => { ...; default = null; description = "The dbus package to use."; type = nullOr package; }
Example:
mkPackageOption pkgs.javaPackages "OpenJFX" { mkPackageOption pkgs.javaPackages "OpenJFX" {
default = "openjfx20"; default = "openjfx20";
pkgsText = "pkgs.javaPackages"; pkgsText = "pkgs.javaPackages";
} }
=> { ...; default = pkgs.javaPackages.openjfx20; defaultText = literalExpression "pkgs.javaPackages.openjfx20"; description = "The OpenJFX package to use."; type = package; } => { ...; default = pkgs.javaPackages.openjfx20; defaultText = literalExpression "pkgs.javaPackages.openjfx20"; description = "The OpenJFX package to use."; type = package; }
```
:::
*/ */
mkPackageOption = mkPackageOption = pkgs:
# Package set (an instantiation of nixpkgs such as pkgs in modules or another package set)
pkgs:
# Name for the package, shown in option description
name: name:
{ {
# Whether the package can be null, for example to disable installing a package altogether (defaults to false)
nullable ? false, nullable ? false,
# The attribute path where the default package is located (may be omitted, in which case it is copied from `name`)
default ? name, default ? name,
# A string or an attribute path to use as an example (may be omitted)
example ? null, example ? null,
# Additional text to include in the option description (may be omitted)
extraDescription ? "", extraDescription ? "",
# Representation of the package set passed as pkgs (defaults to `"pkgs"`)
pkgsText ? "pkgs" pkgsText ? "pkgs"
}: }:
let let
@ -220,16 +336,27 @@ rec {
(if isList example then "${pkgsText}." + concatStringsSep "." example else example); (if isList example then "${pkgsText}." + concatStringsSep "." example else example);
}); });
/* Deprecated alias of mkPackageOption, to be removed in 25.05. /**
Deprecated alias of mkPackageOption, to be removed in 25.05.
Previously used to create options with markdown documentation, which is no longer required. Previously used to create options with markdown documentation, which is no longer required.
*/ */
mkPackageOptionMD = lib.warn "mkPackageOptionMD is deprecated and will be removed in 25.05; please use mkPackageOption." mkPackageOption; mkPackageOptionMD = lib.warn "mkPackageOptionMD is deprecated and will be removed in 25.05; please use mkPackageOption." mkPackageOption;
/* This option accepts anything, but it does not produce any result. /**
This option accepts arbitrary definitions, but it does not produce an option value.
This is useful for sharing a module across different module sets This is useful for sharing a module across different module sets
without having to implement similar features as long as the without having to implement similar features as long as the
values of the options are not accessed. */ values of the options are not accessed.
# Inputs
`attrs`
: Attribute set whose attributes override the argument to `mkOption`.
*/
mkSinkUndeclaredOptions = attrs: mkOption ({ mkSinkUndeclaredOptions = attrs: mkOption ({
internal = true; internal = true;
visible = false; visible = false;
@ -243,6 +370,51 @@ rec {
apply = x: throw "Option value is not readable because the option is not declared."; apply = x: throw "Option value is not readable because the option is not declared.";
} // attrs); } // attrs);
/**
A merge function that merges multiple definitions of an option into a single value
:::{.caution}
This function is used as the default merge operation in `lib.types.mkOptionType`. In most cases, explicit usage of this function is unnecessary.
:::
# Inputs
`loc`
: location of the option in the configuration as a list of strings.
e.g. `["boot" "loader "grub" "enable"]`
`defs`
: list of definition values and locations.
e.g. `[ { file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 } ]`
# Example
:::{.example}
## `lib.options.mergeDefaultOption` usage example
```nix
myType = mkOptionType {
name = "myType";
merge = mergeDefaultOption; # <- This line is redundant. It is the default aready.
};
```
:::
# Merge behavior
Merging requires all definition values to have the same type.
- If all definitions are booleans, the result of a `foldl'` with the `or` operation is returned.
- If all definitions are strings, they are concatenated. (`lib.concatStrings`)
- If all definitions are integers and all are equal, the first one is returned.
- If all definitions are lists, they are concatenated. (`++`)
- If all definitions are attribute sets, they are merged. (`lib.mergeAttrs`)
- If all definitions are functions, the first function is applied to the result of the second function. (`f -> x: f x`)
- Otherwise, an error is thrown.
*/
mergeDefaultOption = loc: defs: mergeDefaultOption = loc: defs:
let list = getValues defs; in let list = getValues defs; in
if length list == 1 then head list if length list == 1 then head list
@ -453,6 +625,47 @@ rec {
in "\n- In `${def.file}'${result}" in "\n- In `${def.file}'${result}"
) defs; ) defs;
/**
Pretty prints all option definition locations
# Inputs
`option`
: The option to pretty print
# Examples
:::{.example}
## `lib.options.showOptionWithDefLocs` usage example
```nix
showOptionWithDefLocs { loc = ["x" "y" ]; files = [ "foo.nix" "bar.nix" ]; }
"x.y, with values defined in:\n - foo.nix\n - bar.nix\n"
```
```nix
nix-repl> eval = lib.evalModules {
modules = [
{
options = {
foo = lib.mkEnableOption "foo";
};
}
];
}
nix-repl> lib.options.showOptionWithDefLocs eval.options.foo
"foo, with values defined in:\n - <unknown-file>\n"
```
:::
# Type
```
showDefsSep :: { files :: [ String ]; loc :: [ String ]; ... } -> string
```
*/
showOptionWithDefLocs = opt: '' showOptionWithDefLocs = opt: ''
${showOption opt.loc}, with values defined in: ${showOption opt.loc}, with values defined in:
${concatMapStringsSep "\n" (defFile: " - ${defFile}") opt.files} ${concatMapStringsSep "\n" (defFile: " - ${defFile}") opt.files}