2009-02-09 16:51:03 +00:00
# Nixpkgs/NixOS option handling.
2017-07-29 01:05:35 +01:00
{ lib }:
2009-02-09 16:51:03 +00:00
2020-10-20 12:47:24 +01:00
let
inherit ( lib )
2020-10-22 12:45:25 +01:00
all
collect
concatLists
concatMap
2022-06-15 12:11:22 +01:00
concatMapStringsSep
2020-10-22 12:45:25 +01:00
filter
foldl'
head
2021-08-10 18:54:32 +01:00
tail
2020-10-22 12:45:25 +01:00
isAttrs
isBool
isDerivation
isFunction
isInt
isList
isString
length
mapAttrs
optional
optionals
take
;
inherit ( lib . attrsets )
2022-01-19 16:09:38 +00:00
attrByPath
2020-10-22 12:45:25 +01:00
optionalAttrs
;
inherit ( lib . strings )
concatMapStrings
concatStringsSep
;
inherit ( lib . types )
mkOptionType
2020-10-20 12:47:24 +01:00
;
2022-02-20 15:17:28 +00:00
inherit ( lib . lists )
last
;
2023-02-09 07:38:40 +00:00
prioritySuggestion = ''
Use ` lib . mkForce value ` or ` lib . mkDefault value ` to change the priority on any of these definitions .
'' ;
2020-10-20 12:47:24 +01:00
in
2009-02-09 16:51:03 +00:00
rec {
2018-10-28 20:31:35 +00:00
/* R e t u r n s t r u e w h e n t h e g i v e n a r g u m e n t i s a n o p t i o n
Type : isOption : : a -> bool
Example :
isOption 1 // = > false
isOption ( mkOption { } ) // = > true
* /
2013-10-23 17:20:39 +01:00
isOption = lib . isType " o p t i o n " ;
2017-10-30 17:12:49 +00:00
2018-10-28 20:31:35 +00:00
/* C r e a t e s a n O p t i o n a t t r i b u t e s e t . m k O p t i o n a c c e p t s a n a t t r i b u t e s e t w i t h t h e f o l l o w i n g k e y s :
All keys default to ` null ` when not given .
Example :
mkOption { } // = > { _type = " o p t i o n " ; }
2021-10-03 16:19:19 +01:00
mkOption { default = " f o o " ; } // = > { _type = " o p t i o n " ; default = " f o o " ; }
2018-10-28 20:31:35 +00:00
* /
2013-10-30 14:33:20 +00:00
mkOption =
2018-10-28 20:31:35 +00:00
{
# Default value used when no definition is given in the configuration.
default ? null ,
# Textual representation of the default, for the manual.
defaultText ? null ,
# Example value used in the manual.
example ? null ,
# String describing the option.
description ? null ,
2019-08-26 01:01:49 +01:00
# Related packages used in the manual (see `genRelatedPackages` in ../nixos/lib/make-options-doc/default.nix).
2018-10-28 20:31:35 +00:00
relatedPackages ? 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 ,
2021-10-28 17:04:49 +01:00
# 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.
2018-10-28 20:31:35 +00:00
visible ? null ,
# Whether the option can be set only once
readOnly ? null ,
2013-10-30 14:33:20 +00:00
} @ attrs :
attrs // { _type = " o p t i o n " ; } ;
2009-05-27 21:25:17 +01:00
2018-10-28 20:31:35 +00:00
/* C r e a t e s a n O p t i o n a t t r i b u t e s e t f o r a b o o l e a n v a l u e o p t i o n i . e a n
option to be toggled on or off :
Example :
mkEnableOption " f o o "
= > { _type = " o p t i o n " ; default = false ; description = " W h e t h e r t o e n a b l e f o o . " ; example = true ; type = { . . . } ; }
* /
mkEnableOption =
# Name for the created option
name : mkOption {
2013-07-18 20:13:42 +01:00
default = false ;
example = true ;
2023-06-11 19:27:54 +01:00
description = " W h e t h e r t o e n a b l e ${ name } . " ;
2013-07-18 20:13:42 +01:00
type = lib . types . bool ;
} ;
2022-01-21 09:41:34 +00:00
/* C r e a t e s a n O p t i o n a t t r i b u t e s e t f o r a n o p t i o n t h a t s p e c i f i e s t h e
package a module should use for some purpose .
2022-01-19 16:09:38 +00:00
2022-02-20 15:17:28 +00:00
The package is specified in the third argument under ` default ` as a list of strings
2023-10-06 11:44:48 +01:00
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 .
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 09:41:34 +00:00
2022-02-20 15:17:28 +00: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 09:41:34 +00:00
2022-02-20 15:17:28 +00:00
To include extra information in the description , pass ` extraDescription ` to
append arbitrary text to the generated description .
2023-10-06 11:43:26 +01:00
2022-02-20 15:17:28 +00:00
You can also pass an ` example ` value , either a literal string or an attribute path .
2022-01-21 09:41:34 +00:00
2023-10-06 11:43:26 +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 09:41:34 +00:00
2022-02-20 15:17:28 +00:00
If you wish to explicitly provide no default , pass ` null ` as ` default ` .
2022-12-24 13:08:11 +00:00
2023-10-06 11:43:26 +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 11:44:48 +01:00
Type : mkPackageOption : : pkgs -> ( string | [ string ] ) -> { nullable ? : : bool , default ? : : string | [ string ] , example ? : : null | string | [ string ] , extraDescription ? : : string , pkgsText ? : : string } -> option
2023-03-04 21:52:02 +00:00
2022-01-21 09:41:34 +00:00
Example :
mkPackageOption pkgs " h e l l o " { }
2023-10-06 11:43:26 +01:00
= > { . . . ; 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 ; }
2022-01-21 09:41:34 +00:00
Example :
mkPackageOption pkgs " G H C " {
default = [ " g h c " ] ;
2022-11-07 14:25:37 +00:00
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 ] ) " ;
2022-01-21 09:41:34 +00:00
}
2023-10-06 11:43:26 +01:00
= > { . . . ; 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 ; }
2022-02-20 15:17:28 +00:00
Example :
2023-10-06 11:43:26 +01:00
mkPackageOption pkgs [ " p y t h o n 3 P a c k a g e s " " p y t o r c h " ] {
2022-02-20 15:17:28 +00:00
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 . " ;
}
2023-10-06 11:43:26 +01:00
= > { . . . ; 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 ; }
Example :
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 ; }
2022-02-20 15:17:28 +00:00
2023-10-06 11:43:26 +01:00
Example :
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 ; }
Example :
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 ; }
2023-10-06 11:44:48 +01:00
Example :
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 16:09:38 +00:00
* /
2022-01-21 09:41:34 +00:00
mkPackageOption =
2023-10-06 11:44:48 +01:00
# Package set (an instantiation of nixpkgs such as pkgs in modules or another package set)
2022-01-21 09:41:34 +00:00
pkgs :
# Name for the package, shown in option description
name :
2022-02-20 15:17:28 +00:00
{
2023-10-06 11:43:26 +01:00
# Whether the package can be null, for example to disable installing a package altogether (defaults to false)
2023-05-19 11:22:21 +01:00
nullable ? false ,
2023-10-06 11:43:26 +01:00
# The attribute path where the default package is located (may be omitted, in which case it is copied from `name`)
2022-02-20 15:17:28 +00:00
default ? name ,
2023-03-04 21:52:02 +00:00
# A string or an attribute path to use as an example (may be omitted)
2022-02-20 15:17:28 +00:00
example ? null ,
2023-03-04 21:52:02 +00:00
# Additional text to include in the option description (may be omitted)
2022-02-20 15:17:28 +00:00
extraDescription ? " " ,
2023-10-06 11:44:48 +01:00
# Representation of the package set passed as pkgs (defaults to `"pkgs"`)
pkgsText ? " p k g s "
2022-02-20 15:17:28 +00:00
} :
let
name' = if isList name then last name else name ;
default' = if isList default then default else [ default ] ;
2023-10-06 11:51:23 +01:00
defaultText = concatStringsSep " . " default' ;
2022-02-20 15:17:28 +00:00
defaultValue = attrByPath default'
2023-10-06 11:51:23 +01:00
( 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 ;
defaultText = literalExpression ( " ${ pkgsText } . " + defaultText ) ;
} 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 ;
type = with lib . types ; ( if nullable then nullOr else lib . id ) package ;
} // optionalAttrs ( example != null ) {
2023-05-19 11:22:21 +01:00
example = literalExpression
2023-10-06 11:44:48 +01:00
( if isList example then " ${ pkgsText } . " + concatStringsSep " . " example else example ) ;
2023-05-19 11:22:21 +01:00
} ) ;
2022-01-19 16:09:38 +00:00
2023-06-11 19:27:54 +01:00
/* A l i a s o f m k P a c k a g e O p t i o n . P r e v i o u s l y u s e d t o c r e a t e o p t i o n s w i t h m a r k d o w n
documentation , which is no longer required .
* /
mkPackageOptionMD = mkPackageOption ;
2022-12-30 20:04:52 +00:00
2018-10-28 20:31:35 +00:00
/* T h i s o p t i o n a c c e p t s a n y t h i n g , b u t i t d o e s n o t p r o d u c e a n y r e s u l t .
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 . * /
2014-12-21 13:50:46 +00: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 ) ;
2013-10-30 13:21:41 +00:00
mergeDefaultOption = loc : defs :
let list = getValues defs ; in
2012-08-13 19:19:31 +01:00
if length list == 1 then head list
2013-11-12 12:48:19 +00:00
else if all isFunction list then x : mergeDefaultOption loc ( map ( f : f x ) list )
2009-05-19 15:54:41 +01:00
else if all isList list then concatLists list
2015-07-23 16:19:21 +01:00
else if all isAttrs list then foldl' lib . mergeAttrs { } list
else if all isBool list then foldl' lib . or false list
2013-11-12 12:48:19 +00:00
else if all isString list then lib . concatStrings list
else if all isInt list && all ( x : x == head list ) list then head list
2020-09-16 19:05:53 +01:00
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
2022-01-24 15:23:18 +00:00
mergeOneOption = mergeUniqueOption { message = " " ; } ;
2013-10-30 13:21:41 +00:00
2022-01-24 00:07:32 +00:00
mergeUniqueOption = { message }: loc : defs :
if length defs == 1
then ( head defs ) . value
else assert length defs > 1 ;
2023-02-09 07:38:40 +00:00
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 13:21:41 +00:00
2015-06-15 17:04:27 +01:00
/* " M e r g e " o p t i o n d e f i n i t i o n s b y c h e c k i n g t h a t t h e y a l l h a v e t h e s a m e v a l u e . */
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 19:30:48 +01: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
2020-10-22 12:41:28 +01:00
else if length defs == 1 then ( head defs ) . value
2020-09-16 19:05:53 +01:00
else ( foldl' ( first : def :
if def . value != first . value then
2023-02-09 07:38:40 +00:00
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 } "
2015-06-15 17:04:27 +01:00
else
2021-08-10 18:54:32 +01:00
first ) ( head defs ) ( tail defs ) ) . value ;
2015-06-15 17:04:27 +01:00
2018-10-28 20:31:35 +00:00
/* E x t r a c t s v a l u e s o f a l l " v a l u e " k e y s o f t h e g i v e n l i s t .
2023-01-30 21:22:02 +00:00
Type : getValues : : [ { value : : a ; } ] -> [ a ]
2018-10-28 20:31:35 +00:00
Example :
getValues [ { value = 1 ; } { value = 2 ; } ] // = > [ 1 2 ]
getValues [ ] // = > [ ]
* /
2013-10-30 13:21:41 +00:00
getValues = map ( x : x . value ) ;
2017-10-30 17:12:49 +00:00
2018-10-28 20:31:35 +00:00
/* E x t r a c t s v a l u e s o f a l l " f i l e " k e y s o f t h e g i v e n l i s t
2023-01-30 21:22:02 +00:00
Type : getFiles : : [ { file : : a ; } ] -> [ a ]
2018-10-28 20:31:35 +00:00
Example :
getFiles [ { file = " f i l e 1 " ; } { file = " f i l e 2 " ; } ] // = > [ " f i l e 1 " " f i l e 2 " ]
getFiles [ ] // = > [ ]
* /
2013-10-30 13:21:41 +00:00
getFiles = map ( x : x . file ) ;
2009-02-09 16:51:03 +00:00
2009-06-11 17:03:38 +01:00
# Generate documentation template from the list of option declaration like
# the set generated with filterOptionSets.
2013-10-28 13:25:58 +00:00
optionAttrSetToDocList = optionAttrSetToDocList' [ ] ;
2022-11-03 14:56:27 +00:00
optionAttrSetToDocList' = _ : options :
2015-07-23 15:32:52 +01:00
concatMap ( opt :
2013-10-28 13:25:58 +00:00
let
2022-12-10 22:23:42 +00:00
name = showOption opt . loc ;
2023-05-06 15:50:08 +01:00
docOption = {
2018-02-11 22:04:09 +00:00
loc = opt . loc ;
2022-12-10 22:23:42 +00:00
inherit name ;
2019-02-22 00:05:58 +00:00
description = opt . description or null ;
2013-10-28 13:25:58 +00:00
declarations = filter ( x : x != unknownModule ) opt . declarations ;
internal = opt . internal or false ;
2021-10-28 17:04:49 +01:00
visible =
if ( opt ? visible && opt . visible == " s h a l l o w " )
then true
else opt . visible or true ;
2015-07-30 12:36:57 +01:00
readOnly = opt . readOnly or false ;
2021-06-16 11:27:47 +01:00
type = opt . type . description or " u n s p e c i f i e d " ;
2013-10-28 13:25:58 +00:00
}
2022-12-10 22:23:42 +00:00
// 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 } ` " (
renderOptionValue opt . example
) ;
}
2023-05-06 15:50:08 +01:00
// optionalAttrs ( opt ? defaultText || opt ? default ) {
2022-12-10 22:23:42 +00:00
default =
2023-05-06 15:50:08 +01:00
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 " } o f o p t i o n ` ${ name } ` " (
2022-12-10 22:23:42 +00:00
renderOptionValue ( opt . defaultText or opt . default )
) ;
}
2016-04-20 22:57:33 +01:00
// optionalAttrs ( opt ? relatedPackages && opt . relatedPackages != null ) { inherit ( opt ) relatedPackages ; } ;
2013-10-28 13:25:58 +00:00
subOptions =
let ss = opt . type . getSubOptions opt . loc ;
in if ss != { } then optionAttrSetToDocList' opt . loc ss else [ ] ;
2021-10-28 17:04:49 +01:00
subOptionsVisible = docOption . visible && opt . visible or null != " s h a l l o w " ;
2013-10-28 13:25:58 +00:00
in
2022-06-27 16:21:34 +01:00
# To find infinite recursion in NixOS option docs:
# builtins.trace opt.loc
2021-10-28 17:04:49 +01:00
[ docOption ] ++ optionals subOptionsVisible subOptions ) ( collect isOption options ) ;
2009-06-11 17:03:38 +01:00
2009-02-09 16:51:03 +00:00
2010-05-12 12:07:49 +01:00
/* T h i s f u n c t i o n r e c u r s i v e l y r e m o v e s a l l d e r i v a t i o n a t t r i b u t e s f r o m
2018-10-28 20:31:35 +00:00
` 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 .
2022-11-03 14:56:27 +00:00
This function was made obsolete by renderOptionValue and is kept for
compatibility with out-of-tree code .
2018-10-28 20:31:35 +00:00
* /
2013-10-17 13:29:51 +01:00
scrubOptionValue = x :
2013-10-30 15:19:07 +00:00
if isDerivation x then
{ type = " d e r i v a t i o n " ; drvPath = x . name ; outPath = x . name ; name = x . name ; }
2010-05-12 12:07:49 +01:00
else if isList x then map scrubOptionValue x
2010-06-01 15:24:16 +01:00
else if isAttrs x then mapAttrs ( n : v : scrubOptionValue v ) ( removeAttrs x [ " _ a r g s " ] )
2010-05-12 12:07:49 +01:00
else x ;
2011-09-05 11:14:24 +01:00
2022-11-03 14:56:27 +00:00
/* E n s u r e s t h a t t h e g i v e n o p t i o n v a l u e ( d e f a u l t o r e x a m p l e ) i s a ` _ t y p e ` d s t r i n g
by rendering Nix values to ` literalExpression ` s .
* /
renderOptionValue = v :
if v ? _type && v ? text then v
else literalExpression ( lib . generators . toPretty {
multiline = true ;
allowPrettyValues = true ;
} v ) ;
2021-10-03 16:19:19 +01:00
/* F o r u s e i n t h e ` d e f a u l t T e x t ` a n d ` e x a m p l e ` o p t i o n a t t r i b u t e s . C a u s e s t h e
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 .
2018-10-28 20:31:35 +00:00
* /
2021-10-03 16:19:19 +01: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 ; } ;
2023-06-11 18:51:46 +01:00
literalExample = lib . warn " 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 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 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 11:14:24 +01:00
2022-06-03 20:47:57 +01:00
/* T r a n s i t i o n m a r k e r f o r d o c u m e n t a t i o n t h a t ' s a l r e a d y m i g r a t e d t o m a r k d o w n
2023-06-11 19:27:54 +01:00
syntax . This is a no-op and no longer needed .
2022-06-03 20:47:57 +01:00
* /
2023-06-11 19:27:54 +01:00
mdDoc = lib . id ;
2022-06-03 20:47:57 +01:00
/* F o r u s e i n t h e ` d e f a u l t T e x t ` a n d ` e x a m p l e ` o p t i o n a t t r i b u t e s . C a u s e s t h e
given MD text to be inserted verbatim in the documentation , for when
a ` literalExpression ` would be too hard to read .
* /
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 ; } ;
2018-10-28 20:31:35 +00:00
# Helper functions.
2011-09-05 11:14:24 +01:00
2023-02-18 17:13:11 +00:00
/* C o n v e r t a n o p t i o n , d e s c r i b e d a s a l i s t o f t h e o p t i o n p a r t s t o a
human-readable version .
2018-03-05 14:54:21 +00:00
2018-10-28 20:31:35 +00:00
Example :
( showOption [ " f o o " " b a r " " b a z " ] ) == " f o o . b a r . b a z "
2023-02-18 17:13:11 +00:00
( 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 "
2020-04-14 03:49:17 +01:00
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 "
2018-10-28 20:31:35 +00:00
* /
2020-04-14 19:29:37 +01:00
showOption = parts : let
escapeOptionPart = part :
let
2022-10-07 08:59:01 +01:00
# We assume that these are "special values" and not real configuration data.
# If it is real configuration data, it is rendered incorrectly.
specialIdentifiers = [
" < n a m e > " # attrsOf (submodule {})
" * " # listOf (submodule {})
" < f u n c t i o n b o d y > " # functionTo
] ;
in if builtins . elem part specialIdentifiers
2020-04-14 19:29:37 +01:00
then part
2022-10-07 08:59:01 +01:00
else lib . strings . escapeNixIdentifier part ;
2020-04-14 19:29:37 +01:00
in ( concatStringsSep " . " ) ( map escapeOptionPart parts ) ;
2013-10-28 18:48:30 +00:00
showFiles = files : concatStringsSep " a n d " ( map ( f : " ` ${ f } ' " ) files ) ;
2020-09-16 19:05:07 +01:00
showDefs = defs : concatMapStrings ( def :
let
# Pretty print the value for display, if successful
2021-08-25 23:28:49 +01:00
prettyEval = builtins . tryEval
( lib . generators . toPretty { }
( lib . generators . withRecursion { depthLimit = 10 ; throwOnDepthLimit = false ; } def . value ) ) ;
2020-09-16 19:05:07 +01:00
# 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 ;
2022-06-15 12:11:22 +01:00
showOptionWithDefLocs = opt : ''
$ { showOption opt . loc } , with values defined in :
$ { concatMapStringsSep " \n " ( defFile : " - ${ defFile } " ) opt . files }
'' ;
2013-10-28 13:25:58 +00:00
unknownModule = " < u n k n o w n - f i l e > " ;
2013-10-27 23:56:22 +00:00
2009-05-24 11:57:41 +01:00
}