Skip to content

Commit 270b0a1

Browse files
committed
modules/docs: construct docs from docs.* options
Introduce various `docs.*` options where doc pages, menu entries, etc can be defined. The options themselves are responsible for rendering this to markdown and HTML.
1 parent 13b5401 commit 270b0a1

File tree

15 files changed

+904
-2
lines changed

15 files changed

+904
-2
lines changed

docs/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ let
8888
{
8989
isDocs = true;
9090
_module.args.pkgs = lib.mkForce noPkgs;
91+
docs._utils.docsPkgs = lib.mkForce pkgs;
9192
}
9293
];
9394
};

modules/default.nix

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@
2323
./performance.nix
2424
./plugins.nix
2525
];
26+
27+
docs.options.options = {
28+
enable = true;
29+
optionScopes = [ ];
30+
};
2631
}

modules/docs/_util.nix

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
{
2+
lib,
3+
config,
4+
pkgs,
5+
...
6+
}:
7+
let
8+
inherit (config.docs.menu)
9+
categories
10+
;
11+
12+
transformOptions =
13+
let
14+
root = builtins.toString ../../.;
15+
mkGitHubDeclaration = user: repo: branch: subpath: {
16+
url = "https://github.com/${user}/${repo}/blob/${branch}/${subpath}";
17+
name = "<${repo}/${subpath}>";
18+
};
19+
transformDeclaration =
20+
decl:
21+
if lib.hasPrefix root (builtins.toString decl) then
22+
mkGitHubDeclaration "nix-community" "nixvim" "main" (
23+
lib.removePrefix "/" (lib.strings.removePrefix root (builtins.toString decl))
24+
)
25+
else if decl == "lib/modules.nix" then
26+
mkGitHubDeclaration "NixOS" "nixpkgs" "master" decl
27+
else
28+
decl;
29+
in
30+
opt: opt // { declarations = builtins.map transformDeclaration opt.declarations; };
31+
32+
docsPageModule =
33+
{ name, config, ... }:
34+
{
35+
options = {
36+
enable = lib.mkOption {
37+
type = lib.types.bool;
38+
description = "Whether to enable this page/menu item.";
39+
default = true;
40+
example = false;
41+
};
42+
target = lib.mkOption {
43+
type = lib.types.str;
44+
description = ''
45+
The target filepath, relative to the root of the docs.
46+
'';
47+
default = lib.optionalString (name != "") (name + "/") + "index.md";
48+
defaultText = lib.literalMD ''
49+
`<name>` joined with `"index.md"`. Separated by `"/"` if `<name>` is non-empty.
50+
'';
51+
};
52+
source = lib.mkOption {
53+
type = with lib.types; nullOr path;
54+
description = ''
55+
Markdown page. Set to null to create a menu entry without a corresponding file.
56+
'';
57+
};
58+
menu.position = lib.mkOption {
59+
type = with lib.types; listOf str;
60+
description = "The position in the menu.";
61+
default =
62+
let
63+
list = lib.splitString "/" config.target;
64+
last = lib.last list;
65+
rest = lib.dropEnd 1 list;
66+
in
67+
if last == "index.md" then
68+
rest
69+
else if lib.hasSuffix ".md" last then
70+
rest ++ [ (lib.removeSuffix ".md" last) ]
71+
else
72+
list;
73+
defaultText = lib.literalMD ''
74+
`target`, split by `"/"`, with any trailing `"index.md` or `".md"` suffixes removed.
75+
'';
76+
};
77+
menu.category = lib.mkOption {
78+
type = lib.types.enum (builtins.attrNames categories);
79+
description = ''
80+
A category defined in `docs.menu.categories`.
81+
82+
Determines the menu category, section, etc.
83+
'';
84+
};
85+
};
86+
};
87+
in
88+
{
89+
options.docs._utils = lib.mkOption {
90+
type = with lib.types; lazyAttrsOf raw;
91+
description = "internal utils, modules, functions, etc";
92+
default = { };
93+
internal = true;
94+
visible = false;
95+
};
96+
97+
config.docs._utils = {
98+
# Can be overridden to an externally defined pkgs,
99+
# because _module.args.pkgs will be stubbed when evaling for the docs
100+
docsPkgs = lib.mkOptionDefault pkgs;
101+
102+
# A liberal type that permits any superset of docsPageModule
103+
docsPageLiberalType = lib.types.submodule [
104+
{ _module.check = false; }
105+
docsPageModule
106+
];
107+
108+
mkOptionList = lib.flip lib.pipe [
109+
(lib.flip builtins.removeAttrs [ "_module" ])
110+
lib.optionAttrSetToDocList
111+
(builtins.map transformOptions)
112+
(builtins.filter (opt: opt.visible && !opt.internal))
113+
# TODO: consider supporting `relatedPackages`
114+
# See https://github.com/NixOS/nixpkgs/blob/61235d44/lib/options.nix#L103-L104
115+
# and https://github.com/NixOS/nixpkgs/blob/61235d44/nixos/lib/make-options-doc/default.nix#L128-L165
116+
];
117+
118+
inherit docsPageModule;
119+
};
120+
}

modules/docs/all.nix

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
lib,
3+
config,
4+
...
5+
}:
6+
let
7+
inherit (config.docs._utils)
8+
docsPageLiberalType
9+
docsPkgs
10+
;
11+
in
12+
{
13+
options.docs = {
14+
all = lib.mkOption {
15+
type = with lib.types; listOf docsPageLiberalType;
16+
# TODO: define docs.allSources option that this option should source pages from
17+
description = "All enabled doc pages defined in `pages`, `platforms`, and `optiosn`";
18+
apply = builtins.filter (page: page.enable);
19+
internal = true;
20+
visible = false;
21+
};
22+
src = lib.mkOption {
23+
type = lib.types.package;
24+
description = "All source files for the docs.";
25+
internal = true;
26+
visible = false;
27+
readOnly = true;
28+
};
29+
};
30+
31+
config.docs = {
32+
# A directory with all the files in it
33+
src = docsPkgs.callPackage ./src.nix {
34+
pages = builtins.filter (page: page.source or null != null) config.docs.all;
35+
};
36+
};
37+
}

modules/docs/default.nix

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,14 @@
55
default = true;
66
description = "Install the man pages for NixVim options.";
77
};
8+
9+
imports = [
10+
./_util.nix
11+
./all.nix
12+
./files.nix
13+
./mdbook
14+
./menu
15+
./options.nix
16+
./platforms.nix
17+
];
818
}

modules/docs/files.nix

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
lib,
3+
config,
4+
...
5+
}:
6+
let
7+
inherit (config.docs._utils)
8+
docsPageModule
9+
;
10+
11+
docsPageType = lib.types.submodule (
12+
{
13+
name,
14+
config,
15+
options,
16+
...
17+
}:
18+
let
19+
derivationName = builtins.replaceStrings [ "/" ] [ "-" ] name;
20+
in
21+
{
22+
imports = [
23+
docsPageModule
24+
];
25+
options.text = lib.mkOption {
26+
type = with lib.types; nullOr lines;
27+
default = null;
28+
description = "Text of the file.";
29+
};
30+
config.source = lib.mkIf (config.text != null) (
31+
lib.mkDerivedConfig options.text (builtins.toFile derivationName)
32+
);
33+
}
34+
);
35+
36+
user-guide = ../../docs/user-guide;
37+
in
38+
{
39+
options.docs = {
40+
files = lib.mkOption {
41+
type = with lib.types; lazyAttrsOf docsPageType;
42+
description = ''
43+
A set of pages to include in the docs.
44+
45+
The attr name defines the filepath.
46+
'';
47+
default = { };
48+
internal = true;
49+
visible = false;
50+
};
51+
};
52+
53+
config.docs = {
54+
files =
55+
{
56+
"" = {
57+
menu.category = "header";
58+
menu.position = [ "Home" ];
59+
source = ../../docs/mdbook/index.md;
60+
};
61+
}
62+
// lib.concatMapAttrs (
63+
name: type:
64+
let
65+
title = lib.removeSuffix ".md" name;
66+
in
67+
lib.optionalAttrs (type == "regular") {
68+
"user-guide/${title}" = {
69+
menu.category = "user-guide";
70+
# TODO: define user-facing titles to show in the menu...
71+
menu.position = [ title ];
72+
source = "${user-guide}/${name}";
73+
};
74+
}
75+
) (builtins.readDir user-guide);
76+
77+
# Copy values into `all`
78+
all = builtins.attrValues config.docs.files;
79+
};
80+
}

modules/docs/mdbook/default.nix

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
lib,
3+
config,
4+
...
5+
}:
6+
let
7+
inherit (config.docs._utils) docsPkgs;
8+
defaultSettings = {
9+
book = {
10+
language = "en";
11+
multilingual = false;
12+
title = "nixvim docs";
13+
};
14+
build.create-missing = false;
15+
output.html.site-url = "/";
16+
output.html.fold = {
17+
enable = true;
18+
level = 0;
19+
};
20+
preprocessor.alerts = { };
21+
};
22+
in
23+
{
24+
options.docs.html = {
25+
site = lib.mkOption {
26+
type = lib.types.package;
27+
description = "HTML docs rendered by mdbook.";
28+
internal = true;
29+
visible = false;
30+
readOnly = true;
31+
};
32+
settings = lib.mkOption {
33+
type = with lib.types; attrsOf anything;
34+
description = ''
35+
Freeform settings written to `book.toml`.
36+
37+
See MDBook's [Configuration](https://rust-lang.github.io/mdBook/format/configuration/index.html) docs.
38+
'';
39+
defaultText = defaultSettings;
40+
internal = true;
41+
visible = false;
42+
};
43+
};
44+
config.docs.html = {
45+
site = docsPkgs.callPackage ./package.nix {
46+
inherit (config.docs) src;
47+
inherit (config.docs.html) settings;
48+
menu = config.docs.menu.src;
49+
};
50+
settings = defaultSettings;
51+
};
52+
}

modules/docs/mdbook/package.nix

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
writers,
3+
mdbook,
4+
mdbook-alerts,
5+
runCommand,
6+
menu,
7+
src,
8+
settings,
9+
}:
10+
runCommand "html-docs"
11+
{
12+
inherit src;
13+
14+
nativeBuildInputs = [
15+
mdbook
16+
mdbook-alerts
17+
];
18+
19+
settings = writers.writeTOML "book.toml" settings;
20+
menu = builtins.toFile "menu.md" (builtins.unsafeDiscardStringContext menu);
21+
}
22+
''
23+
mkdir src
24+
for input in $src/*; do
25+
name=$(basename "$input")
26+
ln -s "$input" "src/$name"
27+
done
28+
ln -s $settings book.toml
29+
ln -s $menu src/SUMMARY.md
30+
31+
# Build the website
32+
mdbook build --dest-dir $out
33+
''

0 commit comments

Comments
 (0)