2025-01-13 22:02:34 +01:00
/* *
Module System option handling .
* /
2017-07-28 20:05:35 -04:00
{ lib }:
2009-02-09 16:51:03 +00:00
2020-10-20 13:47:24 +02:00
let
inherit ( lib )
2020-10-22 13:45:25 +02:00
all
collect
concatLists
concatMap
2022-06-15 13:11:22 +02:00
concatMapStringsSep
2020-10-22 13:45:25 +02:00
filter
foldl'
head
2021-08-10 19:54:32 +02:00
tail
2020-10-22 13:45:25 +02:00
isAttrs
isBool
isDerivation
isFunction
isInt
isList
isString
length
mapAttrs
optional
optionals
take
;
inherit ( lib . attrsets )
2022-01-19 17:09:38 +01:00
attrByPath
2020-10-22 13:45:25 +02:00
optionalAttrs
2025-04-12 05:56:30 +01:00
showAttrPath
2020-10-22 13:45:25 +02:00
;
inherit ( lib . strings )
concatMapStrings
concatStringsSep
;
inherit ( lib . types )
mkOptionType
2020-10-20 13:47:24 +02:00
;
2022-02-20 16:17:28 +01:00
inherit ( lib . lists )
last
2025-04-12 05:56:30 +01:00
toList
2022-02-20 16:17:28 +01:00
;
2023-02-09 07:38:40 +00:00
prioritySuggestion = ''
2025-04-01 20:10:43 +02:00
Use ` lib . mkForce value ` or ` lib . mkDefault value ` to change the priority on any of these definitions .
2023-02-09 07:38:40 +00:00
'' ;
2020-10-20 13:47:24 +02:00
in
2009-02-09 16:51:03 +00:00
rec {
2025-01-13 22:02:34 +01:00
/* *
Returns true when the given argument ` a ` is an option
2018-10-28 21:31:35 +01:00
2025-01-13 22:02:34 +01:00
# 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
` ` `
2018-10-28 21:31:35 +01:00
* /
2013-10-23 18:20:39 +02:00
isOption = lib . isType " o p t i o n " ;
2017-10-30 18:12:49 +01:00
2025-01-13 22:02:34 +01:00
/* *
Creates an Option attribute set . mkOption accepts an attribute set with the following keys :
2018-10-28 21:31:35 +01:00
2025-01-13 22:02:34 +01:00
# Inputs
2018-10-28 21:31:35 +01:00
2025-01-13 22:02:34 +01:00
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 " s h a l l o w " 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 = " o p t i o n " ; }
mkOption { default = " f o o " ; } // = > { _type = " o p t i o n " ; default = " f o o " ; }
` ` `
: : :
2018-10-28 21:31:35 +01:00
* /
2013-10-30 15:33:20 +01:00
mkOption =
2018-10-28 21:31:35 +01:00
{
2025-01-13 22:02:34 +01:00
default ? null ,
defaultText ? null ,
example ? null ,
description ? null ,
relatedPackages ? null ,
type ? null ,
apply ? null ,
internal ? null ,
visible ? null ,
readOnly ? null ,
2025-04-01 20:10:43 +02:00
} @ attrs :
2013-10-30 15:33:20 +01:00
attrs // { _type = " o p t i o n " ; } ;
2009-05-27 20:25:17 +00:00
2025-01-13 22:02:34 +01:00
/* *
Creates an option declaration with a default value of ´ false ´ , and can be defined to ´ true ´ .
2018-10-28 21:31:35 +01:00
2025-01-13 22:02:34 +01:00
# Inputs
` name `
: Name for the created option
# Examples
: : : { . example }
## `lib.options.mkEnableOption` usage example
` ` ` nix
# module
let
eval = lib . evalModules {
modules = [
{
options . foo . enable = mkEnableOption " f o o " ;
config . foo . enable = true ;
}
] :
}
in
eval . config
= > { foo . enable = true ; }
` ` `
: : :
2018-10-28 21:31:35 +01:00
* /
2025-04-01 20:10:43 +02:00
mkEnableOption =
name :
mkOption {
default = false ;
example = true ;
description = " W h e t h e r t o e n a b l e ${ name } . " ;
type = lib . types . bool ;
} ;
2013-07-18 15:13:42 -04:00
2025-01-13 22:02:34 +01:00
/* *
Creates an Option attribute set for an option that specifies the
package a module should use for some purpose .
2022-01-19 17:09:38 +01:00
2025-01-13 22:02:34 +01:00
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 ) .
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 .
2023-10-06 12:44:48 +02:00
2025-01-13 22:02:34 +01:00
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 ` " p k g s " ` by default .
If your expression is complex you should parenthesize it , as the ` pkgsText ` argument
is usually immediately followed by an attribute lookup ( ` . ` ) .
2022-01-21 10:41:34 +01:00
2025-01-13 22:02:34 +01:00
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
( using only the last element if the passed value is a list )
and serves as the fallback value for the ` default ` argument .
2022-01-21 10:41:34 +01:00
2025-01-13 22:02:34 +01:00
To include extra information in the description , pass ` extraDescription ` to
append arbitrary text to the generated description .
2023-10-06 12:43:26 +02:00
2025-01-13 22:02:34 +01:00
You can also pass an ` example ` value , either a literal string or an attribute path .
2022-01-21 10:41:34 +01:00
2025-01-13 22:02:34 +01:00
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 ) .
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 ) .
2022-01-21 10:41:34 +01:00
2025-01-13 22:02:34 +01:00
If you wish to explicitly provide no default , pass ` null ` as ` default ` .
2022-12-24 14:08:11 +01:00
2025-01-13 22:02:34 +01:00
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 .
2023-10-06 12:43:26 +02:00
2025-01-13 22:02:34 +01:00
# Inputs
2022-01-21 10:41:34 +01:00
2025-01-13 22:02:34 +01:00
` pkgs `
2022-02-20 16:17:28 +01:00
2025-01-13 22:02:34 +01:00
: Package set ( an instantiation of nixpkgs such as pkgs in modules or another package set )
2023-10-06 12:43:26 +02:00
2025-01-13 22:02:34 +01:00
` name `
2022-02-20 16:17:28 +01:00
2025-01-13 22:02:34 +01:00
: Name for the package , shown in option description
2023-10-06 12:43:26 +02:00
2025-01-13 22:02:34 +01:00
Structured function argument
: Attribute set containing the following attributes .
2023-10-06 12:44:48 +02:00
2025-01-13 22:02:34 +01:00
` 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 : ` " p k g s " `
# 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 " h e l l o " { }
= > { . . . ; default = pkgs . hello ; defaultText = literalExpression " p k g s . h e l l o " ; description = " T h e h e l l o p a c k a g e t o u s e . " ; type = package ; }
mkPackageOption pkgs " G H C " {
default = [ " g h c " ] ;
example = " p k g s . h a s k e l l . p a c k a g e s . g h c 9 2 . g h c . w i t h P a c k a g e s ( h k g s : [ h k g s . p r i m e s ] ) " ;
}
= > { . . . ; default = pkgs . ghc ; defaultText = literalExpression " p k g s . g h c " ; description = " T h e G H C p a c k a g e t o u s e . " ; example = literalExpression " p k g s . h a s k e l l . p a c k a g e s . g h c 9 2 . g h c . w i t h P a c k a g e s ( h k g s : [ h k g s . p r i m e s ] ) " ; type = package ; }
mkPackageOption pkgs [ " p y t h o n 3 P a c k a g e s " " p y t o r c h " ] {
extraDescription = " T h i s i s a n e x a m p l e a n d d o e s n ' t a c t u a l l y d o a n y t h i n g . " ;
}
= > { . . . ; default = pkgs . python3Packages . pytorch ; defaultText = literalExpression " p k g s . p y t h o n 3 P a c k a g e s . p y t o r c h " ; description = " T h e p y t o r c h p a c k a g e t o u s e . T h i s i s a n e x a m p l e a n d d o e s n ' t a c t u a l l y d o a n y t h i n g . " ; type = package ; }
mkPackageOption pkgs " n u s h e l l " {
nullable = true ;
}
= > { . . . ; default = pkgs . nushell ; defaultText = literalExpression " p k g s . n u s h e l l " ; description = " T h e n u s h e l l p a c k a g e t o u s e . " ; type = nullOr package ; }
mkPackageOption pkgs " c o r e u t i l s " {
default = null ;
}
= > { . . . ; description = " T h e c o r e u t i l s p a c k a g e t o u s e . " ; type = package ; }
mkPackageOption pkgs " d b u s " {
nullable = true ;
default = null ;
}
= > { . . . ; default = null ; description = " T h e d b u s p a c k a g e t o u s e . " ; type = nullOr package ; }
mkPackageOption pkgs . javaPackages " O p e n J F X " {
default = " o p e n j f x 2 0 " ;
pkgsText = " p k g s . j a v a P a c k a g e s " ;
}
= > { . . . ; default = pkgs . javaPackages . openjfx20 ; defaultText = literalExpression " p k g s . j a v a P a c k a g e s . o p e n j f x 2 0 " ; description = " T h e O p e n J F X p a c k a g e t o u s e . " ; type = package ; }
` ` `
: : :
2022-01-19 17:09:38 +01:00
* /
2025-04-01 20:10:43 +02:00
mkPackageOption =
pkgs : name :
{
nullable ? false ,
default ? name ,
example ? null ,
extraDescription ? " " ,
pkgsText ? " p k g s " ,
} :
let
name' = if isList name then last name else name ;
2025-04-12 05:56:30 +01:00
default' = toList default ;
defaultText = showAttrPath default' ;
2025-04-01 20:10:43 +02:00
defaultValue = attrByPath default' ( throw " ${ defaultText } c a n n o t b e f o u n d i n ${ pkgsText } " ) pkgs ;
defaults =
if default != null then
{
default = defaultValue ;
2025-04-12 05:56:30 +01:00
defaultText = literalExpression " ${ pkgsText } . ${ defaultText } " ;
2025-04-01 20:10:43 +02:00
}
else
optionalAttrs nullable {
default = null ;
} ;
in
mkOption (
defaults
// {
description =
" T h e ${ name' } p a c k a g e t o u s e . " + ( if extraDescription = = " " then " " else " " ) + extraDescription ;
2023-10-06 12:51:23 +02:00
type = with lib . types ; ( if nullable then nullOr else lib . id ) package ;
2025-04-01 20:10:43 +02:00
}
// optionalAttrs ( example != null ) {
example = literalExpression (
2025-04-12 05:56:30 +01:00
if isList example then " ${ pkgsText } . ${ showAttrPath example } " else example
2025-04-01 20:10:43 +02:00
) ;
}
) ;
2022-01-19 17:09:38 +01:00
2025-01-13 22:02:34 +01:00
/* *
Deprecated alias of mkPackageOption , to be removed in 25 .05 .
Previously used to create options with markdown documentation , which is no longer required .
2023-06-11 20:27:54 +02:00
* /
2024-06-26 23:11:19 -04:00
mkPackageOptionMD = lib . warn " m k P a c k a g e O p t i o n M D i s d e p r e c a t e d a n d w i l l b e r e m o v e d i n 2 5 . 0 5 ; p l e a s e u s e m k P a c k a g e O p t i o n . " mkPackageOption ;
2022-12-30 21:04:52 +01:00
2025-01-13 22:02:34 +01:00
/* *
This option accepts arbitrary definitions , but it does not produce an option value .
This is useful for sharing a module across different module sets
without having to implement similar features as long as the
values of the options are not accessed .
# Inputs
` attrs `
: Attribute set whose attributes override the argument to ` mkOption ` .
* /
2025-04-01 20:10:43 +02:00
mkSinkUndeclaredOptions =
attrs :
mkOption (
{
internal = true ;
visible = false ;
default = false ;
description = " S i n k f o r o p t i o n d e f i n i t i o n s . " ;
type = mkOptionType {
name = " s i n k " ;
check = x : true ;
merge = loc : defs : false ;
} ;
apply = x : throw " O p t i o n v a l u e i s n o t r e a d a b l e b e c a u s e t h e o p t i o n i s n o t d e c l a r e d . " ;
}
// attrs
) ;
2014-12-21 14:50:46 +01:00
2025-01-13 22:02:34 +01:00
/* *
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 . ` [ " b o o t " " l o a d e r " grub " " enable " ] `
` defs `
: list of definition values and locations .
e . g . ` [ { file = " / f o o . n i x " ; value = 1 ; } { file = " / b a r . n i x " ; value = 2 } ] `
# Example
: : : { . example }
## `lib.options.mergeDefaultOption` usage example
` ` ` nix
myType = mkOptionType {
name = " m y T y p e " ;
2025-06-02 15:54:57 +02:00
merge = mergeDefaultOption ; # <- This line is redundant. It is the default already.
2025-01-13 22:02:34 +01:00
} ;
` ` `
: : :
# 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 .
* /
2025-04-01 20:10:43 +02:00
mergeDefaultOption =
loc : defs :
let
list = getValues defs ;
in
if length list = = 1 then
head list
else if all isFunction list then
x : mergeDefaultOption loc ( map ( f : f x ) list )
else if all isList list then
concatLists list
else if all isAttrs list then
foldl' lib . mergeAttrs { } list
else if all isBool list then
foldl' lib . or false list
else if all isString list then
lib . concatStrings list
else if all isInt list && all ( x : x = = head list ) list then
head list
else
throw " C a n n o t m e r g e d e f i n i t i o n s o f ` ${ showOption loc } ' . D e f i n i t i o n v a l u e s : ${ showDefs defs } " ;
2009-02-09 16:51:03 +00:00
2025-02-12 14:38:20 +07:00
/* *
2024-01-28 14:09:27 +01:00
Require a single definition .
WARNING : Does not perform nested checks , as this does not run the merge function !
2025-01-13 22:02:34 +01:00
* /
2022-01-24 16:23:18 +01:00
mergeOneOption = mergeUniqueOption { message = " " ; } ;
2013-10-30 14:21:41 +01:00
2025-02-12 14:38:20 +07:00
/* *
2024-01-28 14:09:27 +01:00
Require a single definition .
NOTE : When the type is not checked completely by check , pass a merge function for further checking ( of sub-attributes , etc ) .
2025-02-12 14:38:20 +07:00
# Inputs
` loc `
: 2 \ . Function argument
` defs `
: 3 \ . Function argument
* /
2025-04-01 20:10:43 +02:00
mergeUniqueOption =
args @ {
2024-02-04 16:02:13 +01:00
message ,
# WARNING: the default merge function assumes that the definition is a valid (option) value. You MUST pass a merge function if the return value needs to be
2025-06-02 15:54:57 +02:00
# - type checked beyond what .check does (which should be very little; only on the value head; not attribute values, etc)
2024-02-04 16:02:13 +01:00
# - if you want attribute values to be checked, or list items
# - if you want coercedTo-like behavior to work
2025-04-01 20:10:43 +02:00
merge ? loc : defs : ( head defs ) . value ,
} :
2024-02-04 16:02:13 +01:00
loc : defs :
2025-04-01 20:10:43 +02:00
if length defs = = 1 then
merge loc defs
else
assert length defs > 1 ;
throw " T h e o p t i o n ` ${ showOption loc } ' i s d e f i n e d m u l t i p l e t i m e s w h i l e i t ' s e x p e c t e d t o b e u n i q u e . \n ${ message } \n D e f i n i t i o n v a l u e s : ${ showDefs defs } \n ${ prioritySuggestion } " ;
2013-10-30 14:21:41 +01:00
2025-02-12 14:38:20 +07:00
/* *
" M e r g e " option definitions by checking that they all have the same value .
# Inputs
` loc `
: 1 \ . Function argument
` defs `
: 2 \ . Function argument
* /
2025-04-01 20:10:43 +02:00
mergeEqualOption =
loc : defs :
if defs = = [ ] then
abort " T h i s c a s e s h o u l d n e v e r h a p p e n . "
2020-09-15 20:30:48 +02:00
# Return early if we only have one element
# This also makes it work for functions, because the foldl' below would try
# to compare the first element with itself, which is false for functions
2025-04-01 20:10:43 +02:00
else if length defs = = 1 then
( head defs ) . value
else
( foldl' (
first : def :
if def . value != first . value then
throw " T h e o p t i o n ` ${ showOption loc } ' h a s c o n f l i c t i n g d e f i n i t i o n v a l u e s : ${
showDefs [
first
def
]
} \ n $ { prioritySuggestion } "
else
first
) ( head defs ) ( tail defs ) ) . value ;
2015-06-15 18:04:27 +02:00
2025-02-12 14:38:20 +07:00
/* *
Extracts values of all " v a l u e " keys of the given list .
2018-10-28 21:31:35 +01:00
2025-02-12 14:38:20 +07:00
# Type
2018-10-28 21:31:35 +01:00
2025-02-12 14:38:20 +07:00
` ` `
getValues : : [ { value : : a ; } ] -> [ a ]
` ` `
# Examples
: : : { . example }
## `getValues` usage example
` ` ` nix
getValues [ { value = 1 ; } { value = 2 ; } ] // = > [ 1 2 ]
getValues [ ] // = > [ ]
` ` `
: : :
2018-10-28 21:31:35 +01:00
* /
2013-10-30 14:21:41 +01:00
getValues = map ( x : x . value ) ;
2017-10-30 18:12:49 +01:00
2025-02-12 14:38:20 +07:00
/* *
Extracts values of all " f i l e " keys of the given list
# Type
` ` `
getFiles : : [ { file : : a ; } ] -> [ a ]
` ` `
# Examples
: : : { . example }
## `getFiles` usage example
2018-10-28 21:31:35 +01:00
2025-02-12 14:38:20 +07:00
` ` ` nix
getFiles [ { file = " f i l e 1 " ; } { file = " f i l e 2 " ; } ] // = > [ " f i l e 1 " " f i l e 2 " ]
getFiles [ ] // = > [ ]
` ` `
2018-10-28 21:31:35 +01:00
2025-02-12 14:38:20 +07:00
: : :
2018-10-28 21:31:35 +01:00
* /
2013-10-30 14:21:41 +01:00
getFiles = map ( x : x . file ) ;
2009-02-09 16:51:03 +00:00
2009-06-11 16:03:38 +00:00
# Generate documentation template from the list of option declaration like
# the set generated with filterOptionSets.
2025-04-01 20:10:43 +02:00
optionAttrSetToDocList = optionAttrSetToDocList' [ ] ;
2013-10-28 14:25:58 +01:00
2025-04-01 20:10:43 +02:00
optionAttrSetToDocList' =
_ : options :
concatMap (
opt :
2013-10-28 14:25:58 +01:00
let
2022-12-10 23:23:42 +01:00
name = showOption opt . loc ;
2025-04-01 20:10:43 +02:00
docOption =
{
loc = opt . loc ;
inherit name ;
description = opt . description or null ;
declarations = filter ( x : x != unknownModule ) opt . declarations ;
internal = opt . internal or false ;
visible = if ( opt ? visible && opt . visible = = " s h a l l o w " ) then true else opt . visible or true ;
readOnly = opt . readOnly or false ;
type = opt . type . description or " u n s p e c i f i e d " ;
}
// optionalAttrs ( opt ? example ) {
example = builtins . addErrorContext " w h i l e e v a l u a t i n g t h e e x a m p l e o f o p t i o n ` ${ name } ` " (
2022-12-10 23:23:42 +01:00
renderOptionValue opt . example
) ;
2025-04-01 20:10:43 +02:00
}
// optionalAttrs ( opt ? defaultText || opt ? default ) {
default = builtins . addErrorContext " w h i l e e v a l u a t i n g t h e ${
if opt ? defaultText then " d e f a u l t T e x t " else " d e f a u l t v a l u e "
} of option ` $ { name } ` " ( r e n d e r O p t i o n V a l u e ( o p t . d e f a u l t T e x t o r o p t . d e f a u l t ) ) ;
}
// optionalAttrs ( opt ? relatedPackages && opt . relatedPackages != null ) {
inherit ( opt ) relatedPackages ;
} ;
2013-10-28 14:25:58 +01:00
subOptions =
2025-04-01 20:10:43 +02:00
let
ss = opt . type . getSubOptions opt . loc ;
in
if ss != { } then optionAttrSetToDocList' opt . loc ss else [ ] ;
2021-10-28 18:04:49 +02:00
subOptionsVisible = docOption . visible && opt . visible or null != " s h a l l o w " ;
2013-10-28 14:25:58 +01:00
in
2025-04-01 20:10:43 +02:00
# To find infinite recursion in NixOS option docs:
# builtins.trace opt.loc
[ docOption ] ++ optionals subOptionsVisible subOptions
) ( collect isOption options ) ;
2009-02-09 16:51:03 +00:00
2025-02-12 14:38:20 +07:00
/* *
This function recursively removes all derivation attributes from
` x ` except for the ` name ` attribute .
This is to make the generation of ` options . xml ` much more
efficient : the XML representation of derivations is very large
( on the order of megabytes ) and is not actually used by the
manual generator .
This function was made obsolete by renderOptionValue and is kept for
compatibility with out-of-tree code .
# Inputs
2018-10-28 21:31:35 +01:00
2025-02-12 14:38:20 +07:00
` x `
2022-11-03 15:56:27 +01:00
2025-02-12 14:38:20 +07:00
: 1 \ . Function argument
2018-10-28 21:31:35 +01:00
* /
2025-04-01 20:10:43 +02:00
scrubOptionValue =
x :
2013-10-30 16:19:07 +01:00
if isDerivation x then
2025-04-01 20:10:43 +02:00
{
type = " d e r i v a t i o n " ;
drvPath = x . name ;
outPath = x . name ;
name = x . name ;
}
else if isList x then
map scrubOptionValue x
else if isAttrs x then
mapAttrs ( n : v : scrubOptionValue v ) ( removeAttrs x [ " _ a r g s " ] )
else
x ;
2011-09-05 10:14:24 +00:00
2025-02-12 14:38:20 +07:00
/* *
Ensures that the given option value ( default or example ) is a ` _type ` d string
by rendering Nix values to ` literalExpression ` s .
# Inputs
` v `
: 1 \ . Function argument
2022-11-03 15:56:27 +01:00
* /
2025-04-01 20:10:43 +02:00
renderOptionValue =
v :
if v ? _type && v ? text then
v
else
literalExpression (
lib . generators . toPretty {
multiline = true ;
allowPrettyValues = true ;
} v
) ;
2022-11-03 15:56:27 +01:00
2025-02-12 14:38:20 +07:00
/* *
For use in the ` defaultText ` and ` example ` option attributes . Causes the
given string to be rendered verbatim in the documentation as Nix code . This
is necessary for complex values , e . g . functions , or values that depend on
other values or packages .
# Inputs
` text `
: 1 \ . Function argument
2018-10-28 21:31:35 +01:00
* /
2025-04-01 20:10:43 +02:00
literalExpression =
text :
if ! isString text then
throw " l i t e r a l E x p r e s s i o n e x p e c t s a s t r i n g . "
else
{
_type = " l i t e r a l E x p r e s s i o n " ;
inherit text ;
} ;
2021-10-03 17:19:19 +02:00
2024-02-03 16:13:04 +01:00
literalExample = lib . warn " l i b . l i t e r a l E x a m p l e i s d e p r e c a t e d , u s e l i b . l i t e r a l E x p r e s s i o n i n s t e a d , o r u s e l i b . l i t e r a l M D f o r a n o n - N i x d e s c r i p t i o n . " literalExpression ;
2011-09-05 10:14:24 +00:00
2025-02-12 14:38:20 +07:00
/* *
For use in the ` defaultText ` and ` example ` option attributes . Causes the
given MD text to be inserted verbatim in the documentation , for when
a ` literalExpression ` would be too hard to read .
# Inputs
` text `
: 1 \ . Function argument
2022-06-03 21:47:57 +02:00
* /
2025-04-01 20:10:43 +02:00
literalMD =
text :
if ! isString text then
throw " l i t e r a l M D e x p e c t s a s t r i n g . "
else
{
_type = " l i t e r a l M D " ;
inherit text ;
} ;
2022-06-03 21:47:57 +02:00
2018-10-28 21:31:35 +01:00
# Helper functions.
2011-09-05 10:14:24 +00:00
2025-02-12 14:38:20 +07:00
/* *
Convert an option , described as a list of the option parts to a
human-readable version .
2018-03-05 09:54:21 -05:00
2025-02-12 14:38:20 +07:00
# Inputs
` parts `
: 1 \ . Function argument
# Examples
: : : { . example }
## `showOption` usage example
` ` ` nix
( showOption [ " f o o " " b a r " " b a z " ] ) = = " f o o . b a r . b a z "
( showOption [ " f o o " " b a r . b a z " " t u x " ] ) = = " f o o . \" b a r . b a z \" . t u x "
( showOption [ " w i n d o w M a n a g e r " " 2 b w m " " e n a b l e " ] ) = = " w i n d o w M a n a g e r . \" 2 b w m \" . e n a b l e "
Placeholders will not be quoted as they are not actual values :
( showOption [ " f o o " " * " " b a r " ] ) = = " f o o . * . b a r "
( showOption [ " f o o " " < n a m e > " " b a r " ] ) = = " f o o . < n a m e > . b a r "
( showOption [ " f o o " " < m y P l a c e h o l d e r > " " b a r " ] ) = = " f o o . < m y P l a c e h o l d e r > . b a r "
` ` `
: : :
2018-10-28 21:31:35 +01:00
* /
2025-04-01 20:10:43 +02:00
showOption =
parts :
let
# If the part is a named placeholder of the form "<...>" don't escape it.
# It may cause misleading escaping if somebody uses literally "<...>" in their option names.
# This is the trade-off to allow for placeholders in option names.
isNamedPlaceholder = builtins . match " < ( . * ) > " ;
escapeOptionPart =
part :
if part = = " * " || isNamedPlaceholder part != null then
part
else
lib . strings . escapeNixIdentifier part ;
in
( concatStringsSep " . " ) ( map escapeOptionPart parts ) ;
2013-10-28 19:48:30 +01:00
showFiles = files : concatStringsSep " a n d " ( map ( f : " ` ${ f } ' " ) files ) ;
2020-09-16 20:05:07 +02:00
2025-04-01 20:10:43 +02:00
showDefs =
defs :
concatMapStrings (
def :
let
# Pretty print the value for display, if successful
prettyEval = builtins . tryEval (
lib . generators . toPretty { } (
lib . generators . withRecursion {
depthLimit = 10 ;
throwOnDepthLimit = false ;
} def . value
)
) ;
# Split it into its lines
lines = filter ( v : ! isList v ) ( builtins . split " \n " prettyEval . value ) ;
# Only display the first 5 lines, and indent them for better visibility
value = concatStringsSep " \n " ( take 5 lines ++ optional ( length lines > 5 ) " . . . " ) ;
result =
# Don't print any value if evaluating the value strictly fails
if ! prettyEval . success then
" "
# Put it on a new line if it consists of multiple
else if length lines > 1 then
" : \n " + value
else
" : " + value ;
in
" \n - I n ` ${ def . file } ' ${ result } "
) defs ;
2020-09-16 20:05:07 +02:00
2025-01-13 22:02:34 +01:00
/* *
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 = [ " f o o . n i x " " b a r . n i x " ] ; }
" x . y , w i t h v a l u e s d e f i n e d i n : \n - f o o . n i x \n - b a r . n i x \n "
` ` `
` ` ` nix
nix-repl > eval = lib . evalModules {
modules = [
{
options = {
foo = lib . mkEnableOption " f o o " ;
} ;
}
] ;
}
nix-repl > lib . options . showOptionWithDefLocs eval . options . foo
" f o o , w i t h v a l u e s d e f i n e d i n : \n - < u n k n o w n - f i l e > \n "
` ` `
: : :
# Type
` ` `
showDefsSep : : { files : : [ String ] ; loc : : [ String ] ; . . . } -> string
` ` `
* /
2022-06-15 13:11:22 +02:00
showOptionWithDefLocs = opt : ''
2025-04-01 20:10:43 +02:00
$ { showOption opt . loc } , with values defined in :
$ { concatMapStringsSep " \n " ( defFile : " - ${ defFile } " ) opt . files }
'' ;
2022-06-15 13:11:22 +02:00
2013-10-28 14:25:58 +01:00
unknownModule = " < u n k n o w n - f i l e > " ;
2013-10-28 00:56:22 +01:00
2009-05-24 10:57:41 +00:00
}