Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
284 changes: 129 additions & 155 deletions docs/lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,173 +6,147 @@
writers,
nixdoc,
nixvim,
pageSpecs ? import ./pages.nix,
pageSpecs ? ./pages.nix,
}:

let
# Some pages are just menu entries, others have an actual markdown page that
# needs rendering.
shouldRenderPage = page: page ? file || page ? markdown;

# Normalise a page node, recursively normalise its children
elaboratePage =
loc:
{
title ? "",
markdown ? null,
file ? null,
pages ? { },
}@page:
{
name = lib.attrsets.showAttrPath loc;
loc = lib.throwIfNot (
builtins.head loc == "lib"
) "All pages must be within `lib`, unexpected root `${builtins.head loc}`" (builtins.tail loc);
}
// lib.optionalAttrs (shouldRenderPage page) {
inherit
file
title
;
markdown =
if builtins.isString markdown then
builtins.toFile "${lib.strings.replaceStrings [ "/" "-" ] (lib.lists.last loc)}.md" markdown
else
markdown;
outFile = lib.strings.concatStringsSep "/" (loc ++ [ "index.md" ]);
}
// lib.optionalAttrs (page ? pages) {
pages = elaboratePages loc pages;
};

# Recursively normalise page nodes
elaboratePages = prefix: builtins.mapAttrs (name: elaboratePage (prefix ++ [ name ]));
pageConfiguration = lib.evalModules {
modules = [
pageSpecs
{
freeformType = lib.types.attrsOf (
lib.types.submoduleWith {
modules = [ ../modules/page.nix ];
}
);
}
];
};
pages = pageConfiguration.config;

# Collect all page nodes into a list of page entries
collectPages =
pages:
builtins.concatMap (
page:
[ (builtins.removeAttrs page [ "pages" ]) ]
++ lib.optionals (page ? pages) (collectPages page.pages)
node:
let
children = builtins.removeAttrs node [ "_page" ];
in
lib.optional (node ? _page) node._page ++ lib.optionals (children != { }) (collectPages children)
) (builtins.attrValues pages);

# Normalised page specs
elaboratedPageSpecs = elaboratePages [ ] pageSpecs;
pageList = collectPages elaboratedPageSpecs;
pagesToRender = builtins.filter (page: page ? outFile) pageList;
pagesWithFunctions = builtins.filter (page: page.file or null != null) pageList;
in

runCommand "nixvim-lib-docs"
{
nativeBuildInputs = [
nixdoc
];
pageList = collectPages pages;
pagesToRender = builtins.filter (page: page.hasContent) pageList;

locations = writers.writeJSON "locations.json" (
import ./function-locations.nix {
inherit lib;
rootPath = nixvim;
functionSet = lib.extend nixvim.lib.overlay;
pathsToScan = builtins.catAttrs "loc" pagesWithFunctions;
revision = nixvim.rev or "main";
result =
runCommand "nixvim-lib-docs"
{
nativeBuildInputs = [
nixdoc
];

locations = writers.writeJSON "locations.json" (
import ./function-locations.nix {
inherit lib;
rootPath = nixvim;
functionSet = lib.extend nixvim.lib.overlay;
pathsToScan = lib.pipe pageList [
(map (x: x.functions))
(builtins.filter (x: x.file != null))
(map (x: x.loc))
];
revision = nixvim.rev or "main";
}
);

passthru.config = pageConfiguration;

passthru.menu = import ./menu.nix {
inherit lib pages;
};

passthru.pages = map (page: "${result}/${page.target}") pagesToRender;
}
);

passthru.menu = import ./menu.nix {
inherit lib;
pageSpecs = elaboratedPageSpecs;
};

passthru.pages = builtins.listToAttrs (
builtins.map (
{ name, outFile, ... }:
{
inherit name;
value = outFile;
''
function docgen {
md_file="$1"
in_file="$2"
name="$3"
out_file="$out/$4"
title="$5"

if [[ -z "$in_file" ]]; then
if [[ -z "$md_file" ]]; then
>&2 echo "No markdown or nix file for $name"
exit 1
fi
elif [[ -f "$in_file/default.nix" ]]; then
in_file+="/default.nix"
elif [[ ! -f "$in_file" ]]; then
>&2 echo "File not found: $in_file"
exit 1
fi

if [[ -n "$in_file" ]]; then
nixdoc \
--file "$in_file" \
--locs "$locations" \
--category "$name" \
--description "REMOVED BY TAIL" \
--prefix "lib" \
--anchor-prefix "" \
| tail --lines +2 \
> functions.md
fi

default_heading="# $name"
if [[ -n "$title" ]]; then
default_heading+=": $title"
fi

print_heading=true
if [[ -f "$md_file" ]] && [[ "$(head --lines 1 "$md_file")" == '# '* ]]; then
>&2 echo "NOTE: markdown file for $name starts with a <h1> heading. Skipping default heading \"$default_heading\"."
>&2 echo " Found \"$(head --lines 1 "$md_file")\" in: $md_file"
print_heading=false
fi

mkdir -p $(dirname "$out_file")
(
if [[ "$print_heading" = true ]]; then
echo "$default_heading"
echo
fi
if [[ -f "$md_file" ]]; then
cat "$md_file"
echo
fi
if [[ -f functions.md ]]; then
cat functions.md
fi
) > "$out_file"
}
) pagesToRender
);
}
''
function docgen {
md_file="$1"
in_file="$2"
name="$3"
out_file="$out/$4"
title="$5"

if [[ -z "$in_file" ]]; then
if [[ -z "$md_file" ]]; then
>&2 echo "No markdown or nix file for $name"
exit 1
fi
elif [[ -f "$in_file/default.nix" ]]; then
in_file+="/default.nix"
elif [[ ! -f "$in_file" ]]; then
>&2 echo "File not found: $in_file"
exit 1
fi

if [[ -n "$in_file" ]]; then
nixdoc \
--file "$in_file" \
--locs "$locations" \
--category "$name" \
--description "REMOVED BY TAIL" \
--prefix "" \
--anchor-prefix "" \
| tail --lines +2 \
> functions.md
fi

default_heading="# $name"
if [[ -n "$title" ]]; then
default_heading+=": $title"
fi

print_heading=true
if [[ -f "$md_file" ]] && [[ "$(head --lines 1 "$md_file")" == '# '* ]]; then
>&2 echo "NOTE: markdown file for $name starts with a <h1> heading. Skipping default heading \"$default_heading\"."
>&2 echo " Found \"$(head --lines 1 "$md_file")\" in: $md_file"
print_heading=false
fi

mkdir -p $(dirname "$out_file")
(
if [[ "$print_heading" = true ]]; then
echo "$default_heading"
echo
fi
if [[ -f "$md_file" ]]; then
cat "$md_file"
echo
fi
if [[ -f functions.md ]]; then
cat functions.md
fi
) > "$out_file"
}

mkdir -p "$out"

${lib.concatMapStringsSep "\n" (
{
name,
file,
markdown,
outFile,
title ? "",
...
}:
lib.escapeShellArgs [
"docgen"
"${lib.optionalString (markdown != null) markdown}" # md_file
"${lib.optionalString (file != null) file}" # in_file
name # name
outFile # out_file
title # title
]
) pagesToRender}
''
mkdir -p "$out"

${lib.concatMapStringsSep "\n" (
{
functions,
source,
target,
title ? "",
...
}:
lib.escapeShellArgs [
"docgen"
"${lib.optionalString (source != null) source}" # md_file
"${lib.optionalString (functions.file != null) functions.file}" # in_file
(lib.showAttrPath functions.loc) # name
target # out_file
title # title
]
) pagesToRender}
'';
in
result
32 changes: 16 additions & 16 deletions docs/lib/menu.nix
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
{
lib,
pageSpecs,
pages,
indentSize ? " ",
}:
let
pageToLines =
indent: parentName:
{
name,
outFile ? "",
pages ? { },
...
}:
indent: parent: node:
let
menuName = lib.strings.removePrefix (parentName + ".") name;
children = builtins.attrValues pages;

children = lib.pipe node [
(lib.flip builtins.removeAttrs [ "_page" ])
builtins.attrValues
];
# Only add node to the menu if it has content or multiple children
useNodeInMenu = outFile != "" || builtins.length children > 1;
parentOfChildren = if useNodeInMenu then name else parentName;
useNodeInMenu = node._page.target != "" || node._page.children > 1;
nextParent = if useNodeInMenu then node else parent;
nextIndent = if useNodeInMenu then indent + indentSize else indent;
loc = lib.lists.removePrefix (parent._page.loc or [ ]) node._page.loc;
menuName = lib.attrsets.showAttrPath loc;
in
lib.optional useNodeInMenu "${indent}- [${menuName}](${outFile})"
lib.optional useNodeInMenu "${indent}- [${menuName}](${node._page.target})"
++ lib.optionals (children != [ ]) (
builtins.concatMap (pageToLines (indent + indentSize) parentOfChildren) children
builtins.concatMap (pageToLines nextIndent nextParent) children
);
in
lib.pipe pageSpecs [
lib.pipe pages [
builtins.attrValues
(builtins.concatMap (pageToLines "" ""))
(builtins.concatMap (pageToLines "" null))
lib.concatLines
]
24 changes: 11 additions & 13 deletions docs/lib/pages.nix
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah so this means that we can "easily" add documentation "anywhere" in the module system, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I tried to come up with a structured way of representing a mdbook menu tree.

There are other possible approaches. E.g. we could have a flat structure with each element having a "loc" attribute.

Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@
# If there is an issue parsing the file, the resulting markdown will not contain any function docs.

{
lib.pages = {
nixvim = {
lib.nixvim = {
_page = {
title = "Nixvim's functions";
markdown = ./index.md;
source = ./index.md;
};

pages = {
utils = {
file = ../../lib/utils.nix;
title = "utility functions";
};
lua = {
file = ../../lib/to-lua.nix;
title = "lua functions";
};
};
utils._page = {
title = "utility functions";
functions.file = ../../lib/utils.nix;
};
lua._page = {
title = "lua functions";
functions.file = ../../lib/to-lua.nix;
};
};
}
3 changes: 2 additions & 1 deletion docs/man/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ let
../user-guide/faq.md
../user-guide/config-examples.md
]
++ lib.mapAttrsToList (name: file: "${lib-docs}/${file}") lib-docs.pages;
++ lib-docs.pages;

manHeader =
runCommand "nixvim-general-doc-manpage"
{
Expand Down
Loading