mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-10-31 22:51:22 +00:00
nixos/doc: render option values using lib.generators.toPretty
Render un`_type`d defaults and examples as `literalExpression`s using `lib.generators.toPretty` so that consumers don't have to reinvent Nix pretty-printing. `renderOptionValue` is kept internal for now intentionally. Make `toPretty` print floats as valid Nix values (without a tilde). Get rid of the now-obsolete `substSpecial` function. Move towards disallowing evaluation of packages in the manual by raising a warning on `pkgs.foo.{outPath,drvPath}`; later, this should throw an error. Instead, module authors should use `literalExpression` and `mkPackageOption`.
This commit is contained in:
parent
0b661ce32a
commit
6a117e2759
@ -278,8 +278,11 @@ rec {
|
|||||||
mapAny 0;
|
mapAny 0;
|
||||||
|
|
||||||
/* Pretty print a value, akin to `builtins.trace`.
|
/* Pretty print a value, akin to `builtins.trace`.
|
||||||
* Should probably be a builtin as well.
|
* Should probably be a builtin as well.
|
||||||
*/
|
* The pretty-printed string should be suitable for rendering default values
|
||||||
|
* in the NixOS manual. In particular, it should be as close to a valid Nix expression
|
||||||
|
* as possible.
|
||||||
|
*/
|
||||||
toPretty = {
|
toPretty = {
|
||||||
/* If this option is true, attrsets like { __pretty = fn; val = …; }
|
/* If this option is true, attrsets like { __pretty = fn; val = …; }
|
||||||
will use fn to convert val to a pretty printed representation.
|
will use fn to convert val to a pretty printed representation.
|
||||||
@ -294,7 +297,10 @@ rec {
|
|||||||
introSpace = if multiline then "\n${indent} " else " ";
|
introSpace = if multiline then "\n${indent} " else " ";
|
||||||
outroSpace = if multiline then "\n${indent}" else " ";
|
outroSpace = if multiline then "\n${indent}" else " ";
|
||||||
in if isInt v then toString v
|
in if isInt v then toString v
|
||||||
else if isFloat v then "~${toString v}"
|
# toString loses precision on floats, so we use toJSON instead. This isn't perfect
|
||||||
|
# as the resulting string may not parse back as a float (e.g. 42, 1e-06), but for
|
||||||
|
# pretty-printing purposes this is acceptable.
|
||||||
|
else if isFloat v then builtins.toJSON v
|
||||||
else if isString v then
|
else if isString v then
|
||||||
let
|
let
|
||||||
lines = filter (v: ! isList v) (builtins.split "\n" v);
|
lines = filter (v: ! isList v) (builtins.split "\n" v);
|
||||||
@ -328,7 +334,7 @@ rec {
|
|||||||
else "<function, args: {${showFnas}}>"
|
else "<function, args: {${showFnas}}>"
|
||||||
else if isAttrs v then
|
else if isAttrs v then
|
||||||
# apply pretty values if allowed
|
# apply pretty values if allowed
|
||||||
if attrNames v == [ "__pretty" "val" ] && allowPrettyValues
|
if allowPrettyValues && v ? __pretty && v ? val
|
||||||
then v.__pretty v.val
|
then v.__pretty v.val
|
||||||
else if v == {} then "{ }"
|
else if v == {} then "{ }"
|
||||||
else if v ? type && v.type == "derivation" then
|
else if v ? type && v.type == "derivation" then
|
||||||
|
@ -218,7 +218,7 @@ rec {
|
|||||||
# the set generated with filterOptionSets.
|
# the set generated with filterOptionSets.
|
||||||
optionAttrSetToDocList = optionAttrSetToDocList' [];
|
optionAttrSetToDocList = optionAttrSetToDocList' [];
|
||||||
|
|
||||||
optionAttrSetToDocList' = prefix: options:
|
optionAttrSetToDocList' = _: options:
|
||||||
concatMap (opt:
|
concatMap (opt:
|
||||||
let
|
let
|
||||||
docOption = rec {
|
docOption = rec {
|
||||||
@ -234,9 +234,8 @@ rec {
|
|||||||
readOnly = opt.readOnly or false;
|
readOnly = opt.readOnly or false;
|
||||||
type = opt.type.description or "unspecified";
|
type = opt.type.description or "unspecified";
|
||||||
}
|
}
|
||||||
// optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
|
// optionalAttrs (opt ? example) { example = renderOptionValue opt.example; }
|
||||||
// optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
|
// optionalAttrs (opt ? default) { default = renderOptionValue (opt.defaultText or opt.default); }
|
||||||
// optionalAttrs (opt ? defaultText) { default = opt.defaultText; }
|
|
||||||
// optionalAttrs (opt ? relatedPackages && opt.relatedPackages != null) { inherit (opt) relatedPackages; };
|
// optionalAttrs (opt ? relatedPackages && opt.relatedPackages != null) { inherit (opt) relatedPackages; };
|
||||||
|
|
||||||
subOptions =
|
subOptions =
|
||||||
@ -256,6 +255,9 @@ rec {
|
|||||||
efficient: the XML representation of derivations is very large
|
efficient: the XML representation of derivations is very large
|
||||||
(on the order of megabytes) and is not actually used by the
|
(on the order of megabytes) and is not actually used by the
|
||||||
manual generator.
|
manual generator.
|
||||||
|
|
||||||
|
This function was made obsolete by renderOptionValue and is kept for
|
||||||
|
compatibility with out-of-tree code.
|
||||||
*/
|
*/
|
||||||
scrubOptionValue = x:
|
scrubOptionValue = x:
|
||||||
if isDerivation x then
|
if isDerivation x then
|
||||||
@ -265,6 +267,17 @@ rec {
|
|||||||
else x;
|
else x;
|
||||||
|
|
||||||
|
|
||||||
|
/* Ensures that the given option value (default or example) is a `_type`d string
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
/* For use in the `defaultText` and `example` option attributes. Causes the
|
/* For use in the `defaultText` and `example` option attributes. Causes the
|
||||||
given string to be rendered verbatim in the documentation as Nix code. This
|
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
|
is necessary for complex values, e.g. functions, or values that depend on
|
||||||
|
@ -741,7 +741,7 @@ runTests {
|
|||||||
};
|
};
|
||||||
expected = rec {
|
expected = rec {
|
||||||
int = "42";
|
int = "42";
|
||||||
float = "~0.133700";
|
float = "0.1337";
|
||||||
bool = "true";
|
bool = "true";
|
||||||
emptystring = ''""'';
|
emptystring = ''""'';
|
||||||
string = ''"fn\''${o}\"r\\d"'';
|
string = ''"fn\''${o}\"r\\d"'';
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
# If you include more than one option list into a document, you need to
|
# If you include more than one option list into a document, you need to
|
||||||
# provide different ids.
|
# provide different ids.
|
||||||
, variablelistId ? "configuration-variable-list"
|
, variablelistId ? "configuration-variable-list"
|
||||||
# Strig to prefix to the option XML/HTML id attributes.
|
# String to prefix to the option XML/HTML id attributes.
|
||||||
, optionIdPrefix ? "opt-"
|
, optionIdPrefix ? "opt-"
|
||||||
, revision ? "" # Specify revision for the options
|
, revision ? "" # Specify revision for the options
|
||||||
# a set of options the docs we are generating will be merged into, as if by recursiveUpdate.
|
# a set of options the docs we are generating will be merged into, as if by recursiveUpdate.
|
||||||
@ -45,28 +45,11 @@
|
|||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
# Make a value safe for JSON. Functions are replaced by the string "<function>",
|
|
||||||
# derivations are replaced with an attrset
|
|
||||||
# { _type = "derivation"; name = <name of that derivation>; }.
|
|
||||||
# We need to handle derivations specially because consumers want to know about them,
|
|
||||||
# but we can't easily use the type,name subset of keys (since type is often used as
|
|
||||||
# a module option and might cause confusion). Use _type,name instead to the same
|
|
||||||
# effect, since _type is already used by the module system.
|
|
||||||
substSpecial = x:
|
|
||||||
if lib.isDerivation x then { _type = "derivation"; name = x.name; }
|
|
||||||
else if builtins.isAttrs x then lib.mapAttrs (name: substSpecial) x
|
|
||||||
else if builtins.isList x then map substSpecial x
|
|
||||||
else if lib.isFunction x then "<function>"
|
|
||||||
else x;
|
|
||||||
|
|
||||||
rawOpts = lib.optionAttrSetToDocList options;
|
rawOpts = lib.optionAttrSetToDocList options;
|
||||||
transformedOpts = map transformOptions rawOpts;
|
transformedOpts = map transformOptions rawOpts;
|
||||||
filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
|
filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
|
||||||
optionsList = lib.flip map filteredOpts
|
optionsList = lib.flip map filteredOpts
|
||||||
(opt: opt
|
(opt: opt
|
||||||
// lib.optionalAttrs (opt ? example) { example = substSpecial opt.example; }
|
|
||||||
// lib.optionalAttrs (opt ? default) { default = substSpecial opt.default; }
|
|
||||||
// lib.optionalAttrs (opt ? type) { type = substSpecial opt.type; }
|
|
||||||
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages opt.name; }
|
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages opt.name; }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -48,10 +48,15 @@ let
|
|||||||
};
|
};
|
||||||
scrubDerivations = namePrefix: pkgSet: mapAttrs
|
scrubDerivations = namePrefix: pkgSet: mapAttrs
|
||||||
(name: value:
|
(name: value:
|
||||||
let wholeName = "${namePrefix}.${name}"; in
|
let
|
||||||
if isAttrs value then
|
wholeName = "${namePrefix}.${name}";
|
||||||
|
guard = lib.warn "Attempt to evaluate package ${wholeName} in option documentation; this is not supported and will eventually be an error. Use `mkPackageOption` or `literalExpression` instead.";
|
||||||
|
in if isAttrs value then
|
||||||
scrubDerivations wholeName value
|
scrubDerivations wholeName value
|
||||||
// (optionalAttrs (isDerivation value) { outPath = "\${${wholeName}}"; })
|
// optionalAttrs (isDerivation value) {
|
||||||
|
outPath = guard "\${${wholeName}}";
|
||||||
|
drvPath = guard drvPath;
|
||||||
|
}
|
||||||
else value
|
else value
|
||||||
)
|
)
|
||||||
pkgSet;
|
pkgSet;
|
||||||
|
Loading…
Reference in New Issue
Block a user