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>

+329 -116
+329 -116
lib/options.nix
··· 1 - /* Nixpkgs/NixOS option handling. */ 1 + /** 2 + Module System option handling. 3 + */ 2 4 { lib }: 3 5 4 6 let ··· 45 47 in 46 48 rec { 47 49 48 - /* Returns true when the given argument is an option 50 + /** 51 + Returns true when the given argument `a` is an option 49 52 50 - Type: isOption :: a -> bool 53 + # Inputs 51 54 52 - Example: 53 - isOption 1 // => false 54 - isOption (mkOption {}) // => true 55 + `a` 56 + : Any value to check whether it is an option 57 + 58 + # Examples 59 + :::{.example} 60 + ## `lib.options.isOption` usage example 61 + 62 + ```nix 63 + isOption 1 // => false 64 + isOption (mkOption {}) // => true 65 + ``` 66 + 67 + ::: 68 + 69 + # Type 70 + 71 + ``` 72 + isOption :: a -> Bool 73 + ``` 74 + 55 75 */ 56 76 isOption = lib.isType "option"; 57 77 58 - /* Creates an Option attribute set. mkOption accepts an attribute set with the following keys: 78 + /** 79 + Creates an Option attribute set. mkOption accepts an attribute set with the following keys: 59 80 60 - All keys default to `null` when not given. 81 + # Inputs 61 82 62 - Example: 63 - mkOption { } // => { _type = "option"; } 64 - mkOption { default = "foo"; } // => { _type = "option"; default = "foo"; } 83 + Structured attribute set 84 + : Attribute set containing none or some of the following attributes. 85 + 86 + `default` 87 + : Optional default value used when no definition is given in the configuration. 88 + 89 + `defaultText` 90 + : Substitute for documenting the `default`, if evaluating the default value during documentation rendering is not possible. 91 + : Can be any nix value that evaluates. 92 + : Usage with `lib.literalMD` or `lib.literalExpression` is supported 93 + 94 + 95 + `example` 96 + : Optional example value used in the manual. 97 + : Can be any nix value that evaluates. 98 + : Usage with `lib.literalMD` or `lib.literalExpression` is supported 99 + 100 + `description` 101 + : Optional string describing the option. This is required if option documentation is generated. 102 + 103 + `relatedPackages` 104 + : Optional related packages used in the manual (see `genRelatedPackages` in `../nixos/lib/make-options-doc/default.nix`). 105 + 106 + `type` 107 + : Optional option type, providing type-checking and value merging. 108 + 109 + `apply` 110 + : Optional function that converts the option value to something else. 111 + 112 + `internal` 113 + : Optional boolean indicating whether the option is for NixOS developers only. 114 + 115 + `visible` 116 + : 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. 117 + 118 + `readOnly` 119 + : Optional boolean indicating whether the option can be set only once. 120 + 121 + `...` (any other attribute) 122 + : Any other attribute is passed through to the resulting option attribute set. 123 + 124 + # Examples 125 + :::{.example} 126 + ## `lib.options.mkOption` usage example 127 + 128 + ```nix 129 + mkOption { } // => { _type = "option"; } 130 + mkOption { default = "foo"; } // => { _type = "option"; default = "foo"; } 131 + ``` 132 + 133 + ::: 65 134 */ 66 135 mkOption = 67 136 { 68 - # Default value used when no definition is given in the configuration. 69 - default ? null, 70 - # Textual representation of the default, for the manual. 71 - defaultText ? null, 72 - # Example value used in the manual. 73 - example ? null, 74 - # String describing the option. 75 - description ? null, 76 - # Related packages used in the manual (see `genRelatedPackages` in ../nixos/lib/make-options-doc/default.nix). 77 - relatedPackages ? null, 78 - # Option type, providing type-checking and value merging. 79 - type ? null, 80 - # Function that converts the option value to something else. 81 - apply ? null, 82 - # Whether the option is for NixOS developers only. 83 - internal ? null, 84 - # 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. 85 - visible ? null, 86 - # Whether the option can be set only once 87 - readOnly ? null, 137 + default ? null, 138 + defaultText ? null, 139 + example ? null, 140 + description ? null, 141 + relatedPackages ? null, 142 + type ? null, 143 + apply ? null, 144 + internal ? null, 145 + visible ? null, 146 + readOnly ? null, 88 147 } @ attrs: 89 148 attrs // { _type = "option"; }; 90 149 91 - /* Creates an Option attribute set for a boolean value option i.e an 92 - option to be toggled on or off: 150 + /** 151 + Creates an option declaration with a default value of ´false´, and can be defined to ´true´. 93 152 94 - Example: 95 - mkEnableOption "foo" 96 - => { _type = "option"; default = false; description = "Whether to enable foo."; example = true; type = { ... }; } 153 + # Inputs 154 + 155 + `name` 156 + 157 + : Name for the created option 158 + 159 + # Examples 160 + :::{.example} 161 + ## `lib.options.mkEnableOption` usage example 162 + 163 + ```nix 164 + # module 165 + let 166 + eval = lib.evalModules { 167 + modules = [ 168 + { 169 + options.foo.enable = mkEnableOption "foo"; 170 + 171 + config.foo.enable = true; 172 + } 173 + ]: 174 + } 175 + in 176 + eval.config 177 + => { foo.enable = true; } 178 + ``` 179 + 180 + ::: 97 181 */ 98 - mkEnableOption = 99 - # Name for the created option 100 - name: mkOption { 182 + mkEnableOption = name: mkOption { 101 183 default = false; 102 184 example = true; 103 185 description = "Whether to enable ${name}."; 104 186 type = lib.types.bool; 105 187 }; 106 188 107 - /* Creates an Option attribute set for an option that specifies the 108 - package a module should use for some purpose. 189 + /** 190 + Creates an Option attribute set for an option that specifies the 191 + package a module should use for some purpose. 192 + 193 + The package is specified in the third argument under `default` as a list of strings 194 + representing its attribute path in nixpkgs (or another package set). 195 + Because of this, you need to pass nixpkgs itself (usually `pkgs` in a module; 196 + alternatively to nixpkgs itself, another package set) as the first argument. 197 + 198 + If you pass another package set you should set the `pkgsText` option. 199 + This option is used to display the expression for the package set. It is `"pkgs"` by default. 200 + If your expression is complex you should parenthesize it, as the `pkgsText` argument 201 + is usually immediately followed by an attribute lookup (`.`). 202 + 203 + The second argument may be either a string or a list of strings. 204 + It provides the display name of the package in the description of the generated option 205 + (using only the last element if the passed value is a list) 206 + and serves as the fallback value for the `default` argument. 207 + 208 + To include extra information in the description, pass `extraDescription` to 209 + append arbitrary text to the generated description. 210 + 211 + You can also pass an `example` value, either a literal string or an attribute path. 212 + 213 + The `default` argument can be omitted if the provided name is 214 + an attribute of pkgs (if `name` is a string) or a valid attribute path in pkgs (if `name` is a list). 215 + You can also set `default` to just a string in which case it is interpreted as an attribute name 216 + (a singleton attribute path, if you will). 217 + 218 + If you wish to explicitly provide no default, pass `null` as `default`. 219 + 220 + If you want users to be able to set no package, pass `nullable = true`. 221 + In this mode a `default = null` will not be interpreted as no default and is interpreted literally. 222 + 223 + 224 + # Inputs 225 + 226 + `pkgs` 227 + 228 + : Package set (an instantiation of nixpkgs such as pkgs in modules or another package set) 229 + 230 + `name` 231 + 232 + : Name for the package, shown in option description 233 + 234 + Structured function argument 235 + : Attribute set containing the following attributes. 236 + 237 + `nullable` 238 + : Optional whether the package can be null, for example to disable installing a package altogether. Default: `false` 239 + 240 + `default` 241 + : Optional attribute path where the default package is located. Default: `name` 242 + If omitted will be copied from `name` 243 + 244 + `example` 245 + : Optional string or an attribute path to use as an example. Default: `null` 246 + 247 + `extraDescription` 248 + : Optional additional text to include in the option description. Default: `""` 249 + 250 + `pkgsText` 251 + : Optional representation of the package set passed as pkgs. Default: `"pkgs"` 109 252 110 - The package is specified in the third argument under `default` as a list of strings 111 - representing its attribute path in nixpkgs (or another package set). 112 - Because of this, you need to pass nixpkgs itself (usually `pkgs` in a module; 113 - alternatively to nixpkgs itself, another package set) as the first argument. 253 + # Type 114 254 115 - If you pass another package set you should set the `pkgsText` option. 116 - This option is used to display the expression for the package set. It is `"pkgs"` by default. 117 - If your expression is complex you should parenthesize it, as the `pkgsText` argument 118 - is usually immediately followed by an attribute lookup (`.`). 255 + ``` 256 + mkPackageOption :: pkgs -> (string|[string]) -> { nullable? :: bool, default? :: string|[string], example? :: null|string|[string], extraDescription? :: string, pkgsText? :: string } -> option 257 + ``` 119 258 120 - The second argument may be either a string or a list of strings. 121 - It provides the display name of the package in the description of the generated option 122 - (using only the last element if the passed value is a list) 123 - and serves as the fallback value for the `default` argument. 259 + # Examples 260 + :::{.example} 261 + ## `lib.options.mkPackageOption` usage example 124 262 125 - To include extra information in the description, pass `extraDescription` to 126 - append arbitrary text to the generated description. 263 + ```nix 264 + mkPackageOption pkgs "hello" { } 265 + => { ...; default = pkgs.hello; defaultText = literalExpression "pkgs.hello"; description = "The hello package to use."; type = package; } 127 266 128 - You can also pass an `example` value, either a literal string or an attribute path. 129 267 130 - The `default` argument can be omitted if the provided name is 131 - an attribute of pkgs (if `name` is a string) or a valid attribute path in pkgs (if `name` is a list). 132 - You can also set `default` to just a string in which case it is interpreted as an attribute name 133 - (a singleton attribute path, if you will). 268 + mkPackageOption pkgs "GHC" { 269 + default = [ "ghc" ]; 270 + example = "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])"; 271 + } 272 + => { ...; 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; } 134 273 135 - If you wish to explicitly provide no default, pass `null` as `default`. 136 274 137 - If you want users to be able to set no package, pass `nullable = true`. 138 - In this mode a `default = null` will not be interpreted as no default and is interpreted literally. 275 + mkPackageOption pkgs [ "python3Packages" "pytorch" ] { 276 + extraDescription = "This is an example and doesn't actually do anything."; 277 + } 278 + => { ...; 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; } 139 279 140 - Type: mkPackageOption :: pkgs -> (string|[string]) -> { nullable? :: bool, default? :: string|[string], example? :: null|string|[string], extraDescription? :: string, pkgsText? :: string } -> option 141 280 142 - Example: 143 - mkPackageOption pkgs "hello" { } 144 - => { ...; default = pkgs.hello; defaultText = literalExpression "pkgs.hello"; description = "The hello package to use."; type = package; } 281 + mkPackageOption pkgs "nushell" { 282 + nullable = true; 283 + } 284 + => { ...; default = pkgs.nushell; defaultText = literalExpression "pkgs.nushell"; description = "The nushell package to use."; type = nullOr package; } 145 285 146 - Example: 147 - mkPackageOption pkgs "GHC" { 148 - default = [ "ghc" ]; 149 - example = "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])"; 150 - } 151 - => { ...; 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; } 286 + 287 + mkPackageOption pkgs "coreutils" { 288 + default = null; 289 + } 290 + => { ...; description = "The coreutils package to use."; type = package; } 152 291 153 - Example: 154 - mkPackageOption pkgs [ "python3Packages" "pytorch" ] { 155 - extraDescription = "This is an example and doesn't actually do anything."; 156 - } 157 - => { ...; 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; } 158 292 159 - Example: 160 - mkPackageOption pkgs "nushell" { 161 - nullable = true; 162 - } 163 - => { ...; default = pkgs.nushell; defaultText = literalExpression "pkgs.nushell"; description = "The nushell package to use."; type = nullOr package; } 293 + mkPackageOption pkgs "dbus" { 294 + nullable = true; 295 + default = null; 296 + } 297 + => { ...; default = null; description = "The dbus package to use."; type = nullOr package; } 164 298 165 - Example: 166 - mkPackageOption pkgs "coreutils" { 167 - default = null; 168 - } 169 - => { ...; description = "The coreutils package to use."; type = package; } 170 299 171 - Example: 172 - mkPackageOption pkgs "dbus" { 173 - nullable = true; 174 - default = null; 175 - } 176 - => { ...; default = null; description = "The dbus package to use."; type = nullOr package; } 300 + mkPackageOption pkgs.javaPackages "OpenJFX" { 301 + default = "openjfx20"; 302 + pkgsText = "pkgs.javaPackages"; 303 + } 304 + => { ...; default = pkgs.javaPackages.openjfx20; defaultText = literalExpression "pkgs.javaPackages.openjfx20"; description = "The OpenJFX package to use."; type = package; } 305 + ``` 177 306 178 - Example: 179 - mkPackageOption pkgs.javaPackages "OpenJFX" { 180 - default = "openjfx20"; 181 - pkgsText = "pkgs.javaPackages"; 182 - } 183 - => { ...; default = pkgs.javaPackages.openjfx20; defaultText = literalExpression "pkgs.javaPackages.openjfx20"; description = "The OpenJFX package to use."; type = package; } 307 + ::: 184 308 */ 185 - mkPackageOption = 186 - # Package set (an instantiation of nixpkgs such as pkgs in modules or another package set) 187 - pkgs: 188 - # Name for the package, shown in option description 309 + mkPackageOption = pkgs: 189 310 name: 190 311 { 191 - # Whether the package can be null, for example to disable installing a package altogether (defaults to false) 192 312 nullable ? false, 193 - # The attribute path where the default package is located (may be omitted, in which case it is copied from `name`) 194 313 default ? name, 195 - # A string or an attribute path to use as an example (may be omitted) 196 314 example ? null, 197 - # Additional text to include in the option description (may be omitted) 198 315 extraDescription ? "", 199 - # Representation of the package set passed as pkgs (defaults to `"pkgs"`) 200 316 pkgsText ? "pkgs" 201 317 }: 202 318 let ··· 220 336 (if isList example then "${pkgsText}." + concatStringsSep "." example else example); 221 337 }); 222 338 223 - /* Deprecated alias of mkPackageOption, to be removed in 25.05. 224 - Previously used to create options with markdown documentation, which is no longer required. 339 + /** 340 + Deprecated alias of mkPackageOption, to be removed in 25.05. 341 + 342 + Previously used to create options with markdown documentation, which is no longer required. 225 343 */ 226 344 mkPackageOptionMD = lib.warn "mkPackageOptionMD is deprecated and will be removed in 25.05; please use mkPackageOption." mkPackageOption; 227 345 228 - /* This option accepts anything, but it does not produce any result. 346 + /** 347 + This option accepts arbitrary definitions, but it does not produce an option value. 348 + 349 + This is useful for sharing a module across different module sets 350 + without having to implement similar features as long as the 351 + values of the options are not accessed. 352 + 353 + 354 + # Inputs 355 + 356 + `attrs` 229 357 230 - This is useful for sharing a module across different module sets 231 - without having to implement similar features as long as the 232 - values of the options are not accessed. */ 358 + : Attribute set whose attributes override the argument to `mkOption`. 359 + */ 233 360 mkSinkUndeclaredOptions = attrs: mkOption ({ 234 361 internal = true; 235 362 visible = false; ··· 243 370 apply = x: throw "Option value is not readable because the option is not declared."; 244 371 } // attrs); 245 372 373 + /** 374 + A merge function that merges multiple definitions of an option into a single value 375 + 376 + :::{.caution} 377 + This function is used as the default merge operation in `lib.types.mkOptionType`. In most cases, explicit usage of this function is unnecessary. 378 + ::: 379 + 380 + # Inputs 381 + 382 + `loc` 383 + : location of the option in the configuration as a list of strings. 384 + 385 + e.g. `["boot" "loader "grub" "enable"]` 386 + 387 + `defs` 388 + : list of definition values and locations. 389 + 390 + e.g. `[ { file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 } ]` 391 + 392 + # Example 393 + :::{.example} 394 + ## `lib.options.mergeDefaultOption` usage example 395 + 396 + ```nix 397 + myType = mkOptionType { 398 + name = "myType"; 399 + merge = mergeDefaultOption; # <- This line is redundant. It is the default aready. 400 + }; 401 + ``` 402 + 403 + ::: 404 + 405 + # Merge behavior 406 + 407 + Merging requires all definition values to have the same type. 408 + 409 + - If all definitions are booleans, the result of a `foldl'` with the `or` operation is returned. 410 + - If all definitions are strings, they are concatenated. (`lib.concatStrings`) 411 + - If all definitions are integers and all are equal, the first one is returned. 412 + - If all definitions are lists, they are concatenated. (`++`) 413 + - If all definitions are attribute sets, they are merged. (`lib.mergeAttrs`) 414 + - If all definitions are functions, the first function is applied to the result of the second function. (`f -> x: f x`) 415 + - Otherwise, an error is thrown. 416 + 417 + */ 246 418 mergeDefaultOption = loc: defs: 247 419 let list = getValues defs; in 248 420 if length list == 1 then head list ··· 258 430 Require a single definition. 259 431 260 432 WARNING: Does not perform nested checks, as this does not run the merge function! 261 - */ 433 + */ 262 434 mergeOneOption = mergeUniqueOption { message = ""; }; 263 435 264 436 /* ··· 453 625 in "\n- In `${def.file}'${result}" 454 626 ) defs; 455 627 628 + /** 629 + Pretty prints all option definition locations 630 + 631 + # Inputs 632 + 633 + `option` 634 + : The option to pretty print 635 + 636 + # Examples 637 + :::{.example} 638 + ## `lib.options.showOptionWithDefLocs` usage example 639 + 640 + 641 + ```nix 642 + showOptionWithDefLocs { loc = ["x" "y" ]; files = [ "foo.nix" "bar.nix" ]; } 643 + "x.y, with values defined in:\n - foo.nix\n - bar.nix\n" 644 + ``` 645 + 646 + ```nix 647 + nix-repl> eval = lib.evalModules { 648 + modules = [ 649 + { 650 + options = { 651 + foo = lib.mkEnableOption "foo"; 652 + }; 653 + } 654 + ]; 655 + } 656 + 657 + nix-repl> lib.options.showOptionWithDefLocs eval.options.foo 658 + "foo, with values defined in:\n - <unknown-file>\n" 659 + ``` 660 + 661 + ::: 662 + 663 + # Type 664 + 665 + ``` 666 + showDefsSep :: { files :: [ String ]; loc :: [ String ]; ... } -> string 667 + ``` 668 + */ 456 669 showOptionWithDefLocs = opt: '' 457 670 ${showOption opt.loc}, with values defined in: 458 671 ${concatMapStringsSep "\n" (defFile: " - ${defFile}") opt.files}