Skip to content
11 changes: 8 additions & 3 deletions docs/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ let
# The following pkgs attrs are required to eval nixvim, even for the docs:
inherit (pkgs)
_type
callPackage
formats
runCommand
runCommandLocal
stdenv
stdenvNoCC
symlinkJoin
runCommand
runCommandLocal
writeShellApplication
;
}
Expand Down Expand Up @@ -122,7 +124,10 @@ lib.fix (
# > sandbox-exec: pattern serialization length 69298 exceeds maximum (65535)
docs = pkgs.callPackage ./mdbook {
inherit evaledModules transformOptions;
inherit (self) search;
inherit (self) search beta-docs;
};

# Beta docs
beta-docs = evaledModules.config.docs.html.site;
}
)
12 changes: 12 additions & 0 deletions docs/mdbook/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
nixosOptionsDoc,
transformOptions,
search,
beta-docs,
# The root directory of the site
baseHref ? "/",
# A list of all available docs that should be linked to
Expand Down Expand Up @@ -375,6 +376,10 @@ pkgs.stdenv.mkDerivation (finalAttrs: {
cp -r ./book/* $dest
mkdir -p $dest/search
cp -r ${finalAttrs.passthru.search}/* $dest/search

# Also build the beta docs
mkdir -p $dest/beta
cp -r ${finalAttrs.passthru.beta-docs}/* $dest/beta
'';

inherit baseHref;
Expand Down Expand Up @@ -406,6 +411,11 @@ pkgs.stdenv.mkDerivation (finalAttrs: {
search = search.override {
baseHref = finalAttrs.baseHref + "search/";
};
beta-docs = beta-docs.override (old: {
settings = lib.recursiveUpdate old.settings {
output.html.site-url = "${baseHref}/beta";
};
});
docs-versions =
runCommand "docs-versions"
{
Expand Down Expand Up @@ -435,6 +445,8 @@ pkgs.stdenv.mkDerivation (finalAttrs: {

echo "- The $link, for use with nixpkgs \`$nixpkgs\`$suffix" >> "$out"
done
# link to beta-docs
echo "- The [beta-docs](./beta), for use with "
'';
user-configs = callPackage ../user-configs { };
};
Expand Down
31 changes: 31 additions & 0 deletions lib/plugins/utils.nix
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,24 @@
{ options, ... }:
let
opts = lib.getAttrFromPath loc options;
docsfile = lib.concatStringsSep "/" loc;
url =
if args.url or null == null then
opts.package.default.meta.homepage or (throw "unable to get URL for `${lib.showOption loc}`.")
else
args.url;
maintainersString =
let
toMD = m: if m ? github then "[${m.name}](https://github.com/${m.github})" else m.name;
names = builtins.map toMD (lib.unique maintainers);
count = builtins.length names;
in
if count == 1 then
builtins.head names
else if count == 2 then
lib.concatStringsSep " and " names
else
lib.concatMapStrings (name: "\n- ${name}") names;
in
{
meta = {
Expand All @@ -110,5 +123,23 @@
path = loc;
};
};

docs.pages.${docsfile}.text = lib.mkMerge (
[
"# ${lib.last loc}"
""
"**URL:** [${url}](${url})"
""
]
++ lib.optionals (maintainers != [ ]) [
"**Maintainers:** ${maintainersString}"
""
]
++ lib.optionals (description != null && description != "") [
"---"
""
description
]
);
};
}
7 changes: 6 additions & 1 deletion modules/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
# using this in a submodule nested within another nixvim config.
{
imports = [
./docs
./misc
./autocmd.nix
./clipboard.nix
./colorscheme.nix
./commands.nix
./diagnostics.nix
./doc.nix
./editorconfig.nix
./files.nix
./filetype.nix
Expand All @@ -23,4 +23,9 @@
./performance.nix
./plugins.nix
];

docs.optionPages.options = {
enable = true;
optionScopes = [ ];
};
}
8 changes: 0 additions & 8 deletions modules/doc.nix

This file was deleted.

74 changes: 74 additions & 0 deletions modules/docs/_utils.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{ lib, ... }:
let
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; };
in
{
options.docs._utils = lib.mkOption {
type = with lib.types; lazyAttrsOf raw;
description = "internal utils, modules, functions, etc";
default = { };
internal = true;
visible = false;
};

config.docs._utils = {
/**
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 [
(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
];
};
}
27 changes: 27 additions & 0 deletions modules/docs/collect-sources.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
lib,
runCommandLocal,
pages,
}:
# Implementation based on NixOS's /etc module
runCommandLocal "docs-sources" { } ''
set -euo pipefail

makeEntry() {
src="$1"
target="$2"
mkdir -p "$out/$(dirname "$target")"
cp "$src" "$out/$target"
}

mkdir -p "$out"
${lib.concatMapStringsSep "\n" (
{ target, source, ... }:
lib.escapeShellArgs [
"makeEntry"
# Force local source paths to be added to the store
"${source}"
target
]
) pages}
''
45 changes: 45 additions & 0 deletions modules/docs/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{ lib, pkgs, ... }:
let
# Convert links relative to github -> relative to docs
fixLinks = pkgs.callPackage ../../docs/fix-links { };
in
{
options.enableMan = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Install the man pages for NixVim options.";
};

imports = [
./_utils.nix
./mdbook
./menu
./option-pages
./pages.nix
./platforms.nix
./user-guide
];

config.docs = {
pages."" = {
menu.section = "header";
menu.location = [ "Home" ];
source = pkgs.callPackage ./readme.nix {
inherit fixLinks;
# TODO: get `availableVersions` and `baseHref` from module options
};
};
pages.contributing = {
menu.section = "footer";
menu.location = [ "Contributing" ];
source = fixLinks ../../CONTRIBUTING.md;
};
optionPages.docs = {
optionScopes = [ "docs" ];
page.menu.location = [ "docs" ];
page.text = ''
Internal options used to construct these docs.
'';
};
};
}
50 changes: 50 additions & 0 deletions modules/docs/mdbook/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
lib,
config,
pkgs,
...
}:
let
settingsFormat = pkgs.formats.toml { };
defaultSettings = {
book = {
language = "en";
multilingual = false;
title = "nixvim docs";
};
build.create-missing = false;
output.html.site-url = "/";
output.html.fold = {
enable = true;
level = 0;
};
preprocessor.alerts = { };
};
in
{
options.docs.html = {
site = lib.mkOption {
type = lib.types.package;
description = "HTML docs rendered by mdbook.";
readOnly = true;
};
settings = lib.mkOption {
inherit (settingsFormat) type;
description = ''
Freeform settings written to `book.toml`.

See MDBook's [Configuration](https://rust-lang.github.io/mdBook/format/configuration/index.html) docs.
'';
defaultText = defaultSettings;
};
};
config.docs.html = {
site = pkgs.callPackage ./package.nix {
inherit (config.docs) src;
inherit (config.docs.html) settings;
menu = config.docs.menu.src;
writeTOML = settingsFormat.generate;
};
settings = defaultSettings;
};
}
33 changes: 33 additions & 0 deletions modules/docs/mdbook/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
mdbook,
mdbook-alerts,
runCommand,
writeTOML,
menu,
settings,
src,
}:
runCommand "html-docs"
{
inherit src;

nativeBuildInputs = [
mdbook
mdbook-alerts
];

settings = writeTOML "book.toml" settings;
menu = builtins.toFile "menu.md" (builtins.unsafeDiscardStringContext menu);
Copy link
Member

Choose a reason for hiding this comment

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

A comment would be nice to say what is discarded, I guess the why is that docs are "inert"?

Copy link
Member Author

@MattSturgeon MattSturgeon Feb 12, 2025

Choose a reason for hiding this comment

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

I copied this from the nixos docs impl, and there was no comment to copy. I'll try come up with something.

However, yeah "string context" is how nix keeps track of a string's dependencies. E.g. if you do "${pkgs.hello}/bin/hello" then that string has some "context" so that nix knows it has a dependency on the pkgs.hello derivation.

Using unsafeDiscardStringContext drops that context, so unsafeDiscardStringContext "${pkgs.hello}/bin/hello" would have the same string value, but without the dependency on building the pkgs.hello derivation.

In the context of the docs, I believe this is mainly relevant for the "declared by" links, and maybe any default or example values that accidentally used a derivation in its value. I.e. we want the string value, but we don't want the dependency.

}
''
mkdir src
for input in $src/*; do
name=$(basename "$input")
ln -s "$input" "src/$name"
done
ln -s $settings book.toml
ln -s $menu src/SUMMARY.md

# Build the website
mdbook build --dest-dir $out
''
Loading