2023-08-07 13:18:01 +03:30
|
|
|
|
{
|
|
|
|
|
lib,
|
|
|
|
|
modules,
|
2024-01-12 23:22:03 +01:00
|
|
|
|
pkgs,
|
|
|
|
|
}: let
|
|
|
|
|
nixvimPath = toString ./..;
|
2023-08-24 14:50:16 +03:30
|
|
|
|
|
2024-01-12 23:22:03 +01:00
|
|
|
|
gitHubDeclaration = user: repo: subpath: {
|
|
|
|
|
url = "https://github.com/${user}/${repo}/blob/master/${subpath}";
|
|
|
|
|
name = "<${repo}/${subpath}>";
|
|
|
|
|
};
|
2023-08-24 14:50:16 +03:30
|
|
|
|
|
2024-01-12 23:22:03 +01:00
|
|
|
|
transformOptions = opt:
|
|
|
|
|
opt
|
|
|
|
|
// {
|
|
|
|
|
declarations =
|
|
|
|
|
map (
|
|
|
|
|
decl:
|
|
|
|
|
if pkgs.lib.hasPrefix nixvimPath (toString decl)
|
|
|
|
|
then
|
|
|
|
|
gitHubDeclaration "nix-community" "nixvim"
|
|
|
|
|
(pkgs.lib.removePrefix "/" (pkgs.lib.removePrefix nixvimPath (toString decl)))
|
|
|
|
|
else if decl == "lib/modules.nix"
|
|
|
|
|
then gitHubDeclaration "NixOS" "nixpkgs" decl
|
|
|
|
|
else decl
|
|
|
|
|
)
|
|
|
|
|
opt.declarations;
|
2023-08-07 13:18:01 +03:30
|
|
|
|
};
|
|
|
|
|
|
2024-01-12 23:22:03 +01:00
|
|
|
|
getSubOptions' = type: loc: let
|
|
|
|
|
types =
|
|
|
|
|
# Composite types
|
|
|
|
|
{
|
|
|
|
|
either =
|
|
|
|
|
(getSubOptions' type.nestedTypes.left loc)
|
|
|
|
|
// (getSubOptions' type.nestedTypes.right loc);
|
|
|
|
|
nullOr = getSubOptions' type.nestedTypes.elemType loc;
|
|
|
|
|
lazyAttrsOf = getSubOptions' type.nestedTypes.elemType (loc ++ ["<name>"]);
|
|
|
|
|
attrsOf = getSubOptions' type.nestedTypes.elemType (loc ++ ["<name>"]);
|
|
|
|
|
listOf = getSubOptions' type.nestedTypes.elemType (loc ++ ["*"]);
|
|
|
|
|
functionTo = getSubOptions' type.nestedTypes.elemType (loc ++ ["<function body>"]);
|
|
|
|
|
|
|
|
|
|
# Taken from lib/types.nix
|
|
|
|
|
submodule = let
|
|
|
|
|
base = lib.evalModules {
|
|
|
|
|
modules =
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
_module.args.name = lib.mkOptionDefault "‹name›";
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
++ type.getSubModules;
|
|
|
|
|
};
|
|
|
|
|
inherit (base._module) freeformType;
|
2023-08-07 13:18:01 +03:30
|
|
|
|
in
|
2024-01-12 23:22:03 +01:00
|
|
|
|
(base.extendModules
|
|
|
|
|
{prefix = loc;})
|
|
|
|
|
.options
|
|
|
|
|
// lib.optionalAttrs (freeformType != null) {
|
|
|
|
|
_freeformOptions = getSubOptions' freeformType loc;
|
2023-08-07 13:18:01 +03:30
|
|
|
|
};
|
2024-01-12 23:22:03 +01:00
|
|
|
|
}
|
|
|
|
|
# Leaf types
|
|
|
|
|
// lib.genAttrs [
|
|
|
|
|
"raw"
|
|
|
|
|
"bool"
|
|
|
|
|
"optionType"
|
|
|
|
|
"unspecified"
|
|
|
|
|
"str"
|
|
|
|
|
"attrs"
|
|
|
|
|
"rawLua"
|
|
|
|
|
"int"
|
|
|
|
|
"package"
|
|
|
|
|
"numberBetween"
|
|
|
|
|
"enum"
|
|
|
|
|
"anything"
|
|
|
|
|
"separatedString"
|
|
|
|
|
"path"
|
|
|
|
|
"maintainer"
|
|
|
|
|
"unsignedInt"
|
|
|
|
|
"float"
|
|
|
|
|
"positiveInt"
|
|
|
|
|
"intBetween"
|
|
|
|
|
"nullType"
|
|
|
|
|
"nonEmptyStr"
|
|
|
|
|
] (_: {});
|
|
|
|
|
in
|
|
|
|
|
# For recursive types avoid calculating sub options, else this
|
|
|
|
|
# will end up in an unbounded recursion
|
|
|
|
|
if loc == ["plugins" "packer" "plugins" "*" "requires"]
|
|
|
|
|
then {}
|
|
|
|
|
else if builtins.hasAttr type.name types
|
|
|
|
|
then types.${type.name}
|
|
|
|
|
else throw "unhandled type in documentation: ${type.name}";
|
|
|
|
|
|
|
|
|
|
mkOptionsJSON = options: let
|
|
|
|
|
# Mainly present to patch the type.getSubOptions of `either`, but we need to patch all
|
|
|
|
|
# the options in order to correctly handle other composite options
|
|
|
|
|
# The code that follows is taken almost exactly from nixpkgs,
|
|
|
|
|
# by changing type.getSubOptions to getSubOptions'
|
|
|
|
|
# lib/options.nix
|
|
|
|
|
optionAttrSetToDocList' = _: options:
|
|
|
|
|
lib.concatMap (opt: let
|
|
|
|
|
name = lib.showOption opt.loc;
|
|
|
|
|
docOption =
|
|
|
|
|
{
|
|
|
|
|
inherit (opt) loc;
|
|
|
|
|
inherit name;
|
|
|
|
|
description = opt.description or null;
|
|
|
|
|
declarations = builtins.filter (x: x != lib.unknownModule) opt.declarations;
|
|
|
|
|
internal = opt.internal or false;
|
|
|
|
|
visible =
|
|
|
|
|
if (opt ? visible && opt.visible == "shallow")
|
|
|
|
|
then true
|
|
|
|
|
else opt.visible or true;
|
|
|
|
|
readOnly = opt.readOnly or false;
|
|
|
|
|
type = opt.type.description or "unspecified";
|
|
|
|
|
}
|
|
|
|
|
// lib.optionalAttrs (opt ? example) {
|
|
|
|
|
example = builtins.addErrorContext "while evaluating the example of option `${name}`" (
|
|
|
|
|
lib.options.renderOptionValue opt.example
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// lib.optionalAttrs (opt ? defaultText || opt ? default) {
|
|
|
|
|
default =
|
|
|
|
|
builtins.addErrorContext "while evaluating the ${
|
|
|
|
|
if opt ? defaultText
|
|
|
|
|
then "defaultText"
|
|
|
|
|
else "default value"
|
|
|
|
|
} of option `${name}`" (
|
|
|
|
|
lib.options.renderOptionValue (opt.defaultText or opt.default)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != null) {inherit (opt) relatedPackages;};
|
|
|
|
|
|
|
|
|
|
subOptions = let
|
|
|
|
|
ss = getSubOptions' opt.type opt.loc;
|
|
|
|
|
in
|
|
|
|
|
if ss != {}
|
|
|
|
|
then optionAttrSetToDocList' opt.loc ss
|
|
|
|
|
else [];
|
|
|
|
|
subOptionsVisible = docOption.visible && opt.visible or null != "shallow";
|
2023-08-07 13:18:01 +03:30
|
|
|
|
in
|
2024-01-12 23:22:03 +01:00
|
|
|
|
# To find infinite recursion in NixOS option docs:
|
|
|
|
|
# builtins.trace opt.loc
|
|
|
|
|
[docOption] ++ lib.optionals subOptionsVisible subOptions) (lib.collect lib.isOption options);
|
|
|
|
|
|
|
|
|
|
# Generate documentation template from the list of option declaration like
|
|
|
|
|
# the set generated with filterOptionSets.
|
|
|
|
|
optionAttrSetToDocList = optionAttrSetToDocList' [];
|
|
|
|
|
|
|
|
|
|
# nixos/lib/make-options-doc/default.nix
|
|
|
|
|
|
|
|
|
|
rawOpts = optionAttrSetToDocList options;
|
|
|
|
|
transformedOpts = map transformOptions rawOpts;
|
|
|
|
|
filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
|
|
|
|
|
|
|
|
|
|
# Generate DocBook documentation for a list of packages. This is
|
|
|
|
|
# what `relatedPackages` option of `mkOption` from
|
|
|
|
|
# ../../../lib/options.nix influences.
|
|
|
|
|
#
|
|
|
|
|
# Each element of `relatedPackages` can be either
|
|
|
|
|
# - a string: that will be interpreted as an attribute name from `pkgs` and turned into a link
|
|
|
|
|
# to search.nixos.org,
|
|
|
|
|
# - a list: that will be interpreted as an attribute path from `pkgs` and turned into a link
|
|
|
|
|
# to search.nixos.org,
|
|
|
|
|
# - an attrset: that can specify `name`, `path`, `comment`
|
|
|
|
|
# (either of `name`, `path` is required, the rest are optional).
|
|
|
|
|
#
|
|
|
|
|
# NOTE: No checks against `pkgs` are made to ensure that the referenced package actually exists.
|
|
|
|
|
# Such checks are not compatible with option docs caching.
|
|
|
|
|
genRelatedPackages = packages: optName: let
|
|
|
|
|
unpack = p:
|
|
|
|
|
if lib.isString p
|
|
|
|
|
then {name = p;}
|
|
|
|
|
else if lib.isList p
|
|
|
|
|
then {path = p;}
|
|
|
|
|
else p;
|
|
|
|
|
describe = args: let
|
|
|
|
|
title = args.title or null;
|
|
|
|
|
name = args.name or (lib.concatStringsSep "." args.path);
|
|
|
|
|
in ''
|
|
|
|
|
- [${lib.optionalString (title != null) "${title} aka "}`pkgs.${name}`](
|
|
|
|
|
https://search.nixos.org/packages?show=${name}&sort=relevance&query=${name}
|
|
|
|
|
)${
|
|
|
|
|
lib.optionalString (args ? comment) "\n\n ${args.comment}"
|
2023-08-07 13:18:01 +03:30
|
|
|
|
}
|
2024-01-12 23:22:03 +01:00
|
|
|
|
'';
|
2023-08-07 13:18:01 +03:30
|
|
|
|
in
|
2024-01-12 23:22:03 +01:00
|
|
|
|
lib.concatMapStrings (p: describe (unpack p)) packages;
|
2023-08-07 13:18:01 +03:30
|
|
|
|
|
2024-01-12 23:22:03 +01:00
|
|
|
|
nixvimOptionsList =
|
|
|
|
|
lib.flip map filteredOpts
|
2023-08-07 13:18:01 +03:30
|
|
|
|
(
|
2024-01-12 23:22:03 +01:00
|
|
|
|
opt:
|
|
|
|
|
opt
|
|
|
|
|
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) {
|
|
|
|
|
relatedPackages = genRelatedPackages opt.relatedPackages opt.name;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
nixvimOptionsNix = builtins.listToAttrs (map (o: {
|
|
|
|
|
inherit (o) name;
|
|
|
|
|
value = removeAttrs o ["name" "visible" "internal"];
|
|
|
|
|
})
|
|
|
|
|
nixvimOptionsList);
|
|
|
|
|
in
|
|
|
|
|
pkgs.runCommand "options.json"
|
|
|
|
|
{
|
|
|
|
|
meta.description = "List of NixOS options in JSON format";
|
|
|
|
|
nativeBuildInputs = [
|
|
|
|
|
pkgs.brotli
|
|
|
|
|
pkgs.python3Minimal
|
|
|
|
|
];
|
|
|
|
|
options =
|
|
|
|
|
builtins.toFile "options.json"
|
|
|
|
|
(builtins.unsafeDiscardStringContext (builtins.toJSON nixvimOptionsNix));
|
|
|
|
|
baseJSON = builtins.toFile "base.json" "{}";
|
|
|
|
|
}
|
|
|
|
|
''
|
|
|
|
|
# Export list of options in different format.
|
|
|
|
|
dst=$out/share/doc/nixos
|
|
|
|
|
mkdir -p $dst
|
|
|
|
|
|
|
|
|
|
TOUCH_IF_DB=$dst/.used-docbook \
|
|
|
|
|
python ${pkgs.path}/nixos/lib/make-options-doc/mergeJSON.py \
|
|
|
|
|
$baseJSON $options \
|
|
|
|
|
> $dst/options.json
|
|
|
|
|
|
|
|
|
|
if grep /nixpkgs/nixos/modules $dst/options.json; then
|
|
|
|
|
echo "The manual appears to depend on the location of Nixpkgs, which is bad"
|
|
|
|
|
echo "since this prevents sharing via the NixOS channel. This is typically"
|
|
|
|
|
echo "caused by an option default that refers to a relative path (see above"
|
|
|
|
|
echo "for hints about the offending path)."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
brotli -9 < $dst/options.json > $dst/options.json.br
|
|
|
|
|
|
|
|
|
|
mkdir -p $out/nix-support
|
|
|
|
|
echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
|
|
|
|
|
echo "file json-br $dst/options.json.br" >> $out/nix-support/hydra-build-products
|
2023-08-07 13:18:01 +03:30
|
|
|
|
'';
|
2024-01-12 23:22:03 +01:00
|
|
|
|
in
|
|
|
|
|
rec {
|
|
|
|
|
options-json = mkOptionsJSON (lib.evalModules {inherit modules;}).options;
|
|
|
|
|
man-docs = pkgs.callPackage ./man {inherit options-json;};
|
|
|
|
|
}
|
|
|
|
|
# Do not check if documentation builds fine on darwin as it fails:
|
|
|
|
|
# > sandbox-exec: pattern serialization length 69298 exceeds maximum (65535)
|
|
|
|
|
// lib.optionalAttrs (!pkgs.stdenv.isDarwin) {
|
|
|
|
|
docs = pkgs.callPackage ./mdbook {
|
|
|
|
|
inherit mkOptionsJSON modules getSubOptions';
|
|
|
|
|
};
|
2023-08-07 13:18:01 +03:30
|
|
|
|
}
|