Skip to content

Commit 4f03ca0

Browse files
committed
docs/lib: generalise menu impl using module system
Move the mdbook menu rendering code into the module system and generalise it to apply to multiple "categories" (mdbook parts) and "types" of category (prefix, suffix, etc).
1 parent 2f952af commit 4f03ca0

File tree

8 files changed

+228
-60
lines changed

8 files changed

+228
-60
lines changed

docs/lib/default.nix

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,14 @@
1010
}:
1111

1212
let
13-
pageConfiguration = lib.evalModules {
13+
menuConfiguration = lib.evalModules {
1414
modules = [
1515
pageSpecs
16-
{
17-
freeformType = lib.types.attrsOf (
18-
lib.types.submoduleWith {
19-
modules = [ ../modules/page.nix ];
20-
}
21-
);
22-
}
16+
../modules/menu.nix
2317
];
2418
};
25-
pages = pageConfiguration.config;
19+
cfg = menuConfiguration.config;
20+
pages = cfg.functions;
2621

2722
# Collect all page nodes into a list of page entries
2823
collectPages =
@@ -33,7 +28,7 @@ let
3328
children = builtins.removeAttrs node [ "_page" ];
3429
in
3530
lib.optional (node ? _page) node._page ++ lib.optionals (children != { }) (collectPages children)
36-
) (builtins.attrValues pages);
31+
) (builtins.attrValues (builtins.removeAttrs pages [ "_category" ]));
3732

3833
# Normalised page specs
3934
pageList = collectPages pages;
@@ -60,11 +55,9 @@ let
6055
}
6156
);
6257

63-
passthru.config = pageConfiguration;
58+
passthru.config = menuConfiguration;
6459

65-
passthru.menu = import ./menu.nix {
66-
inherit lib pages;
67-
};
60+
passthru.menu = cfg._menu.text;
6861

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

docs/lib/menu.nix

Lines changed: 0 additions & 31 deletions
This file was deleted.

docs/lib/pages.nix

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@
44
# If there is an issue parsing the file, the resulting markdown will not contain any function docs.
55

66
{
7-
lib.nixvim = {
8-
_page = {
9-
title = "lib.nixvim: Nixvim's functions";
10-
source = ./index.md;
11-
};
7+
functions = {
8+
_category.name = "Functions";
129

13-
utils._page = {
14-
title = "lib.nixvim.utils: utility functions";
15-
functions.file = ../../lib/utils.nix;
16-
};
17-
lua._page = {
18-
title = "lib.nixvim.lua: lua functions";
19-
functions.file = ../../lib/to-lua.nix;
10+
lib.nixvim = {
11+
_page = {
12+
title = "lib.nixvim: Nixvim's functions";
13+
source = ./index.md;
14+
};
15+
16+
utils._page = {
17+
title = "lib.nixvim.utils: utility functions";
18+
functions.file = ../../lib/utils.nix;
19+
};
20+
lua._page = {
21+
title = "lib.nixvim.lua: lua functions";
22+
functions.file = ../../lib/to-lua.nix;
23+
};
2024
};
2125
};
2226
}

docs/mdbook/SUMMARY.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
- [Configuration examples](./user-guide/config-examples.md)
1010
- [Lazy Loading](./user-guide/lazy-loading.md)
1111

12-
# Functions
13-
1412
@FUNCTIONS_MENU@
1513

1614
# Platforms

docs/modules/category.nix

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
{
2+
lib,
3+
name,
4+
config,
5+
options,
6+
...
7+
}:
8+
let
9+
cfg = config._category;
10+
11+
pageType = lib.types.submoduleWith {
12+
modules = [ ./page.nix ];
13+
};
14+
15+
pages = builtins.removeAttrs config (builtins.attrNames options);
16+
in
17+
{
18+
freeformType = lib.types.attrsOf pageType;
19+
20+
options._category = {
21+
name = lib.mkOption {
22+
type = lib.types.str;
23+
default = name;
24+
defaultText = lib.literalMD "attribute name";
25+
};
26+
27+
order = lib.mkOption {
28+
type = lib.types.int;
29+
default = 100;
30+
description = "Priority for where this category will appear in the menu.";
31+
};
32+
33+
type = lib.mkOption {
34+
type = lib.types.enum [
35+
"prefix"
36+
"normal"
37+
"suffix"
38+
];
39+
default = "normal";
40+
description = ''
41+
The kind of mdbook chapters this category contains.
42+
43+
**Prefix Chapter**
44+
: Before the main numbered chapters, prefix chapters can be added that
45+
will not be numbered. This is useful for forewords, introductions, etc.
46+
There are, however, some constraints.
47+
Prefix chapters cannot be nested; they should all be on the root level.
48+
And you cannot add prefix chapters once you have added numbered chapters.
49+
50+
**Normal Chapter**
51+
: Called a "Numbered Chapter" in the MDBook docs.
52+
Numbered chapters outline the main content of the book and can be
53+
nested, resulting in a nice hierarchy (chapters, sub-chapters, etc.).
54+
55+
**Suffix Chapter**
56+
: Like prefix chapters, suffix chapters are unnumbered, but they come
57+
after numbered chapters.
58+
59+
See <https://rust-lang.github.io/mdBook/format/summary.html>.
60+
'';
61+
};
62+
63+
text = lib.mkOption {
64+
type = lib.types.str;
65+
description = "The rendered menu.";
66+
readOnly = true;
67+
};
68+
};
69+
70+
config._category = {
71+
text = lib.optionalString (pages != { }) ''
72+
# ${cfg.name}
73+
74+
${lib.pipe pages [
75+
builtins.attrValues
76+
(map (
77+
page:
78+
page._page.toMenu {
79+
nested = cfg.type == "normal";
80+
indent = "";
81+
prefix = [ ];
82+
inherit page;
83+
}
84+
))
85+
(builtins.concatStringsSep "\n")
86+
]}
87+
'';
88+
};
89+
}

docs/modules/menu.nix

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
lib,
3+
config,
4+
options,
5+
...
6+
}:
7+
let
8+
categoryType = lib.types.submoduleWith {
9+
modules = [ ./category.nix ];
10+
};
11+
12+
categories = builtins.removeAttrs config (builtins.attrNames options);
13+
in
14+
{
15+
freeformType = lib.types.attrsOf categoryType;
16+
17+
options._menu = {
18+
text = lib.mkOption {
19+
type = lib.types.str;
20+
description = "The rendered menu.";
21+
readOnly = true;
22+
};
23+
};
24+
25+
config._menu = {
26+
text = lib.pipe categories [
27+
builtins.attrValues
28+
(map (x: x._category))
29+
(lib.sortOn (x: x.order))
30+
(builtins.groupBy (x: x.type))
31+
(
32+
{
33+
prefix ? [ ],
34+
normal ? [ ],
35+
suffix ? [ ],
36+
}:
37+
prefix ++ normal ++ suffix
38+
)
39+
(map (x: x.text))
40+
(builtins.concatStringsSep "\n\n")
41+
];
42+
};
43+
}

docs/modules/page-options.nix

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ in
4949
};
5050
functions.loc = lib.mkOption {
5151
type = lib.types.listOf lib.types.str;
52-
default = lib.lists.removePrefix [ "lib" ] cfg.loc;
52+
default = if lib.lists.hasPrefix [ "lib" ] cfg.loc then builtins.tail cfg.loc else cfg.loc;
5353
defaultText = lib.literalMD ''
5454
`loc`'s attrpath, without any leading "lib"
5555
'';
@@ -72,6 +72,30 @@ in
7272
If an attrset is provided, it will be coerced using `lib.options.optionAttrSetToDocList`.
7373
'';
7474
};
75+
toMenu = lib.mkOption {
76+
type = lib.types.functionTo lib.types.str;
77+
description = ''
78+
A function to render the menu for this sub-tree.
79+
80+
Typically, this involves invoking `_page.toMenu` for all children.
81+
82+
**Inputs**
83+
84+
`settings`
85+
: `nested`
86+
: Whether this menu category supports nesting.
87+
88+
`indent`
89+
: The indentation to use before non-empty lines.
90+
91+
`page`
92+
: This page node.
93+
94+
`prefix`
95+
: The menu loc prefix, to be omitted from menu entry text.
96+
Usually the `loc` of the parent page node.
97+
'';
98+
};
7599
children = lib.mkOption {
76100
type = lib.types.ints.unsigned;
77101
description = ''
@@ -100,5 +124,10 @@ in
100124
cfg.functions.file # doc-comments
101125
cfg.options # module options
102126
];
127+
128+
toMenu = import ./to-menu.nix {
129+
inherit lib;
130+
optionNames = builtins.attrNames options;
131+
};
103132
};
104133
}

docs/modules/to-menu.nix

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
lib,
3+
optionNames,
4+
}:
5+
/**
6+
The default `toMenu` function renders a page node into a menu subtree.
7+
*/
8+
{
9+
page,
10+
prefix ? [ ],
11+
indent ? "",
12+
nested ? true,
13+
}:
14+
let
15+
inherit (page._page) loc target;
16+
count = page._page.children;
17+
18+
# Only add node to the menu if it has content or multiple children
19+
showInMenu = target != "" || count > 1;
20+
nextPrefix = if showInMenu then loc else prefix;
21+
nextIndent = if showInMenu && nested then indent + " " else indent;
22+
23+
children = builtins.removeAttrs page optionNames;
24+
submenu = lib.pipe children [
25+
builtins.attrValues
26+
(map (
27+
subpage:
28+
page._page.toMenu {
29+
inherit nested;
30+
page = subpage;
31+
indent = nextIndent;
32+
prefix = nextPrefix;
33+
}
34+
))
35+
];
36+
37+
loc' = if lib.lists.hasPrefix prefix loc then lib.lists.drop (builtins.length prefix) loc else loc;
38+
menuText = lib.attrsets.showAttrPath loc';
39+
menuitem = lib.optionals showInMenu [
40+
(indent + lib.optionalString nested "- " + "[${menuText}](${target})")
41+
];
42+
in
43+
builtins.concatStringsSep "\n" (menuitem ++ submenu)

0 commit comments

Comments
 (0)