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,158 +47,272 @@ 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
`a`
: Any value to check whether it is an option
# Examples
:::{.example}
## `lib.options.isOption` usage example
```nix
isOption 1 // => false
isOption (mkOption {}) // => true
```
:::
# Type
```
isOption :: a -> Bool
```
Example:
isOption 1 // => false
isOption (mkOption {}) // => true
*/ */
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
mkOption { } // => { _type = "option"; } : Attribute set containing none or some of the following attributes.
mkOption { default = "foo"; } // => { _type = "option"; default = "foo"; }
`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 { default = "foo"; } // => { _type = "option"; default = "foo"; }
```
:::
*/ */
mkOption = mkOption =
{ {
# Default value used when no definition is given in the configuration. default ? null,
default ? null, defaultText ? null,
# Textual representation of the default, for the manual. example ? null,
defaultText ? null, description ? null,
# Example value used in the manual. relatedPackages ? null,
example ? null, type ? null,
# String describing the option. apply ? null,
description ? null, internal ? null,
# Related packages used in the manual (see `genRelatedPackages` in ../nixos/lib/make-options-doc/default.nix). visible ? null,
relatedPackages ? null, readOnly ? null,
# Option type, providing type-checking and value merging.
type ? null,
# Function that converts the option value to something else.
apply ? null,
# Whether the option is for NixOS developers only.
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,
# Whether the option can be set only once
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 /**
package a module should use for some purpose. Creates an Option attribute set for an option that specifies the
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
representing its attribute path in nixpkgs (or another package set). representing its attribute path in nixpkgs (or another package set).
Because of this, you need to pass nixpkgs itself (usually `pkgs` in a module; Because of this, you need to pass nixpkgs itself (usually `pkgs` in a module;
alternatively to nixpkgs itself, another package set) as the first argument. alternatively to nixpkgs itself, another package set) as the first argument.
If you pass another package set you should set the `pkgsText` option. If you pass another package set you should set the `pkgsText` option.
This option is used to display the expression for the package set. It is `"pkgs"` by default. This option is used to display the expression for the package set. It is `"pkgs"` by default.
If your expression is complex you should parenthesize it, as the `pkgsText` argument If your expression is complex you should parenthesize it, as the `pkgsText` argument
is usually immediately followed by an attribute lookup (`.`). is usually immediately followed by an attribute lookup (`.`).
The second argument may be either a string or a list of strings. The second argument may be either a string or a list of strings.
It provides the display name of the package in the description of the generated option It provides the display name of the package in the description of the generated option
(using only the last element if the passed value is a list) (using only the last element if the passed value is a list)
and serves as the fallback value for the `default` argument. and serves as the fallback value for the `default` argument.
To include extra information in the description, pass `extraDescription` to To include extra information in the description, pass `extraDescription` to
append arbitrary text to the generated description. append arbitrary text to the generated description.
You can also pass an `example` value, either a literal string or an attribute path. You can also pass an `example` value, either a literal string or an attribute path.
The `default` argument can be omitted if the provided name is The `default` argument can be omitted if the provided name is
an attribute of pkgs (if `name` is a string) or a valid attribute path in pkgs (if `name` is a list). an attribute of pkgs (if `name` is a string) or a valid attribute path in pkgs (if `name` is a list).
You can also set `default` to just a string in which case it is interpreted as an attribute name You can also set `default` to just a string in which case it is interpreted as an attribute name
(a singleton attribute path, if you will). (a singleton attribute path, if you will).
If you wish to explicitly provide no default, pass `null` as `default`. If you wish to explicitly provide no default, pass `null` as `default`.
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
mkPackageOption pkgs "hello" { }
=> { ...; default = pkgs.hello; defaultText = literalExpression "pkgs.hello"; description = "The hello package to use."; type = package; }
Example: `pkgs`
mkPackageOption pkgs "GHC" {
default = [ "ghc" ];
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; }
Example: : Package set (an instantiation of nixpkgs such as pkgs in modules or another package set)
mkPackageOption pkgs [ "python3Packages" "pytorch" ] {
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; }
Example: `name`
mkPackageOption pkgs "nushell" {
nullable = true;
}
=> { ...; default = pkgs.nushell; defaultText = literalExpression "pkgs.nushell"; description = "The nushell package to use."; type = nullOr package; }
Example: : Name for the package, shown in option description
mkPackageOption pkgs "coreutils" {
default = null;
}
=> { ...; description = "The coreutils package to use."; type = package; }
Example: Structured function argument
mkPackageOption pkgs "dbus" { : Attribute set containing the following attributes.
nullable = true;
default = null;
}
=> { ...; default = null; description = "The dbus package to use."; type = nullOr package; }
Example: `nullable`
mkPackageOption pkgs.javaPackages "OpenJFX" { : Optional whether the package can be null, for example to disable installing a package altogether. Default: `false`
default = "openjfx20";
pkgsText = "pkgs.javaPackages"; `default`
} : Optional attribute path where the default package is located. Default: `name`
=> { ...; default = pkgs.javaPackages.openjfx20; defaultText = literalExpression "pkgs.javaPackages.openjfx20"; description = "The OpenJFX package to use."; type = package; } 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" { }
=> { ...; default = pkgs.hello; defaultText = literalExpression "pkgs.hello"; description = "The hello package to use."; type = package; }
mkPackageOption pkgs "GHC" {
default = [ "ghc" ];
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; }
mkPackageOption pkgs [ "python3Packages" "pytorch" ] {
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; }
mkPackageOption pkgs "nushell" {
nullable = true;
}
=> { ...; default = pkgs.nushell; defaultText = literalExpression "pkgs.nushell"; description = "The nushell package to use."; type = nullOr package; }
mkPackageOption pkgs "coreutils" {
default = null;
}
=> { ...; description = "The coreutils package to use."; type = package; }
mkPackageOption pkgs "dbus" {
nullable = true;
default = null;
}
=> { ...; default = null; description = "The dbus package to use."; type = nullOr package; }
mkPackageOption pkgs.javaPackages "OpenJFX" {
default = "openjfx20";
pkgsText = "pkgs.javaPackages";
}
=> { ...; 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. /**
Previously used to create options with markdown documentation, which is no longer required. Deprecated alias of mkPackageOption, to be removed in 25.05.
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
@ -258,7 +430,7 @@ rec {
Require a single definition. Require a single definition.
WARNING: Does not perform nested checks, as this does not run the merge function! WARNING: Does not perform nested checks, as this does not run the merge function!
*/ */
mergeOneOption = mergeUniqueOption { message = ""; }; mergeOneOption = mergeUniqueOption { message = ""; };
/* /*
@ -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}