mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-21 00:25:42 +02:00
docs: Use a nixpkgs patch instead of copy/pasting nixpkgs functions (#1011)
This makes the code more maintainable, as it only depends on our small patch, instead of a large number of internals of nixpkgs.
This commit is contained in:
parent
2294a12b0b
commit
507ff5b142
7 changed files with 97 additions and 251 deletions
256
docs/default.nix
256
docs/default.nix
|
@ -1,8 +1,21 @@
|
|||
{
|
||||
lib,
|
||||
modules,
|
||||
rawModules,
|
||||
pkgs,
|
||||
}: let
|
||||
pkgsDoc =
|
||||
import (pkgs.applyPatches {
|
||||
name = "nixpkgs-nixvim-doc";
|
||||
src = pkgs.path;
|
||||
patches = [
|
||||
./either_recursive.patch
|
||||
];
|
||||
}) {
|
||||
inherit (pkgs) system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
|
||||
inherit (pkgsDoc) lib;
|
||||
|
||||
nixvimPath = toString ./..;
|
||||
|
||||
gitHubDeclaration = user: repo: subpath: {
|
||||
|
@ -16,10 +29,10 @@
|
|||
declarations =
|
||||
map (
|
||||
decl:
|
||||
if pkgs.lib.hasPrefix nixvimPath (toString decl)
|
||||
if lib.hasPrefix nixvimPath (toString decl)
|
||||
then
|
||||
gitHubDeclaration "nix-community" "nixvim"
|
||||
(pkgs.lib.removePrefix "/" (pkgs.lib.removePrefix nixvimPath (toString decl)))
|
||||
(lib.removePrefix "/" (lib.removePrefix nixvimPath (toString decl)))
|
||||
else if decl == "lib/modules.nix"
|
||||
then gitHubDeclaration "NixOS" "nixpkgs" decl
|
||||
else decl
|
||||
|
@ -27,222 +40,6 @@
|
|||
opt.declarations;
|
||||
};
|
||||
|
||||
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;
|
||||
in
|
||||
(base.extendModules
|
||||
{prefix = loc;})
|
||||
.options
|
||||
// lib.optionalAttrs (freeformType != null) {
|
||||
_freeformOptions = getSubOptions' freeformType loc;
|
||||
};
|
||||
}
|
||||
# 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"
|
||||
"nixvim-configuration"
|
||||
] (_: {});
|
||||
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";
|
||||
in
|
||||
# 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}"
|
||||
}
|
||||
'';
|
||||
in
|
||||
lib.concatMapStrings (p: describe (unpack p)) packages;
|
||||
|
||||
nixvimOptionsList =
|
||||
lib.flip map filteredOpts
|
||||
(
|
||||
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
|
||||
'';
|
||||
|
||||
nixvmConfigType = lib.mkOptionType {
|
||||
name = "nixvim-configuration";
|
||||
description = "nixvim configuration options";
|
||||
|
@ -270,17 +67,24 @@
|
|||
};
|
||||
})
|
||||
]
|
||||
++ modules;
|
||||
++ (rawModules pkgsDoc);
|
||||
in
|
||||
rec {
|
||||
options-json = mkOptionsJSON (lib.evalModules {modules = topLevelModules;}).options;
|
||||
man-docs = pkgs.callPackage ./man {inherit options-json;};
|
||||
options-json =
|
||||
(pkgsDoc.nixosOptionsDoc
|
||||
{
|
||||
inherit (lib.evalModules {modules = topLevelModules;}) options;
|
||||
inherit transformOptions;
|
||||
warningsAreErrors = false;
|
||||
})
|
||||
.optionsJSON;
|
||||
man-docs = pkgsDoc.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 getSubOptions';
|
||||
// lib.optionalAttrs (!pkgsDoc.stdenv.isDarwin) {
|
||||
docs = pkgsDoc.callPackage ./mdbook {
|
||||
inherit transformOptions;
|
||||
modules = topLevelModules;
|
||||
};
|
||||
}
|
||||
|
|
49
docs/either_recursive.patch
Normal file
49
docs/either_recursive.patch
Normal file
|
@ -0,0 +1,49 @@
|
|||
commit e067eb1f6da7994150f10854e5fd635ca8bd0e92
|
||||
Author: traxys <quentin+dev@familleboyer.net>
|
||||
Date: Sun Jan 14 17:54:55 2024 +0100
|
||||
|
||||
lib.types: Include the suboptions of both types for either
|
||||
|
||||
This allows to correctly gather the sub options for types of the form
|
||||
`either <type> (submodule {...})`.
|
||||
|
||||
This requires adding two new types: `eitherRecursive` and
|
||||
`oneOfRecursive` that avoid infinite recursions for types like
|
||||
configuration types that are often of the form `oneOf [atom (listOf
|
||||
configType)]`
|
||||
|
||||
diff --git a/lib/types.nix b/lib/types.nix
|
||||
index cea63c598321..d26982db6cc0 100644
|
||||
--- a/lib/types.nix
|
||||
+++ b/lib/types.nix
|
||||
@@ -906,10 +906,16 @@ rec {
|
||||
then functor.type mt1 mt2
|
||||
else null;
|
||||
functor = (defaultFunctor name) // { wrapped = [ t1 t2 ]; };
|
||||
+ getSubOptions = prefix: (t1.getSubOptions prefix) // (t2.getSubOptions prefix);
|
||||
nestedTypes.left = t1;
|
||||
nestedTypes.right = t2;
|
||||
};
|
||||
|
||||
+ # Handle recursive leaf types, avoiding an infinite recursion
|
||||
+ eitherRecursive = t1: t2: (either t1 t2) // {
|
||||
+ getSubOptions = _: {};
|
||||
+ };
|
||||
+
|
||||
# Any of the types in the given list
|
||||
oneOf = ts:
|
||||
let
|
||||
@@ -917,6 +923,13 @@ rec {
|
||||
tail' = tail ts;
|
||||
in foldl' either head' tail';
|
||||
|
||||
+ # Handle recursive leaf types, avoiding an infinite recursion
|
||||
+ oneOfRecursive = ts:
|
||||
+ let
|
||||
+ head' = if ts == [] then throw "types.oneOfRecursive needs to get at least one type in its argument" else head ts;
|
||||
+ tail' = tail ts;
|
||||
+ in foldl' eitherRecursive head' tail';
|
||||
+
|
||||
# Either value of type `coercedType` or `finalType`, the former is
|
||||
# converted to `finalType` using `coerceFunc`.
|
||||
coercedTo = coercedType: coerceFunc: finalType:
|
|
@ -2,10 +2,8 @@
|
|||
pkgs,
|
||||
lib,
|
||||
modules,
|
||||
mkOptionsJSON,
|
||||
runCommand,
|
||||
nixos-render-docs,
|
||||
getSubOptions',
|
||||
nixosOptionsDoc,
|
||||
transformOptions,
|
||||
}:
|
||||
with lib; let
|
||||
options = lib.evalModules {
|
||||
|
@ -13,18 +11,12 @@ with lib; let
|
|||
specialArgs = {inherit pkgs lib;};
|
||||
};
|
||||
|
||||
mkMDDoc = options: let
|
||||
optionsJson = mkOptionsJSON options;
|
||||
in
|
||||
runCommand "options.md" {
|
||||
nativeBuildInputs = [nixos-render-docs];
|
||||
} ''
|
||||
nixos-render-docs -j $NIX_BUILD_CORES options commonmark \
|
||||
--manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \
|
||||
--revision "" \
|
||||
${optionsJson}/share/doc/nixos/options.json \
|
||||
$out
|
||||
'';
|
||||
mkMDDoc = options:
|
||||
(nixosOptionsDoc {
|
||||
inherit options transformOptions;
|
||||
warningsAreErrors = false;
|
||||
})
|
||||
.optionsCommonMark;
|
||||
|
||||
removeUnwanted = attrs:
|
||||
builtins.removeAttrs attrs [
|
||||
|
@ -37,7 +29,7 @@ with lib; let
|
|||
|
||||
removeWhitespace = builtins.replaceStrings [" "] [""];
|
||||
|
||||
getSubOptions = opts: path: removeUnwanted (getSubOptions' opts.type path);
|
||||
getSubOptions = opts: path: removeUnwanted (opts.type.getSubOptions path);
|
||||
|
||||
isVisible = opts:
|
||||
if isOption opts
|
||||
|
|
|
@ -31,13 +31,12 @@
|
|||
|
||||
perSystem = {
|
||||
pkgs,
|
||||
pkgsUnfree,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
_module.args = {
|
||||
modules = modules pkgs;
|
||||
modulesUnfree = modules pkgsUnfree;
|
||||
rawModules = modules;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
perSystem = {
|
||||
pkgs,
|
||||
config,
|
||||
modulesUnfree,
|
||||
pkgsUnfree,
|
||||
rawModules,
|
||||
...
|
||||
}: {
|
||||
packages = import ../docs {
|
||||
modules = modulesUnfree;
|
||||
pkgs = pkgsUnfree;
|
||||
inherit (pkgs) lib;
|
||||
inherit rawModules pkgs;
|
||||
};
|
||||
|
||||
# Test that all packages build fine when running `nix flake check`.
|
||||
|
|
|
@ -72,6 +72,9 @@ in
|
|||
|
||||
strLua = strLikeType "lua code string";
|
||||
strLuaFn = strLikeType "lua function string";
|
||||
|
||||
# Overridden when building the documentation
|
||||
eitherRecursive = either;
|
||||
}
|
||||
# Allow to do `with nixvimTypes;` instead of `with types;`
|
||||
// lib.types
|
||||
|
|
|
@ -60,7 +60,9 @@ in {
|
|||
])
|
||||
"Post-install hook";
|
||||
|
||||
requires = helpers.mkNullOrOption (either str listOfPlugins) "Plugin dependencies";
|
||||
requires =
|
||||
helpers.mkNullOrOption (helpers.nixvimTypes.eitherRecursive str listOfPlugins)
|
||||
"Plugin dependencies";
|
||||
|
||||
rocks =
|
||||
helpers.mkNullOrOption (either str (listOf (either str attrs)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue