mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-21 16:39:00 +02:00
254 lines
6.8 KiB
Nix
254 lines
6.8 KiB
Nix
|
{
|
||
|
pkgs,
|
||
|
lib,
|
||
|
modules,
|
||
|
mkOptionsJSON,
|
||
|
runCommand,
|
||
|
nixos-render-docs,
|
||
|
getSubOptions',
|
||
|
}:
|
||
|
with lib; let
|
||
|
options = lib.evalModules {
|
||
|
inherit modules;
|
||
|
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
|
||
|
'';
|
||
|
|
||
|
removeUnwanted = attrs:
|
||
|
builtins.removeAttrs attrs [
|
||
|
"_module"
|
||
|
"_freeformOptions"
|
||
|
"warnings"
|
||
|
"assertions"
|
||
|
"content"
|
||
|
];
|
||
|
|
||
|
removeWhitespace = builtins.replaceStrings [" "] [""];
|
||
|
|
||
|
getSubOptions = opts: path: removeUnwanted (getSubOptions' opts.type path);
|
||
|
|
||
|
isVisible = opts:
|
||
|
if isOption opts
|
||
|
then attrByPath ["visible"] true opts
|
||
|
else if opts.isOption
|
||
|
then attrByPath ["index" "options" "visible"] true opts
|
||
|
else let
|
||
|
filterFunc =
|
||
|
filterAttrs
|
||
|
(
|
||
|
_: v:
|
||
|
if isAttrs v
|
||
|
then isVisible v
|
||
|
else true
|
||
|
);
|
||
|
|
||
|
hasEmptyIndex = (filterFunc opts.index.options) == {};
|
||
|
hasEmptyComponents = (filterFunc opts.components) == {};
|
||
|
in
|
||
|
!hasEmptyIndex || !hasEmptyComponents;
|
||
|
|
||
|
wrapModule = path: opts: isOpt: rec {
|
||
|
index = {
|
||
|
options =
|
||
|
if isOpt
|
||
|
then opts
|
||
|
else filterAttrs (_: component: component.isOption && (isVisible component)) opts;
|
||
|
path = removeWhitespace (concatStringsSep "/" path);
|
||
|
};
|
||
|
|
||
|
components =
|
||
|
if isOpt
|
||
|
then {}
|
||
|
else filterAttrs (_: component: !component.isOption && (isVisible component)) opts;
|
||
|
|
||
|
hasComponents = components != {};
|
||
|
|
||
|
isOption = isOpt;
|
||
|
};
|
||
|
|
||
|
processModulesRec = modules: let
|
||
|
recurse = path: mods: let
|
||
|
g = name: opts:
|
||
|
if !isOption opts
|
||
|
then wrapModule (path ++ [name]) (recurse (path ++ [name]) opts) false
|
||
|
else let
|
||
|
subOpts = getSubOptions opts (path ++ [name]);
|
||
|
in
|
||
|
if subOpts != {}
|
||
|
then
|
||
|
wrapModule
|
||
|
(path ++ [name])
|
||
|
(
|
||
|
(recurse (path ++ [name]) subOpts)
|
||
|
// {
|
||
|
# This is necessary to include the submodule option's definition in the docs (description, type, etc.)
|
||
|
# For instance, this helps submodules like "autoCmd" to include their base definitions and examples in the docs
|
||
|
# Though there might be a better, less "hacky" solution than this.
|
||
|
${name} = recursiveUpdate opts {
|
||
|
isOption = true;
|
||
|
type.getSubOptions = _: _: {}; # Used to exclude suboptions from the submodule definition itself
|
||
|
};
|
||
|
}
|
||
|
)
|
||
|
false
|
||
|
else wrapModule (path ++ [name]) opts true;
|
||
|
in
|
||
|
mapAttrs g mods;
|
||
|
in
|
||
|
foldlAttrs
|
||
|
(
|
||
|
acc: name: opts: let
|
||
|
group =
|
||
|
if !opts.hasComponents
|
||
|
then "Neovim Options"
|
||
|
else "none";
|
||
|
|
||
|
last =
|
||
|
acc.${group}
|
||
|
or {
|
||
|
index = {
|
||
|
options = {};
|
||
|
path = removeWhitespace "${group}";
|
||
|
};
|
||
|
components = {};
|
||
|
isGroup = true;
|
||
|
hasComponents = false;
|
||
|
};
|
||
|
|
||
|
isOpt = !opts.hasComponents && (isOption opts.index.options);
|
||
|
in
|
||
|
acc
|
||
|
// {
|
||
|
${group} = recursiveUpdate last {
|
||
|
index.options = optionalAttrs isOpt {
|
||
|
${name} = opts.index.options;
|
||
|
};
|
||
|
|
||
|
components = optionalAttrs (!isOpt) {
|
||
|
${name} = recursiveUpdate opts {
|
||
|
index.path =
|
||
|
removeWhitespace
|
||
|
(
|
||
|
concatStringsSep "/"
|
||
|
(
|
||
|
(optional (group != "none") group) ++ [opts.index.path]
|
||
|
)
|
||
|
);
|
||
|
hasComponents = true;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
hasComponents = last.components != {};
|
||
|
};
|
||
|
}
|
||
|
)
|
||
|
{}
|
||
|
(recurse [] modules);
|
||
|
|
||
|
mapModulesToString = f: modules: let
|
||
|
recurse = mods: let
|
||
|
g = name: opts:
|
||
|
if (opts ? "isGroup")
|
||
|
then
|
||
|
if name != "none"
|
||
|
then (f name opts) + ("\n" + recurse opts.components)
|
||
|
else recurse opts.components
|
||
|
else if opts.hasComponents
|
||
|
then (f name opts) + ("\n" + recurse opts.components)
|
||
|
else f name opts;
|
||
|
in
|
||
|
concatStringsSep "\n" (mapAttrsToList g mods);
|
||
|
in
|
||
|
recurse modules;
|
||
|
|
||
|
docs = rec {
|
||
|
modules = processModulesRec (removeUnwanted options.options);
|
||
|
commands =
|
||
|
mapModulesToString
|
||
|
(
|
||
|
name: opts: let
|
||
|
isBranch =
|
||
|
if (hasSuffix "index" opts.index.path)
|
||
|
then true
|
||
|
else opts.hasComponents;
|
||
|
path =
|
||
|
if isBranch
|
||
|
then "${opts.index.path}/index.md"
|
||
|
else "${opts.index.path}.md";
|
||
|
in
|
||
|
(optionalString isBranch
|
||
|
"mkdir -p ${opts.index.path}\n")
|
||
|
+ "cp ${mkMDDoc opts.index.options} ${path}"
|
||
|
)
|
||
|
modules;
|
||
|
};
|
||
|
|
||
|
mdbook = {
|
||
|
nixvimOptions =
|
||
|
mapModulesToString
|
||
|
(
|
||
|
name: opts: let
|
||
|
isBranch =
|
||
|
if name == "index"
|
||
|
then true
|
||
|
else opts.hasComponents && opts.index.options != {};
|
||
|
|
||
|
path =
|
||
|
if isBranch
|
||
|
then "${opts.index.path}/index.md"
|
||
|
else if !opts.hasComponents
|
||
|
then "${opts.index.path}.md"
|
||
|
else "";
|
||
|
|
||
|
indentLevel = with builtins; length (filter isString (split "/" opts.index.path)) - 1;
|
||
|
|
||
|
padding = concatStrings (builtins.genList (_: "\t") indentLevel);
|
||
|
in "${padding}- [${name}](${path})"
|
||
|
)
|
||
|
docs.modules;
|
||
|
};
|
||
|
|
||
|
prepareMD = ''
|
||
|
# Copy inputs into the build directory
|
||
|
cp -r --no-preserve=all $inputs/* ./
|
||
|
cp ${../../CONTRIBUTING.md} ./CONTRIBUTING.md
|
||
|
|
||
|
# Copy the generated MD docs into the build directory
|
||
|
# Using pkgs.writeShellScript helps to avoid the "bash: argument list too long" error
|
||
|
bash -e ${pkgs.writeShellScript "copy_docs" docs.commands}
|
||
|
|
||
|
# Prepare SUMMARY.md for mdBook
|
||
|
# Using pkgs.writeText helps to avoid the same error as above
|
||
|
substituteInPlace ./SUMMARY.md \
|
||
|
--replace "@NIXVIM_OPTIONS@" "$(cat ${pkgs.writeText "nixvim-options-summary.md" mdbook.nixvimOptions})"
|
||
|
'';
|
||
|
in
|
||
|
pkgs.stdenv.mkDerivation {
|
||
|
name = "nixvim-docs";
|
||
|
|
||
|
phases = ["buildPhase"];
|
||
|
|
||
|
buildInputs = [pkgs.mdbook];
|
||
|
inputs = sourceFilesBySuffices ./. [".md" ".toml" ".js"];
|
||
|
|
||
|
buildPhase = ''
|
||
|
dest=$out/share/doc
|
||
|
mkdir -p $dest
|
||
|
${prepareMD}
|
||
|
mdbook build
|
||
|
cp -r ./book/* $dest
|
||
|
'';
|
||
|
}
|