Skip to content

Commit

Permalink
docs: Correctly generate documentation for types `either a (submodule…
Browse files Browse the repository at this point in the history
… ...)` (#929)

This requires pulling quite a lot of code from nixpkgs in order to
make the `either` type work correctly, the effects can be seen for
example in the documentation of `ollama.promps` and `ollama.actions`
  • Loading branch information
traxys authored Jan 12, 2024
1 parent 61da581 commit 29225c2
Show file tree
Hide file tree
Showing 10 changed files with 515 additions and 314 deletions.
485 changes: 239 additions & 246 deletions docs/default.nix

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions docs/man/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
options-json,
runCommand,
installShellFiles,
nixos-render-docs,
}:
runCommand "nixvim-configuration-reference-manpage" {
nativeBuildInputs = [installShellFiles nixos-render-docs];
} ''
# Generate man-pages
mkdir -p $out/share/man/man5
nixos-render-docs -j $NIX_BUILD_CORES options manpage \
--revision unstable \
--header ${./nixvim-header.5} \
--footer ${./nixvim-footer.5} \
${options-json}/share/doc/nixos/options.json \
$out/share/man/man5/nixvim.5
compressManPages $out
''
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
253 changes: 253 additions & 0 deletions docs/mdbook/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
{
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
'';
}
File renamed without changes.
21 changes: 4 additions & 17 deletions flake-modules/packages.nix
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
{
perSystem = {
pkgs,
pkgsUnfree,
config,
modules,
...
}: {
packages = let
# Do not check if documentation builds fine on darwin as it fails:
# > sandbox-exec: pattern serialization length 69298 exceeds maximum (65535)
docs = pkgs.lib.optionalAttrs (!pkgs.stdenv.isDarwin) {
docs = pkgsUnfree.callPackage (import ../docs) {
inherit modules;
};
};

man-docs = import ../man-docs {
pkgs = pkgsUnfree;
inherit modules;
};
in
docs
// man-docs;
packages = import ../docs {
inherit modules pkgs;
inherit (pkgs) lib;
};

# Test that all packages build fine when running `nix flake check`.
checks = config.packages;
Expand Down
51 changes: 0 additions & 51 deletions man-docs/default.nix

This file was deleted.

0 comments on commit 29225c2

Please sign in to comment.