summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md33
-rw-r--r--checks/simple-mdbook/.gitignore1
-rw-r--r--checks/simple-mdbook/book.toml6
-rw-r--r--checks/simple-mdbook/src/SUMMARY.md6
-rw-r--r--checks/simple-mdbook/src/chapter_1.md1
-rw-r--r--checks/simple-mdbook/src/chapter_2-1.md1
-rw-r--r--checks/simple-mdbook/src/chapter_2.md1
-rw-r--r--doc-options-md.nix67
-rw-r--r--documentation-highlighter/LICENSE29
-rw-r--r--documentation-highlighter/README.md47
-rw-r--r--documentation-highlighter/default.nix15
-rw-r--r--documentation-highlighter/highlight.min.js400
-rw-r--r--documentation-highlighter/loader.js7
-rw-r--r--documentation-highlighter/mono-blue.min.css1
-rwxr-xr-xdocumentation-highlighter/update.sh44
-rw-r--r--flake.lock27
-rw-r--r--flake.nix133
-rw-r--r--manpage.nix139
-rw-r--r--mdbook.nix141
20 files changed, 1101 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..750baeb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
1result
2result-*
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..70eeb2a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,33 @@
1# nix-module-doc
2
3Generate documentation for your NixOS-like modules.
4
5`nix-module-doc` is capable of generating a markdown file, a manpage, and an
6mkbook.
7
8## Usage
9
10In your `flake.nix`
11
12```nix
13{
14 inputs.nix-module-doc.url = "github:minijackson/nix-module-doc";
15
16 outputs = inputs: {
17 nixosModule.yourModule = let
18 docParams = {
19 # Where to store the outputs
20 outputAttrPath = ["your" "module" "outputs"];
21 # Where to store the documentation options
22 optionsAttrPath = ["your" "module" "doc"];
23 };
24 in {
25 imports = [
26 (inputs.nix-module-doc.lib.modules.doc-options-md docParams)
27 (inputs.nix-module-doc.lib.modules.manpage docParams)
28 (inputs.nix-module-doc.lib.modules.mdbook docParams)
29 ];
30 }
31 };
32}
33```
diff --git a/checks/simple-mdbook/.gitignore b/checks/simple-mdbook/.gitignore
new file mode 100644
index 0000000..7585238
--- /dev/null
+++ b/checks/simple-mdbook/.gitignore
@@ -0,0 +1 @@
book
diff --git a/checks/simple-mdbook/book.toml b/checks/simple-mdbook/book.toml
new file mode 100644
index 0000000..425d511
--- /dev/null
+++ b/checks/simple-mdbook/book.toml
@@ -0,0 +1,6 @@
1[book]
2authors = ["Minijackson"]
3language = "en"
4multilingual = false
5src = "src"
6title = "Simple MdBook"
diff --git a/checks/simple-mdbook/src/SUMMARY.md b/checks/simple-mdbook/src/SUMMARY.md
new file mode 100644
index 0000000..250cfce
--- /dev/null
+++ b/checks/simple-mdbook/src/SUMMARY.md
@@ -0,0 +1,6 @@
1# Summary
2
3- [Chapter 1](./chapter_1.md)
4- [Chapter 2](./chapter_2.md)
5 - [Chapter 2.2](./chapter_2-1.md)
6- [Available options](./options.md)
diff --git a/checks/simple-mdbook/src/chapter_1.md b/checks/simple-mdbook/src/chapter_1.md
new file mode 100644
index 0000000..b743fda
--- /dev/null
+++ b/checks/simple-mdbook/src/chapter_1.md
@@ -0,0 +1 @@
# Chapter 1
diff --git a/checks/simple-mdbook/src/chapter_2-1.md b/checks/simple-mdbook/src/chapter_2-1.md
new file mode 100644
index 0000000..b5cb2dc
--- /dev/null
+++ b/checks/simple-mdbook/src/chapter_2-1.md
@@ -0,0 +1 @@
# Chapter 2.2
diff --git a/checks/simple-mdbook/src/chapter_2.md b/checks/simple-mdbook/src/chapter_2.md
new file mode 100644
index 0000000..7ebb596
--- /dev/null
+++ b/checks/simple-mdbook/src/chapter_2.md
@@ -0,0 +1 @@
# Chapter 2
diff --git a/doc-options-md.nix b/doc-options-md.nix
new file mode 100644
index 0000000..1cc1bf2
--- /dev/null
+++ b/doc-options-md.nix
@@ -0,0 +1,67 @@
1{
2 outputAttrPath,
3 optionsAttrPath,
4 optionsInternal ? true,
5}: {
6 lib,
7 options,
8 pkgs,
9 ...
10}:
11with lib; let
12 visibleOptionDocs = filter (opt: opt.visible && !opt.internal) (optionAttrSetToDocList options);
13
14 isLiteral = value:
15 value
16 ? _type
17 && (value._type == "literalExpression"
18 || value._type == "literalExample"
19 || value._type == "literalMD");
20
21 toValue = value:
22 if isLiteral value
23 then value.text
24 else generators.toPretty {} value;
25
26 toText = value:
27 if value ? _type
28 then value.text
29 else value;
30
31 toMarkdown = option: ''
32 ## `${option.name}`
33
34 ${toText option.description}
35
36 ${optionalString (option ? default) ''
37 **Default value**:
38
39 ```nix
40 ${toValue option.default}
41 ```
42 ''}
43
44 **Type**: ${option.type}${optionalString option.readOnly " (read only)"}
45
46 ${optionalString (option ? example) ''
47 **Example**:
48
49 ```nix
50 ${toValue option.example}
51 ```
52 ''}
53
54 Declared in:
55
56 ${concatStringsSep "\n" (map (decl: "- ${decl}") option.declarations)}
57
58 '';
59
60 # TODO: rewrite "Declared in" so that it points to GitHub repository
61
62 options-md = concatStringsSep "\n" (map toMarkdown visibleOptionDocs);
63in {
64 config = setAttrByPath outputAttrPath {
65 doc-options-md = pkgs.writeText "options.md" options-md;
66 };
67}
diff --git a/documentation-highlighter/LICENSE b/documentation-highlighter/LICENSE
new file mode 100644
index 0000000..2250cc7
--- /dev/null
+++ b/documentation-highlighter/LICENSE
@@ -0,0 +1,29 @@
1BSD 3-Clause License
2
3Copyright (c) 2006, Ivan Sagalaev.
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are met:
8
9* Redistributions of source code must retain the above copyright notice, this
10 list of conditions and the following disclaimer.
11
12* Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16* Neither the name of the copyright holder nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/documentation-highlighter/README.md b/documentation-highlighter/README.md
new file mode 100644
index 0000000..569c90a
--- /dev/null
+++ b/documentation-highlighter/README.md
@@ -0,0 +1,47 @@
1This file was generated with pkgs/misc/documentation-highlighter/update.sh
2
3# Highlight.js CDN Assets
4
5[![install size](https://packagephobia.now.sh/badge?p=highlight.js)](https://packagephobia.now.sh/result?p=highlight.js)
6
7**This package contains only the CDN build assets of highlight.js.**
8
9This may be what you want if you'd like to install the pre-built distributable highlight.js client-side assets via NPM. If you're wanting to use highlight.js mainly on the server-side you likely want the [highlight.js][1] package instead.
10
11To access these files via CDN:<br>
12https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/
13
14**If you just want a single .js file with the common languages built-in:
15<https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/highlight.min.js>**
16
17---
18
19## Highlight.js
20
21Highlight.js is a syntax highlighter written in JavaScript. It works in
22the browser as well as on the server. It works with pretty much any
23markup, doesn’t depend on any framework, and has automatic language
24detection.
25
26If you'd like to read the full README:<br>
27<https://github.com/highlightjs/highlight.js/blob/main/README.md>
28
29## License
30
31Highlight.js is released under the BSD License. See [LICENSE][7] file
32for details.
33
34## Links
35
36The official site for the library is at <https://highlightjs.org/>.
37
38The Github project may be found at: <https://github.com/highlightjs/highlight.js>
39
40Further in-depth documentation for the API and other topics is at
41<http://highlightjs.readthedocs.io/>.
42
43A list of the Core Team and contributors can be found in the [CONTRIBUTORS.md][8] file.
44
45[1]: https://www.npmjs.com/package/highlight.js
46[7]: https://github.com/highlightjs/highlight.js/blob/main/LICENSE
47[8]: https://github.com/highlightjs/highlight.js/blob/main/CONTRIBUTORS.md
diff --git a/documentation-highlighter/default.nix b/documentation-highlighter/default.nix
new file mode 100644
index 0000000..dbba883
--- /dev/null
+++ b/documentation-highlighter/default.nix
@@ -0,0 +1,15 @@
1{
2 lib,
3 runCommand,
4}:
5runCommand "documentation-highlighter" {
6 meta = {
7 description = "Highlight.js sources for the Nix Ecosystem's documentation";
8 homepage = "https://highlightjs.org";
9 license = lib.licenses.bsd3;
10 platforms = lib.platforms.all;
11 maintainers = [lib.maintainers.grahamc];
12 };
13} ''
14 cp -r ${./.} $out
15''
diff --git a/documentation-highlighter/highlight.min.js b/documentation-highlighter/highlight.min.js
new file mode 100644
index 0000000..550f2b3
--- /dev/null
+++ b/documentation-highlighter/highlight.min.js
@@ -0,0 +1,400 @@
1/*!
2 Highlight.js v11.4.0 (git: 2d0e7c1094)
3 (c) 2006-2022 Ivan Sagalaev and other contributors
4 License: BSD-3-Clause
5 */
6var hljs=function(){"use strict";var e={exports:{}};function t(e){
7return e instanceof Map?e.clear=e.delete=e.set=()=>{
8throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{
9throw Error("set is read-only")
10}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((n=>{var i=e[n]
11;"object"!=typeof i||Object.isFrozen(i)||t(i)})),e}
12e.exports=t,e.exports.default=t;var n=e.exports;class i{constructor(e){
13void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
14ignoreMatch(){this.isMatchIgnored=!0}}function r(e){
15return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
16}function s(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
17;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const o=e=>!!e.kind
18;class a{constructor(e,t){
19this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
20this.buffer+=r(e)}openNode(e){if(!o(e))return;let t=e.kind
21;t=e.sublanguage?"language-"+t:((e,{prefix:t})=>{if(e.includes(".")){
22const n=e.split(".")
23;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
24}return`${t}${e}`})(t,{prefix:this.classPrefix}),this.span(t)}closeNode(e){
25o(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
26this.buffer+=`<span class="${e}">`}}class c{constructor(){this.rootNode={
27children:[]},this.stack=[this.rootNode]}get top(){
28return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
29this.top.children.push(e)}openNode(e){const t={kind:e,children:[]}
30;this.add(t),this.stack.push(t)}closeNode(){
31if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
32for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
33walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
34return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
35t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
36"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
37c._collapse(e)})))}}class l extends c{constructor(e){super(),this.options=e}
38addKeyword(e,t){""!==e&&(this.openNode(t),this.addText(e),this.closeNode())}
39addText(e){""!==e&&this.add(e)}addSublanguage(e,t){const n=e.root
40;n.kind=t,n.sublanguage=!0,this.add(n)}toHTML(){
41return new a(this,this.options).value()}finalize(){return!0}}function g(e){
42return e?"string"==typeof e?e:e.source:null}function d(e){return f("(?=",e,")")}
43function u(e){return f("(?:",e,")*")}function h(e){return f("(?:",e,")?")}
44function f(...e){return e.map((e=>g(e))).join("")}function p(...e){const t=(e=>{
45const t=e[e.length-1]
46;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
47})(e);return"("+(t.capture?"":"?:")+e.map((e=>g(e))).join("|")+")"}
48function b(e){return RegExp(e.toString()+"|").exec("").length-1}
49const m=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
50;function E(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
51;let i=g(e),r="";for(;i.length>0;){const e=m.exec(i);if(!e){r+=i;break}
52r+=i.substring(0,e.index),
53i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?r+="\\"+(Number(e[1])+t):(r+=e[0],
54"("===e[0]&&n++)}return r})).map((e=>`(${e})`)).join(t)}
55const x="[a-zA-Z]\\w*",w="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",_="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",v="\\b(0b[01]+)",k={
56begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'",
57illegal:"\\n",contains:[k]},N={scope:"string",begin:'"',end:'"',illegal:"\\n",
58contains:[k]},M=(e,t,n={})=>{const i=s({scope:"comment",begin:e,end:t,
59contains:[]},n);i.contains.push({scope:"doctag",
60begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
61end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
62;const r=p("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
63;return i.contains.push({begin:f(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i
64},S=M("//","$"),R=M("/\\*","\\*/"),j=M("#","$");var A=Object.freeze({
65__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:x,UNDERSCORE_IDENT_RE:w,
66NUMBER_RE:y,C_NUMBER_RE:_,BINARY_NUMBER_RE:v,
67RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
68SHEBANG:(e={})=>{const t=/^#![ ]*\//
69;return e.binary&&(e.begin=f(t,/.*\b/,e.binary,/\b.*/)),s({scope:"meta",begin:t,
70end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
71BACKSLASH_ESCAPE:k,APOS_STRING_MODE:O,QUOTE_STRING_MODE:N,PHRASAL_WORDS_MODE:{
72begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
73},COMMENT:M,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:R,HASH_COMMENT_MODE:j,
74NUMBER_MODE:{scope:"number",begin:y,relevance:0},C_NUMBER_MODE:{scope:"number",
75begin:_,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:v,relevance:0},
76REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,
77end:/\/[gimuy]*/,illegal:/\n/,contains:[k,{begin:/\[/,end:/\]/,relevance:0,
78contains:[k]}]}]},TITLE_MODE:{scope:"title",begin:x,relevance:0},
79UNDERSCORE_TITLE_MODE:{scope:"title",begin:w,relevance:0},METHOD_GUARD:{
80begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{
81"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
82t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function I(e,t){
83"."===e.input[e.index-1]&&t.ignoreMatch()}function T(e,t){
84void 0!==e.className&&(e.scope=e.className,delete e.className)}function L(e,t){
85t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
86e.__beforeBegin=I,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
87void 0===e.relevance&&(e.relevance=0))}function B(e,t){
88Array.isArray(e.illegal)&&(e.illegal=p(...e.illegal))}function D(e,t){
89if(e.match){
90if(e.begin||e.end)throw Error("begin & end are not supported with match")
91;e.begin=e.match,delete e.match}}function H(e,t){
92void 0===e.relevance&&(e.relevance=1)}const P=(e,t)=>{if(!e.beforeMatch)return
93;if(e.starts)throw Error("beforeMatch cannot be used with starts")
94;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
95})),e.keywords=n.keywords,e.begin=f(n.beforeMatch,d(n.begin)),e.starts={
96relevance:0,contains:[Object.assign(n,{endsParent:!0})]
97},e.relevance=0,delete n.beforeMatch
98},C=["of","and","for","in","not","or","if","then","parent","list","value"]
99;function $(e,t,n="keyword"){const i=Object.create(null)
100;return"string"==typeof e?r(n,e.split(" ")):Array.isArray(e)?r(n,e):Object.keys(e).forEach((n=>{
101Object.assign(i,$(e[n],t,n))})),i;function r(e,n){
102t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
103;i[n[0]]=[e,U(n[0],n[1])]}))}}function U(e,t){
104return t?Number(t):(e=>C.includes(e.toLowerCase()))(e)?0:1}const z={},K=e=>{
105console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{
106z[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),z[`${e}/${t}`]=!0)
107},G=Error();function Z(e,t,{key:n}){let i=0;const r=e[n],s={},o={}
108;for(let e=1;e<=t.length;e++)o[e+i]=r[e],s[e+i]=!0,i+=b(t[e-1])
109;e[n]=o,e[n]._emit=s,e[n]._multi=!0}function F(e){(e=>{
110e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
111delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
112_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
113}),(e=>{if(Array.isArray(e.begin)){
114if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
115G
116;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"),
117G;Z(e,e.begin,{key:"beginScope"}),e.begin=E(e.begin,{joinWith:""})}})(e),(e=>{
118if(Array.isArray(e.end)){
119if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
120G
121;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"),
122G;Z(e,e.end,{key:"endScope"}),e.end=E(e.end,{joinWith:""})}})(e)}function V(e){
123function t(t,n){
124return RegExp(g(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
125}class n{constructor(){
126this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
127addRule(e,t){
128t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
129this.matchAt+=b(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
130;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(E(e,{joinWith:"|"
131}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
132;const t=this.matcherRe.exec(e);if(!t)return null
133;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
134;return t.splice(0,n),Object.assign(t,i)}}class i{constructor(){
135this.rules=[],this.multiRegexes=[],
136this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
137if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
138;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
139t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
140return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
141this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
142const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
143;let n=t.exec(e)
144;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
145const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
146return n&&(this.regexIndex+=n.position+1,
147this.regexIndex===this.count&&this.considerAll()),n}}
148if(e.compilerExtensions||(e.compilerExtensions=[]),
149e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
150;return e.classNameAliases=s(e.classNameAliases||{}),function n(r,o){const a=r
151;if(r.isCompiled)return a
152;[T,D,F,P].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))),
153r.__beforeBegin=null,[L,B,H].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null
154;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
155c=r.keywords.$pattern,
156delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=$(r.keywords,e.case_insensitive)),
157a.keywordPatternRe=t(c,!0),
158o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
159r.end&&(a.endRe=t(a.end)),
160a.terminatorEnd=g(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)),
161r.illegal&&(a.illegalRe=t(r.illegal)),
162r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>s(e,{
163variants:null},t)))),e.cachedVariants?e.cachedVariants:q(e)?s(e,{
164starts:e.starts?s(e.starts):null
165}):Object.isFrozen(e)?s(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a)
166})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new i
167;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
168}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
169}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function q(e){
170return!!e&&(e.endsWithParent||q(e.starts))}class J extends Error{
171constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
172const Y=r,Q=s,ee=Symbol("nomatch");var te=(e=>{
173const t=Object.create(null),r=Object.create(null),s=[];let o=!0
174;const a="Could not find the language '{}', did you forget to load/include a language module?",c={
175disableAutodetect:!0,name:"Plain text",contains:[]};let g={
176ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
177languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
178cssSelector:"pre code",languages:null,__emitter:l};function b(e){
179return g.noHighlightRe.test(e)}function m(e,t,n){let i="",r=""
180;"object"==typeof t?(i=e,
181n=t.ignoreIllegals,r=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."),
182X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
183r=e,i=t),void 0===n&&(n=!0);const s={code:i,language:r};N("before:highlight",s)
184;const o=s.result?s.result:E(s.language,s.code,n)
185;return o.code=s.code,N("after:highlight",o),o}function E(e,n,r,s){
186const c=Object.create(null);function l(){if(!O.keywords)return void M.addText(S)
187;let e=0;O.keywordPatternRe.lastIndex=0;let t=O.keywordPatternRe.exec(S),n=""
188;for(;t;){n+=S.substring(e,t.index)
189;const r=y.case_insensitive?t[0].toLowerCase():t[0],s=(i=r,O.keywords[i]);if(s){
190const[e,i]=s
191;if(M.addText(n),n="",c[r]=(c[r]||0)+1,c[r]<=7&&(R+=i),e.startsWith("_"))n+=t[0];else{
192const n=y.classNameAliases[e]||e;M.addKeyword(t[0],n)}}else n+=t[0]
193;e=O.keywordPatternRe.lastIndex,t=O.keywordPatternRe.exec(S)}var i
194;n+=S.substr(e),M.addText(n)}function d(){null!=O.subLanguage?(()=>{
195if(""===S)return;let e=null;if("string"==typeof O.subLanguage){
196if(!t[O.subLanguage])return void M.addText(S)
197;e=E(O.subLanguage,S,!0,N[O.subLanguage]),N[O.subLanguage]=e._top
198}else e=x(S,O.subLanguage.length?O.subLanguage:null)
199;O.relevance>0&&(R+=e.relevance),M.addSublanguage(e._emitter,e.language)
200})():l(),S=""}function u(e,t){let n=1;for(;void 0!==t[n];){if(!e._emit[n]){n++
201;continue}const i=y.classNameAliases[e[n]]||e[n],r=t[n]
202;i?M.addKeyword(r,i):(S=r,l(),S=""),n++}}function h(e,t){
203return e.scope&&"string"==typeof e.scope&&M.openNode(y.classNameAliases[e.scope]||e.scope),
204e.beginScope&&(e.beginScope._wrap?(M.addKeyword(S,y.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
205S=""):e.beginScope._multi&&(u(e.beginScope,t),S="")),O=Object.create(e,{parent:{
206value:O}}),O}function f(e,t,n){let r=((e,t)=>{const n=e&&e.exec(t)
207;return n&&0===n.index})(e.endRe,n);if(r){if(e["on:end"]){const n=new i(e)
208;e["on:end"](t,n),n.isMatchIgnored&&(r=!1)}if(r){
209for(;e.endsParent&&e.parent;)e=e.parent;return e}}
210if(e.endsWithParent)return f(e.parent,t,n)}function p(e){
211return 0===O.matcher.regexIndex?(S+=e[0],1):(I=!0,0)}function b(e){
212const t=e[0],i=n.substr(e.index),r=f(O,e,i);if(!r)return ee;const s=O
213;O.endScope&&O.endScope._wrap?(d(),
214M.addKeyword(t,O.endScope._wrap)):O.endScope&&O.endScope._multi?(d(),
215u(O.endScope,e)):s.skip?S+=t:(s.returnEnd||s.excludeEnd||(S+=t),
216d(),s.excludeEnd&&(S=t));do{
217O.scope&&M.closeNode(),O.skip||O.subLanguage||(R+=O.relevance),O=O.parent
218}while(O!==r.parent);return r.starts&&h(r.starts,e),s.returnEnd?0:t.length}
219let m={};function w(t,s){const a=s&&s[0];if(S+=t,null==a)return d(),0
220;if("begin"===m.type&&"end"===s.type&&m.index===s.index&&""===a){
221if(S+=n.slice(s.index,s.index+1),!o){const t=Error(`0 width match regex (${e})`)
222;throw t.languageName=e,t.badRule=m.rule,t}return 1}
223if(m=s,"begin"===s.type)return(e=>{
224const t=e[0],n=e.rule,r=new i(n),s=[n.__beforeBegin,n["on:begin"]]
225;for(const n of s)if(n&&(n(e,r),r.isMatchIgnored))return p(t)
226;return n.skip?S+=t:(n.excludeBegin&&(S+=t),
227d(),n.returnBegin||n.excludeBegin||(S=t)),h(n,e),n.returnBegin?0:t.length})(s)
228;if("illegal"===s.type&&!r){
229const e=Error('Illegal lexeme "'+a+'" for mode "'+(O.scope||"<unnamed>")+'"')
230;throw e.mode=O,e}if("end"===s.type){const e=b(s);if(e!==ee)return e}
231if("illegal"===s.type&&""===a)return 1
232;if(A>1e5&&A>3*s.index)throw Error("potential infinite loop, way more iterations than matches")
233;return S+=a,a.length}const y=v(e)
234;if(!y)throw K(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
235;const _=V(y);let k="",O=s||_;const N={},M=new g.__emitter(g);(()=>{const e=[]
236;for(let t=O;t!==y;t=t.parent)t.scope&&e.unshift(t.scope)
237;e.forEach((e=>M.openNode(e)))})();let S="",R=0,j=0,A=0,I=!1;try{
238for(O.matcher.considerAll();;){
239A++,I?I=!1:O.matcher.considerAll(),O.matcher.lastIndex=j
240;const e=O.matcher.exec(n);if(!e)break;const t=w(n.substring(j,e.index),e)
241;j=e.index+t}return w(n.substr(j)),M.closeAllNodes(),M.finalize(),k=M.toHTML(),{
242language:e,value:k,relevance:R,illegal:!1,_emitter:M,_top:O}}catch(t){
243if(t.message&&t.message.includes("Illegal"))return{language:e,value:Y(n),
244illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j,
245context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:k},_emitter:M};if(o)return{
246language:e,value:Y(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:O}
247;throw t}}function x(e,n){n=n||g.languages||Object.keys(t);const i=(e=>{
248const t={value:Y(e),illegal:!1,relevance:0,_top:c,_emitter:new g.__emitter(g)}
249;return t._emitter.addText(e),t})(e),r=n.filter(v).filter(O).map((t=>E(t,e,!1)))
250;r.unshift(i);const s=r.sort(((e,t)=>{
251if(e.relevance!==t.relevance)return t.relevance-e.relevance
252;if(e.language&&t.language){if(v(e.language).supersetOf===t.language)return 1
253;if(v(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=s,l=o
254;return l.secondBest=a,l}function w(e){let t=null;const n=(e=>{
255let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
256;const n=g.languageDetectRe.exec(t);if(n){const t=v(n[1])
257;return t||(W(a.replace("{}",n[1])),
258W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
259return t.split(/\s+/).find((e=>b(e)||v(e)))})(e);if(b(n))return
260;if(N("before:highlightElement",{el:e,language:n
261}),e.children.length>0&&(g.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
262console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),
263console.warn("The element with unescaped HTML:"),
264console.warn(e)),g.throwUnescapedHTML))throw new J("One of your code blocks includes unescaped HTML.",e.innerHTML)
265;t=e;const i=t.textContent,s=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
266;e.innerHTML=s.value,((e,t,n)=>{const i=t&&r[t]||n
267;e.classList.add("hljs"),e.classList.add("language-"+i)
268})(e,n,s.language),e.result={language:s.language,re:s.relevance,
269relevance:s.relevance},s.secondBest&&(e.secondBest={
270language:s.secondBest.language,relevance:s.secondBest.relevance
271}),N("after:highlightElement",{el:e,result:s,text:i})}let y=!1;function _(){
272"loading"!==document.readyState?document.querySelectorAll(g.cssSelector).forEach(w):y=!0
273}function v(e){return e=(e||"").toLowerCase(),t[e]||t[r[e]]}
274function k(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
275r[e.toLowerCase()]=t}))}function O(e){const t=v(e)
276;return t&&!t.disableAutodetect}function N(e,t){const n=e;s.forEach((e=>{
277e[n]&&e[n](t)}))}
278"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
279y&&_()}),!1),Object.assign(e,{highlight:m,highlightAuto:x,highlightAll:_,
280highlightElement:w,
281highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"),
282X("10.7.0","Please use highlightElement now."),w(e)),configure:e=>{g=Q(g,e)},
283initHighlighting:()=>{
284_(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
285initHighlightingOnLoad:()=>{
286_(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
287},registerLanguage:(n,i)=>{let r=null;try{r=i(e)}catch(e){
288if(K("Language definition for '{}' could not be registered.".replace("{}",n)),
289!o)throw e;K(e),r=c}
290r.name||(r.name=n),t[n]=r,r.rawDefinition=i.bind(null,e),r.aliases&&k(r.aliases,{
291languageName:n})},unregisterLanguage:e=>{delete t[e]
292;for(const t of Object.keys(r))r[t]===e&&delete r[t]},
293listLanguages:()=>Object.keys(t),getLanguage:v,registerAliases:k,
294autoDetection:O,inherit:Q,addPlugin:e=>{(e=>{
295e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
296e["before:highlightBlock"](Object.assign({block:t.el},t))
297}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
298e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),s.push(e)}
299}),e.debugMode=()=>{o=!1},e.safeMode=()=>{o=!0
300},e.versionString="11.4.0",e.regex={concat:f,lookahead:d,either:p,optional:h,
301anyNumberOfTimes:u};for(const e in A)"object"==typeof A[e]&&n(A[e])
302;return Object.assign(e,A),e})({});return te}()
303;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `python` grammar compiled for Highlight.js 11.4.0 */
304(()=>{var e=(()=>{"use strict";return e=>{
305const n=e.regex,a=/[\p{XID_Start}_]\p{XID_Continue}*/u,i=["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],s={
306$pattern:/[A-Za-z]\w+|__\w+__/,keyword:i,
307built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],
308literal:["__debug__","Ellipsis","False","None","NotImplemented","True"],
309type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"]
310},t={className:"meta",begin:/^(>>>|\.\.\.) /},r={className:"subst",begin:/\{/,
311end:/\}/,keywords:s,illegal:/#/},l={begin:/\{\{/,relevance:0},b={
312className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{
313begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,
314contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{
315begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,
316contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{
317begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,
318contains:[e.BACKSLASH_ESCAPE,t,l,r]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,
319end:/"""/,contains:[e.BACKSLASH_ESCAPE,t,l,r]},{begin:/([uU]|[rR])'/,end:/'/,
320relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{
321begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,
322end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,
323contains:[e.BACKSLASH_ESCAPE,l,r]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,
324contains:[e.BACKSLASH_ESCAPE,l,r]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]
325},o="[0-9](_?[0-9])*",c=`(\\b(${o}))?\\.(${o})|\\b(${o})\\.`,d="\\b|"+i.join("|"),g={
326className:"number",relevance:0,variants:[{
327begin:`(\\b(${o})|(${c}))[eE][+-]?(${o})[jJ]?(?=${d})`},{begin:`(${c})[jJ]?`},{
328begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${d})`},{
329begin:`\\b0[bB](_?[01])+[lL]?(?=${d})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${d})`
330},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${d})`},{begin:`\\b(${o})[jJ](?=${d})`
331}]},p={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:s,
332contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={
333className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,
334end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:s,
335contains:["self",t,g,b,e.HASH_COMMENT_MODE]}]};return r.contains=[b,g,t],{
336name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:s,
337illegal:/(<\/|->|\?)|=>/,contains:[t,g,{begin:/\bself\b/},{beginKeywords:"if",
338relevance:0},b,p,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,a],scope:{
3391:"keyword",3:"title.function"},contains:[m]},{variants:[{
340match:[/\bclass/,/\s+/,a,/\s*/,/\(\s*/,a,/\s*\)/]},{match:[/\bclass/,/\s+/,a]}],
341scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{
342className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[g,m,b]}]}}})()
343;hljs.registerLanguage("python",e)})();/*! `bash` grammar compiled for Highlight.js 11.4.0 */
344(()=>{var e=(()=>{"use strict";return e=>{const s=e.regex,t={},n={begin:/\$\{/,
345end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]};Object.assign(t,{
346className:"variable",variants:[{
347begin:s.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},n]});const a={
348className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={
349begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,
350end:/(\w+)/,className:"string"})]}},c={className:"string",begin:/"/,end:/"/,
351contains:[e.BACKSLASH_ESCAPE,t,a]};a.contains.push(c);const o={begin:/\$\(\(/,
352end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]
353},r=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10
354}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,
355contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{
356name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/,
357keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],
358literal:["true","false"],
359built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"]
360},contains:[r,e.SHEBANG(),l,o,e.HASH_COMMENT_MODE,i,{match:/(\/[a-z._-]+)+/},c,{
361className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},t]}}})()
362;hljs.registerLanguage("bash",e)})();/*! `nix` grammar compiled for Highlight.js 11.4.0 */
363(()=>{var e=(()=>{"use strict";return e=>{const n={
364keyword:["rec","with","let","in","inherit","assert","if","else","then"],
365literal:["true","false","or","and","null"],
366built_in:["import","abort","baseNameOf","dirOf","isNull","builtins","map","removeAttrs","throw","toString","derivation"]
367},i={className:"subst",begin:/\$\{/,end:/\}/,keywords:n},s={className:"string",
368contains:[i],variants:[{begin:"''",end:"''"},{begin:'"',end:'"'}]
369},t=[e.NUMBER_MODE,e.HASH_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{
370begin:/[a-zA-Z0-9-_]+(\s*=)/,returnBegin:!0,relevance:0,contains:[{
371className:"attr",begin:/\S+/}]}];return i.contains=t,{name:"Nix",
372aliases:["nixos"],keywords:n,contains:t}}})();hljs.registerLanguage("nix",e)
373})();/*! `makefile` grammar compiled for Highlight.js 11.4.0 */
374(()=>{var e=(()=>{"use strict";return e=>{const i={className:"variable",
375variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",
376contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%<?\^\+\*]/}]},a={className:"string",
377begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,i]},n={className:"variable",
378begin:/\$\([\w-]+\s/,end:/\)/,keywords:{
379built_in:"subst patsubst strip findstring filter filter-out sort word wordlist firstword lastword dir notdir suffix basename addsuffix addprefix join wildcard realpath abspath error warning shell origin flavor foreach if or and call eval file value"
380},contains:[i]},s={begin:"^"+e.UNDERSCORE_IDENT_RE+"\\s*(?=[:+?]?=)"},r={
381className:"section",begin:/^[^\s]+:/,end:/$/,contains:[i]};return{
382name:"Makefile",aliases:["mk","mak","make"],keywords:{$pattern:/[\w-]+/,
383keyword:"define endef undefine ifdef ifndef ifeq ifneq else endif include -include sinclude override export unexport private vpath"
384},contains:[e.HASH_COMMENT_MODE,i,a,n,s,{className:"meta",begin:/^\.PHONY:/,
385end:/$/,keywords:{$pattern:/[\.\w]+/,keyword:".PHONY"}},r]}}})()
386;hljs.registerLanguage("makefile",e)})();/*! `ini` grammar compiled for Highlight.js 11.4.0 */
387(()=>{var e=(()=>{"use strict";return e=>{const n=e.regex,a={className:"number",
388relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{begin:e.NUMBER_RE}]
389},s=e.COMMENT();s.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];const i={
390className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)\}/
391}]},t={className:"literal",begin:/\bon|off|true|false|yes|no\b/},r={
392className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",
393end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'
394},{begin:"'",end:"'"}]},l={begin:/\[/,end:/\]/,contains:[s,t,i,r,a,"self"],
395relevance:0},c=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{
396name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,
397contains:[s,{className:"section",begin:/\[+/,end:/\]+/},{
398begin:n.concat(c,"(\\s*\\.\\s*",c,")*",n.lookahead(/\s*=\s*[^#\s]/)),
399className:"attr",starts:{end:/$/,contains:[s,l,t,i,r,a]}}]}}})()
400;hljs.registerLanguage("ini",e)})(); \ No newline at end of file
diff --git a/documentation-highlighter/loader.js b/documentation-highlighter/loader.js
new file mode 100644
index 0000000..4ad7dbf
--- /dev/null
+++ b/documentation-highlighter/loader.js
@@ -0,0 +1,7 @@
1/* This file is NOT part of highlight.js */
2document.onreadystatechange = function () {
3 var listings = document.querySelectorAll('.programlisting, .screen');
4 for (i = 0; i < listings.length; ++i) {
5 hljs.highlightBlock(listings[i]);
6 }
7}
diff --git a/documentation-highlighter/mono-blue.min.css b/documentation-highlighter/mono-blue.min.css
new file mode 100644
index 0000000..fb74d40
--- /dev/null
+++ b/documentation-highlighter/mono-blue.min.css
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#eaeef3;color:#00193a}.hljs-doctag,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title{font-weight:700}.hljs-comment{color:#738191}.hljs-addition,.hljs-built_in,.hljs-literal,.hljs-name,.hljs-quote,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-tag,.hljs-title,.hljs-type{color:#0048ab}.hljs-attribute,.hljs-bullet,.hljs-deletion,.hljs-link,.hljs-meta,.hljs-regexp,.hljs-subst,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#4c81c9}.hljs-emphasis{font-style:italic} \ No newline at end of file
diff --git a/documentation-highlighter/update.sh b/documentation-highlighter/update.sh
new file mode 100755
index 0000000..8e31a96
--- /dev/null
+++ b/documentation-highlighter/update.sh
@@ -0,0 +1,44 @@
1#!/usr/bin/env nix-shell
2#!nix-shell -i bash -p curl -p unzip
3
4# Adapted from <nixpkgs>/pkgs/misc/documentation-highlighter/update.sh
5
6set -eu
7set -o pipefail
8
9root=$(pwd)
10
11if [ ! -f "./update.sh" ]; then
12 echo "Please run this script from within pkgs/misc/documentation-highlighter/!"
13 exit 1
14fi
15
16scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
17function finish {
18 rm -rf "$scratch"
19}
20trap finish EXIT
21
22
23mkdir $scratch/src
24cd $scratch/src
25
26token=$(curl https://highlightjs.org/download/ -c "$scratch/jar" \
27 | grep csrf \
28 | cut -d'"' -f6)
29
30curl --header "Referer: https://highlightjs.org/download/"\
31 -b "$scratch/jar" \
32 --data "csrfmiddlewaretoken=$token&nix.js=on&bash.js=on&python.js=on&makefile.js=on&ini.js=on" \
33 https://highlightjs.org/download/ > $scratch/out.zip
34
35unzip "$scratch/out.zip"
36out="$root/"
37mkdir -p "$out"
38cp ./{highlight.min.js,LICENSE,styles/mono-blue.min.css} "$out"
39
40(
41 echo "This file was generated with pkgs/misc/documentation-highlighter/update.sh"
42 echo ""
43 cat README.md
44) > "$out/README.md"
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..e8abb12
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,27 @@
1{
2 "nodes": {
3 "nixpkgs": {
4 "locked": {
5 "lastModified": 1673800717,
6 "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=",
7 "owner": "NixOS",
8 "repo": "nixpkgs",
9 "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f",
10 "type": "github"
11 },
12 "original": {
13 "owner": "NixOS",
14 "ref": "nixos-22.11",
15 "repo": "nixpkgs",
16 "type": "github"
17 }
18 },
19 "root": {
20 "inputs": {
21 "nixpkgs": "nixpkgs"
22 }
23 }
24 },
25 "root": "root",
26 "version": 7
27}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..4e03cbf
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,133 @@
1{
2 description = "Generate documentation for your own projects using the NixOS module system";
3
4 inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";
5
6 outputs = {
7 self,
8 nixpkgs,
9 }: let
10 pkgs = nixpkgs.legacyPackages.x86_64-linux;
11 in {
12 lib.modules = {
13 doc-options-md = import ./doc-options-md.nix;
14 mdbook = import ./mdbook.nix;
15 manpage = import ./manpage.nix;
16 };
17
18 checks.x86_64-linux = let
19 evalModules = modules:
20 pkgs.lib.evalModules {
21 modules =
22 [
23 {config._module.args = {pkgs = pkgs.__splicedPackages;};}
24 ]
25 ++ modules;
26 };
27 simpleModule = with pkgs.lib; {
28 options.my.simple.module.outputs = mkOption {
29 type = with types; attrsOf package;
30 default = {};
31 description = ''
32 Output products of my simple module system.
33 '';
34 };
35 };
36 params = {
37 outputAttrPath = ["my" "simple" "module" "outputs"];
38 optionsAttrPath = ["my" "simple" "module" "doc"];
39 optionsInternal = false;
40 };
41
42 simple-manpage = {
43 name = "my simple module system";
44 shortDescription = "A sample module system";
45 };
46
47 advanced-manpage = {
48 name = "my simple module system";
49 section = 5;
50 shortDescription = "A sample module system";
51 description = ''
52 This is a very advanced module system, for advanced people.
53 '';
54
55 textBefore = ''
56 # A SECTION BEFORE
57
58 This is a section before the options.
59 '';
60
61 textAfter = ''
62 # A SECTION AFTER
63
64 This is a section after the options.
65 '';
66 };
67 in {
68 simple-doc-options-md =
69 (evalModules [
70 simpleModule
71 (self.lib.modules.doc-options-md params)
72 ])
73 .config
74 .my
75 .simple
76 .module
77 .outputs
78 .doc-options-md;
79
80 simple-manpage =
81 (evalModules [
82 simpleModule
83 (self.lib.modules.doc-options-md params)
84 (self.lib.modules.manpage params)
85 {
86 my.simple.module.doc.manpage = simple-manpage;
87 }
88 ])
89 .config
90 .my
91 .simple
92 .module
93 .outputs
94 .manpage;
95
96 advanced-manpage =
97 (evalModules [
98 simpleModule
99 (self.lib.modules.doc-options-md params)
100 (self.lib.modules.manpage params)
101 {
102 my.simple.module.doc.manpage = advanced-manpage;
103 }
104 ])
105 .config
106 .my
107 .simple
108 .module
109 .outputs
110 .manpage;
111
112 simple-mdbook =
113 (evalModules [
114 simpleModule
115 (self.lib.modules.doc-options-md params)
116 (self.lib.modules.mdbook params)
117 {
118 my.simple.module.doc.mdbook.src = ./checks/simple-mdbook;
119 }
120 ])
121 .config
122 .my
123 .simple
124 .module
125 .outputs
126 .mdbook;
127 };
128
129 devShell.x86_64-linux = pkgs.mkShell {
130 nativeBuildInputs = with pkgs; [mdbook pandoc];
131 };
132 };
133}
diff --git a/manpage.nix b/manpage.nix
new file mode 100644
index 0000000..c47d88a
--- /dev/null
+++ b/manpage.nix
@@ -0,0 +1,139 @@
1{
2 outputAttrPath,
3 optionsAttrPath,
4 optionsInternal ? true,
5}: {
6 config,
7 lib,
8 pkgs,
9 ...
10}:
11with lib; let
12 cfg = getAttrFromPath (optionsAttrPath ++ ["manpage"]) config;
13in {
14 options = setAttrByPath optionsAttrPath {
15 manpage = {
16 name = mkOption {
17 type = types.str;
18 description = ''
19 Name of the generated manpage.
20 '';
21 internal = optionsInternal;
22 };
23
24 shortDescription = mkOption {
25 type = types.str;
26 description = ''
27 A short description of the generated manpage.
28 '';
29 internal = optionsInternal;
30 };
31
32 description = mkOption {
33 type = with types; nullOr lines;
34 description = ''
35 A long description of the generated manpage.
36 '';
37 default = null;
38 internal = optionsInternal;
39 };
40
41 section = mkOption {
42 type = types.int;
43 default = 5;
44 description = ''
45 The section number for the generated manpage.
46
47 The table below shows the section numbers of the manual followed by the types of pages they contain.
48
49 1. Executable programs or shell commands
50 2. System calls (functions provided by the kernel)
51 3. Library calls (functions within program libraries)
52 4. Special files (usually found in /dev)
53 5. File formats and conventions, e.g. /etc/passwd
54 6. Games
55 7. Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
56 8. System administration commands (usually only for root)
57 9. Kernel routines [Non standard]
58 '';
59 internal = optionsInternal;
60 };
61
62 file = mkOption {
63 type = types.str;
64 description = ''
65 The file containing the generated manpage.
66 '';
67 default = "${strings.sanitizeDerivationName cfg.name}.${toString cfg.section}";
68 defaultText = "\${lib.strings.sanitizeDerivationName cfg.name}.\${toString cfg.section}";
69 internal = optionsInternal;
70 };
71
72 title = mkOption {
73 type = types.str;
74 default = "${toUpper (strings.sanitizeDerivationName cfg.name)}(${toString cfg.section})";
75 defaultText = "\${toUpper cfg.name}(\${toString cfg.section})";
76 description = ''
77 Title of the generated manpage.
78 '';
79 internal = optionsInternal;
80 };
81
82 textBefore = mkOption {
83 type = types.lines;
84 description = ''
85 Some text to insert before the list of options.
86 '';
87 default = "";
88 internal = optionsInternal;
89 };
90
91 textAfter = mkOption {
92 type = types.lines;
93 description = ''
94 Some text to insert after the list of options.
95 '';
96 default = "";
97 internal = optionsInternal;
98 };
99 };
100 };
101
102 config = setAttrByPath outputAttrPath {
103 manpage =
104 pkgs.runCommand cfg.file
105 {
106 src = pkgs.writeText "${cfg.file}.md" ''
107 % ${cfg.title}
108
109 # NAME
110
111 ${cfg.name} - ${cfg.shortDescription}
112
113
114 ${optionalString (cfg.description != null) ''
115 # DESCRIPTION
116
117 ${cfg.description}
118 ''}
119
120
121 ${cfg.textBefore}
122
123
124 # OPTIONS
125
126 You can use the following options:
127
128 ${readFile (getAttrFromPath (outputAttrPath ++ ["doc-options-md"]) config)}
129
130
131 ${cfg.textAfter}
132 '';
133
134 nativeBuildInputs = [pkgs.pandoc];
135 } ''
136 pandoc "$src" --from=markdown --to=man --standalone --output="$out"
137 '';
138 };
139}
diff --git a/mdbook.nix b/mdbook.nix
new file mode 100644
index 0000000..931dbc1
--- /dev/null
+++ b/mdbook.nix
@@ -0,0 +1,141 @@
1{
2 outputAttrPath,
3 optionsAttrPath,
4 optionsInternal ? true,
5}: {
6 config,
7 lib,
8 pkgs,
9 ...
10}:
11with lib; let
12 cfg = getAttrFromPath (optionsAttrPath ++ ["mdbook"]) config;
13
14 documentation-highlighter = pkgs.callPackage ./documentation-highlighter {};
15in {
16 options = setAttrByPath optionsAttrPath {
17 mdbook = {
18 src = mkOption {
19 type = with types; either path package;
20 description = ''
21 Root directory of mdbook sources to compile.
22 '';
23 internal = optionsInternal;
24 };
25
26 pages = mkOption {
27 type = with types;
28 attrsOf (submodule ({
29 name,
30 config,
31 ...
32 }: {
33 options = {
34 target = mkOption {
35 type = types.str;
36 default = name;
37 description = ''
38 Where to install the page, relative to the `src/` directory.
39 '';
40 internal = optionsInternal;
41 };
42
43 text = mkOption {
44 type = types.lines;
45 description = ''
46 Content of the page.
47 '';
48 internal = optionsInternal;
49 };
50
51 source = mkOption {
52 type = types.path;
53 description = ''
54 Path of the source file for this page.
55
56 If both `text` and `source` are defined, `source` takes
57 precedence.
58 '';
59 internal = optionsInternal;
60 };
61 };
62
63 config.source = mkDefault (pkgs.writeText name config.text);
64 }));
65 default = {};
66 example = {
67 "my-page.md".text = ''
68 # Title
69
70 hello, world!
71 '';
72 };
73 description = ''
74 Pages to add to the source directory before building.
75 '';
76 internal = optionsInternal;
77 };
78
79 preBuild = mkOption {
80 type = types.lines;
81 description = ''
82 Extra commands executed before running `mdbook build`.
83 '';
84 default = "";
85 internal = optionsInternal;
86 };
87
88 postBuild = mkOption {
89 type = types.lines;
90 description = ''
91 Extra commands executed after running `mdbook build`.
92 '';
93 default = "";
94 internal = optionsInternal;
95 };
96 };
97 };
98
99 config = mkMerge [
100 (setAttrByPath (optionsAttrPath ++ ["mdbook"]) {
101 pages."options.md".text = ''
102 # Available options
103
104 You can use the following options:
105
106
107 ${readFile (getAttrFromPath (outputAttrPath ++ ["doc-options-md"]) config)}
108 '';
109 })
110
111 (setAttrByPath outputAttrPath {
112 # TODO: make pandoc pre-processor
113 mdbook =
114 pkgs.runCommand "mdbook"
115 {
116 src = cfg.src;
117 nativeBuildInputs = with pkgs; [mdbook];
118 } ''
119 unpackFile "$src"
120 chmod -R u+w .
121 cd */
122
123 mkdir theme
124 cp ${documentation-highlighter}/highlight.min.js theme/highlight.js
125 cp ${documentation-highlighter}/mono-blue.min.css theme/highlight.css
126
127 ${concatMapStrings (page: ''
128 cp "${page.source}" "src/${page.target}"
129 '') (attrValues cfg.pages)}
130
131 ${cfg.preBuild}
132
133 mdbook build
134
135 ${cfg.postBuild}
136
137 cp -r book "$out"
138 '';
139 })
140 ];
141}