-
-
Notifications
You must be signed in to change notification settings - Fork 300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: experimental re-write #2884
base: main
Are you sure you want to change the base?
Changes from all commits
1cff786
ac29a33
2df01b6
6fdfa80
fc972cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
{ | ||
lib, | ||
config, | ||
pkgs, | ||
... | ||
}: | ||
let | ||
inherit (config.docs.menu) | ||
sections | ||
; | ||
|
||
transformOption = | ||
let | ||
root = builtins.toString ../../.; | ||
mkGitHubDeclaration = user: repo: branch: subpath: { | ||
url = "https://github.com/${user}/${repo}/blob/${branch}/${subpath}"; | ||
name = "<${repo}/${subpath}>"; | ||
}; | ||
transformDeclaration = | ||
decl: | ||
if lib.hasPrefix root (builtins.toString decl) then | ||
mkGitHubDeclaration "nix-community" "nixvim" "main" ( | ||
lib.removePrefix "/" (lib.strings.removePrefix root (builtins.toString decl)) | ||
) | ||
else if decl == "lib/modules.nix" then | ||
mkGitHubDeclaration "NixOS" "nixpkgs" "master" decl | ||
else | ||
decl; | ||
in | ||
opt: opt // { declarations = builtins.map transformDeclaration opt.declarations; }; | ||
|
||
docsPageModule = | ||
{ name, config, ... }: | ||
{ | ||
options = { | ||
enable = lib.mkOption { | ||
type = lib.types.bool; | ||
description = "Whether to enable this page/menu item."; | ||
default = true; | ||
example = false; | ||
}; | ||
target = lib.mkOption { | ||
type = lib.types.str; | ||
description = '' | ||
The target filepath, relative to the root of the docs. | ||
''; | ||
default = lib.optionalString (name != "") (name + "/") + "index.md"; | ||
defaultText = lib.literalMD '' | ||
`<name>` joined with `"index.md"`. Separated by `"/"` if `<name>` is non-empty. | ||
''; | ||
}; | ||
source = lib.mkOption { | ||
type = with lib.types; nullOr path; | ||
description = '' | ||
Markdown page. Set to null to create a menu entry without a corresponding file. | ||
''; | ||
}; | ||
menu.location = lib.mkOption { | ||
type = with lib.types; listOf str; | ||
description = '' | ||
A location path that represents the page's position in the menu tree. | ||
|
||
The text displayed in the menu is derived from this value, | ||
after the location of any parent nodes in the tree is removed. | ||
|
||
For example, if this page has the location `[ "foo" "bar" ]` | ||
and there is another page with the location `[ "foo" ]`, | ||
then the menu will render as: | ||
```markdown | ||
- foo | ||
- bar | ||
``` | ||
|
||
However if there was no other page with the `[ "foo" ]` location, | ||
the menu would instead render as: | ||
```markdown | ||
- foo.bar | ||
``` | ||
''; | ||
default = | ||
let | ||
list = lib.splitString "/" config.target; | ||
last = lib.last list; | ||
rest = lib.dropEnd 1 list; | ||
in | ||
if last == "index.md" then | ||
rest | ||
else if lib.hasSuffix ".md" last then | ||
rest ++ [ (lib.removeSuffix ".md" last) ] | ||
else | ||
list; | ||
defaultText = lib.literalMD '' | ||
`target`, split by `"/"`, with any trailing `"index.md` or `".md"` suffixes removed. | ||
''; | ||
}; | ||
menu.section = lib.mkOption { | ||
type = lib.types.enum (builtins.attrNames sections); | ||
description = '' | ||
Determines the menu section. | ||
|
||
Must be a section defined in `docs.menu.sections`. | ||
''; | ||
}; | ||
}; | ||
}; | ||
in | ||
{ | ||
options.docs._utils = lib.mkOption { | ||
type = with lib.types; lazyAttrsOf raw; | ||
description = "internal utils, modules, functions, etc"; | ||
default = { }; | ||
internal = true; | ||
visible = false; | ||
}; | ||
|
||
Comment on lines
+108
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we go with a "utils" module instead of additions to the nixvim lib or to a separate "docs" library? (I'm not suggesting it's better, I genuinely don't know why we should choose one or the other) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thought process was that I wanted to avoid bloating our lib with docs-specific things. I also wanted things in this util to be able to depend on Not saying this is the best approach, though. |
||
config.docs._utils = { | ||
# A liberal type that permits any superset of docsPageModule | ||
docsPageLiberalType = lib.types.submodule [ | ||
{ _module.check = false; } | ||
docsPageModule | ||
]; | ||
Comment on lines
+118
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the difference between this and a freeform option? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah this is an "extendable" submodule in some sense? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A freeform submodule allows On the other hand, this "liberal" submodule just discards any definitions that don't correspond to a declared option. I.e. option existence checks are disabled. |
||
|
||
/** | ||
Uses `lib.optionAttrSetToDocList` to produce a list of docs-options. | ||
|
||
A doc-option has the following attrs, as expected by `nixos-render-docs`: | ||
|
||
``` | ||
{ | ||
loc, | ||
name, # rendered with `showOption loc` | ||
description, | ||
declarations, | ||
internal, | ||
visible, # normalised to a boolean | ||
readOnly, | ||
type, # normalised to `type.description` | ||
default,? # rendered with `lib.options.renderOptionValue` | ||
example,? # rendered with `lib.options.renderOptionValue` | ||
relatedPackages,? | ||
} | ||
``` | ||
|
||
Additionally, sub-options are recursively flattened into the list, | ||
unless `visible == "shallow"` or `visible == false`. | ||
|
||
This function extends `lib.optionAttrSetToDocList` by also filtering out | ||
invisible and internal options, and by applying Nixvim's `transformOption` | ||
function. | ||
|
||
The implementation is based on `pkgs.nixosOptionsDoc`: | ||
https://github.com/NixOS/nixpkgs/blob/e2078ef3/nixos/lib/make-options-doc/default.nix#L117-L126 | ||
*/ | ||
mkOptionList = lib.flip lib.pipe [ | ||
MattSturgeon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(lib.flip builtins.removeAttrs [ "_module" ]) | ||
lib.optionAttrSetToDocList | ||
(builtins.map transformOption) | ||
(builtins.filter (opt: opt.visible && !opt.internal)) | ||
# TODO: consider supporting `relatedPackages` | ||
# See https://github.com/NixOS/nixpkgs/blob/61235d44/lib/options.nix#L103-L104 | ||
# and https://github.com/NixOS/nixpkgs/blob/61235d44/nixos/lib/make-options-doc/default.nix#L128-L165 | ||
]; | ||
|
||
inherit docsPageModule; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
lib, | ||
config, | ||
pkgs, | ||
... | ||
}: | ||
let | ||
inherit (config.docs._utils) | ||
docsPageLiberalType | ||
; | ||
in | ||
{ | ||
options.docs = { | ||
_allInputs = lib.mkOption { | ||
type = with lib.types; listOf str; | ||
description = "`docs.*` option names that should be included in `docs.all`."; | ||
defaultText = config.docs._allInputs; | ||
default = [ ]; | ||
internal = true; | ||
visible = false; | ||
}; | ||
all = lib.mkOption { | ||
type = with lib.types; listOf docsPageLiberalType; | ||
description = '' | ||
All enabled doc pages defined in: | ||
${lib.concatMapStringsSep "\n" (name: "- `docs.${name}`") config.docs._allInputs}. | ||
''; | ||
visible = "shallow"; | ||
readOnly = true; | ||
}; | ||
Comment on lines
+14
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This dance is to have a readonly option whose definitions are split around the nixvim source right? Is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kinda. I marked it as read-only because it seemed unlikely that someone should define a page directly here, without using one of the more specific implementations. The other options listed in Also, unlike |
||
src = lib.mkOption { | ||
type = lib.types.package; | ||
description = "All source files for the docs."; | ||
readOnly = true; | ||
}; | ||
}; | ||
|
||
config.docs = { | ||
# Copy all pages from options listed in _allInputs | ||
all = builtins.filter (page: page.enable or true) ( | ||
builtins.concatMap (name: builtins.attrValues config.docs.${name}) config.docs._allInputs | ||
); | ||
|
||
# A directory with all the files in it | ||
src = pkgs.callPackage ./src.nix { | ||
pages = builtins.filter (page: page.source or null != null) config.docs.all; | ||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ lib, ... }: | ||
{ | ||
options.enableMan = lib.mkOption { | ||
type = lib.types.bool; | ||
default = true; | ||
description = "Install the man pages for NixVim options."; | ||
}; | ||
|
||
imports = [ | ||
./_util.nix | ||
./all.nix | ||
./files.nix | ||
./mdbook | ||
./menu | ||
./options.nix | ||
./platforms.nix | ||
]; | ||
|
||
config.docs.options = { | ||
docs = { | ||
menu.location = [ "docs" ]; | ||
optionScopes = [ "docs" ]; | ||
description = '' | ||
Internal options used to construct these docs. | ||
''; | ||
}; | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a gut reaction it feels a bit strange to have a function called
mkMetaModule
that sets other things than meta arguments.It feels a "duplicate" of the metadata in another form, can't we extract it with a well placed library function? (Not entirely sure, as the metadata is a bit of a complicated beast --')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot of deliberately duplicated stuff, with the idea being that the "old" way will eventually be removed.