mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-21 08:35:43 +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,
|
rawModules,
|
||||||
modules,
|
|
||||||
pkgs,
|
pkgs,
|
||||||
}: let
|
}: 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 ./..;
|
nixvimPath = toString ./..;
|
||||||
|
|
||||||
gitHubDeclaration = user: repo: subpath: {
|
gitHubDeclaration = user: repo: subpath: {
|
||||||
|
@ -16,10 +29,10 @@
|
||||||
declarations =
|
declarations =
|
||||||
map (
|
map (
|
||||||
decl:
|
decl:
|
||||||
if pkgs.lib.hasPrefix nixvimPath (toString decl)
|
if lib.hasPrefix nixvimPath (toString decl)
|
||||||
then
|
then
|
||||||
gitHubDeclaration "nix-community" "nixvim"
|
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"
|
else if decl == "lib/modules.nix"
|
||||||
then gitHubDeclaration "NixOS" "nixpkgs" decl
|
then gitHubDeclaration "NixOS" "nixpkgs" decl
|
||||||
else decl
|
else decl
|
||||||
|
@ -27,222 +40,6 @@
|
||||||
opt.declarations;
|
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 {
|
nixvmConfigType = lib.mkOptionType {
|
||||||
name = "nixvim-configuration";
|
name = "nixvim-configuration";
|
||||||
description = "nixvim configuration options";
|
description = "nixvim configuration options";
|
||||||
|
@ -270,17 +67,24 @@
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
++ modules;
|
++ (rawModules pkgsDoc);
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
options-json = mkOptionsJSON (lib.evalModules {modules = topLevelModules;}).options;
|
options-json =
|
||||||
man-docs = pkgs.callPackage ./man {inherit 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:
|
# Do not check if documentation builds fine on darwin as it fails:
|
||||||
# > sandbox-exec: pattern serialization length 69298 exceeds maximum (65535)
|
# > sandbox-exec: pattern serialization length 69298 exceeds maximum (65535)
|
||||||
// lib.optionalAttrs (!pkgs.stdenv.isDarwin) {
|
// lib.optionalAttrs (!pkgsDoc.stdenv.isDarwin) {
|
||||||
docs = pkgs.callPackage ./mdbook {
|
docs = pkgsDoc.callPackage ./mdbook {
|
||||||
inherit mkOptionsJSON getSubOptions';
|
inherit transformOptions;
|
||||||
modules = topLevelModules;
|
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,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
modules,
|
modules,
|
||||||
mkOptionsJSON,
|
nixosOptionsDoc,
|
||||||
runCommand,
|
transformOptions,
|
||||||
nixos-render-docs,
|
|
||||||
getSubOptions',
|
|
||||||
}:
|
}:
|
||||||
with lib; let
|
with lib; let
|
||||||
options = lib.evalModules {
|
options = lib.evalModules {
|
||||||
|
@ -13,18 +11,12 @@ with lib; let
|
||||||
specialArgs = {inherit pkgs lib;};
|
specialArgs = {inherit pkgs lib;};
|
||||||
};
|
};
|
||||||
|
|
||||||
mkMDDoc = options: let
|
mkMDDoc = options:
|
||||||
optionsJson = mkOptionsJSON options;
|
(nixosOptionsDoc {
|
||||||
in
|
inherit options transformOptions;
|
||||||
runCommand "options.md" {
|
warningsAreErrors = false;
|
||||||
nativeBuildInputs = [nixos-render-docs];
|
})
|
||||||
} ''
|
.optionsCommonMark;
|
||||||
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
|
|
||||||
'';
|
|
||||||
|
|
||||||
removeUnwanted = attrs:
|
removeUnwanted = attrs:
|
||||||
builtins.removeAttrs attrs [
|
builtins.removeAttrs attrs [
|
||||||
|
@ -37,7 +29,7 @@ with lib; let
|
||||||
|
|
||||||
removeWhitespace = builtins.replaceStrings [" "] [""];
|
removeWhitespace = builtins.replaceStrings [" "] [""];
|
||||||
|
|
||||||
getSubOptions = opts: path: removeUnwanted (getSubOptions' opts.type path);
|
getSubOptions = opts: path: removeUnwanted (opts.type.getSubOptions path);
|
||||||
|
|
||||||
isVisible = opts:
|
isVisible = opts:
|
||||||
if isOption opts
|
if isOption opts
|
||||||
|
|
|
@ -31,13 +31,12 @@
|
||||||
|
|
||||||
perSystem = {
|
perSystem = {
|
||||||
pkgs,
|
pkgs,
|
||||||
pkgsUnfree,
|
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
_module.args = {
|
_module.args = {
|
||||||
modules = modules pkgs;
|
modules = modules pkgs;
|
||||||
modulesUnfree = modules pkgsUnfree;
|
rawModules = modules;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
perSystem = {
|
perSystem = {
|
||||||
pkgs,
|
pkgs,
|
||||||
config,
|
config,
|
||||||
modulesUnfree,
|
rawModules,
|
||||||
pkgsUnfree,
|
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
packages = import ../docs {
|
packages = import ../docs {
|
||||||
modules = modulesUnfree;
|
inherit rawModules pkgs;
|
||||||
pkgs = pkgsUnfree;
|
|
||||||
inherit (pkgs) lib;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Test that all packages build fine when running `nix flake check`.
|
# Test that all packages build fine when running `nix flake check`.
|
||||||
|
|
|
@ -72,6 +72,9 @@ in
|
||||||
|
|
||||||
strLua = strLikeType "lua code string";
|
strLua = strLikeType "lua code string";
|
||||||
strLuaFn = strLikeType "lua function string";
|
strLuaFn = strLikeType "lua function string";
|
||||||
|
|
||||||
|
# Overridden when building the documentation
|
||||||
|
eitherRecursive = either;
|
||||||
}
|
}
|
||||||
# Allow to do `with nixvimTypes;` instead of `with types;`
|
# Allow to do `with nixvimTypes;` instead of `with types;`
|
||||||
// lib.types
|
// lib.types
|
||||||
|
|
|
@ -60,7 +60,9 @@ in {
|
||||||
])
|
])
|
||||||
"Post-install hook";
|
"Post-install hook";
|
||||||
|
|
||||||
requires = helpers.mkNullOrOption (either str listOfPlugins) "Plugin dependencies";
|
requires =
|
||||||
|
helpers.mkNullOrOption (helpers.nixvimTypes.eitherRecursive str listOfPlugins)
|
||||||
|
"Plugin dependencies";
|
||||||
|
|
||||||
rocks =
|
rocks =
|
||||||
helpers.mkNullOrOption (either str (listOf (either str attrs)))
|
helpers.mkNullOrOption (either str (listOf (either str attrs)))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue