174 lines
4.6 KiB
Nix
174 lines
4.6 KiB
Nix
let
|
|
elems = import ./elems.nix;
|
|
in rec {
|
|
readMd = md:
|
|
if builtins.isPath md then
|
|
processMd (builtins.readFile md)
|
|
else
|
|
processMd md;
|
|
|
|
processMd = processStr;
|
|
|
|
recReadMd = root:
|
|
assert builtins.isPath root;
|
|
builtins.mapAttrs (path: type:
|
|
if type == "directory" then
|
|
recReadMd (root + (/. + path))
|
|
else if type == "regular" then
|
|
mdToPage (root + (/. + path))
|
|
else
|
|
throw "Cannot read ${path}, file type ${type}") (builtins.readDir root);
|
|
|
|
recFixAppendix = site:
|
|
builtins.listToAttrs (builtins.attrValues (builtins.mapAttrs (name: value: {
|
|
name = fixAppendix name;
|
|
value = if builtins.isAttrs value then recFixAppendix value else value;
|
|
}) site));
|
|
|
|
fixAppendix = builtins.replaceStrings [ ".md" ] [ ".html" ];
|
|
|
|
readDir = root: recFixAppendix (recReadMd root);
|
|
|
|
mdToPage = md:
|
|
elems.Doc { } [ [ (elems.title { } "markdown file") ] (readMd md) ];
|
|
|
|
code = block:
|
|
matchThen "(```)(.*)(```)" block (m: elems.code (builtins.elemAt m 1));
|
|
|
|
list = block:
|
|
matchThen (''
|
|
(- .+
|
|
)*(- .+
|
|
?)'') block (m: elems.List (splitList block));
|
|
|
|
splitList = block:
|
|
map (listItem) (builtins.filter (s: builtins.isString s && s != "")
|
|
(builtins.split "\n" block));
|
|
|
|
listItem = str:
|
|
let
|
|
li = builtins.match "- (.*)" str;
|
|
checkbox = builtins.match "- \\[(.)] (.*)" str;
|
|
checked = builtins.elemAt checkbox 0;
|
|
content = builtins.elemAt checkbox 1;
|
|
in if checkbox == null then
|
|
li
|
|
else [
|
|
(elems.input {
|
|
type = "checkbox";
|
|
checked = checked != " ";
|
|
disabled = true;
|
|
})
|
|
content
|
|
];
|
|
|
|
replace = regex: apply: block:
|
|
(let
|
|
m = builtins.match regex block;
|
|
before = let v = builtins.elemAt m 0; in if v == null then "" else v;
|
|
after = toString( builtins.elemAt m (matchCount - 1));
|
|
matchCount = builtins.length m;
|
|
in if m == null then
|
|
block
|
|
else
|
|
(replace regex apply before) + (apply m) + after);
|
|
|
|
rule = matcher: apply: blocks:
|
|
map (b: if builtins.isString b then replace matcher apply b else b) blocks;
|
|
|
|
applyRules = i: rules: input:
|
|
let
|
|
group = if builtins.isString input then [ input ] else input;
|
|
len = builtins.length rules;
|
|
rule = builtins.elemAt rules i;
|
|
next = i + 1;
|
|
in assert i < len;
|
|
if next < len then rule (applyRules next rules group) else rule group;
|
|
|
|
basicRule = matcher: elem: rule matcher (m: elem (builtins.elemAt m 1));
|
|
|
|
processStr = applyRules 0 [
|
|
(basicRule (wrap "\\^") elems.sup)
|
|
(basicRule (wrap "~") elems.sub)
|
|
(basicRule (wrap "\\*") elems.em)
|
|
(basicRule (wrapBreak "_") elems.em)
|
|
(basicRule (wrap "`") elems.code)
|
|
(basicRule (wrap "==") elems.mark)
|
|
(basicRule (wrap "~~") elems.del)
|
|
(basicRule (wrap "\\*\\*") elems.strong)
|
|
(basicRule (wrapBreak "__") elems.strong)
|
|
(rule (contains "\\[(.*)]\\((.*)\\)") (
|
|
m:
|
|
let
|
|
href = builtins.elemAt m 2;
|
|
text = builtins.elemAt m 1;
|
|
in
|
|
(elems.a href text)
|
|
))
|
|
(rule (''
|
|
(.*
|
|
)([^-][^
|
|
]+
|
|
)((- [^
|
|
]+
|
|
)+)(.*)'') (
|
|
|
|
l:
|
|
(elems.ul (basicRule (''
|
|
(.*
|
|
)?- ([^
|
|
]+)
|
|
(.*)'') (m:
|
|
elems.li (basicRule ("()\\[(.)](.*)") (check:
|
|
elems.input {
|
|
type = "checkbox";
|
|
checked = check != " ";
|
|
disabled = true;
|
|
}) [ m ])) [ (builtins.elemAt l 2) ]))
|
|
|
|
))
|
|
(basicRule ( "(.*\n\n)?(.+)\n(.*)?" ) elems.p)
|
|
(basicRule ("(.*\n\n)?```(.*)```(.*)?") (elems.textarea { readonly = true; }))
|
|
(basicRule (containsBreak ''
|
|
###### ([^
|
|
]+)'') (elems.h6))
|
|
(basicRule (containsBreak ''
|
|
##### ([^
|
|
]+)'') (elems.h5))
|
|
(basicRule (containsBreak ''
|
|
#### ([^
|
|
]+)'') (elems.h4))
|
|
(basicRule (containsBreak ''
|
|
### ([^
|
|
]+)'') (elems.h3))
|
|
(basicRule (containsBreak ''
|
|
## ([^
|
|
]+)'') (elems.h2))
|
|
(basicRule (containsBreak ''
|
|
# ([^
|
|
]+)'') (elems.h1))
|
|
(basicRule (containsBreak "<(${linkmatcher})>") (m: elems.a m m))
|
|
];
|
|
|
|
linkmatcher = "[-[:alnum:].%?&#=:/]+";
|
|
contains = matcher: "(.*)?${matcher}(.*)";
|
|
wrap = matcher: contains "${matcher}([^${matcher}]+)${matcher}";
|
|
|
|
containsBreak = matcher: "(.*[[:space:]])?${matcher}(.*)";
|
|
wrapBreak = matcher: containsBreak "${matcher}([^${matcher}]+)${matcher}";
|
|
|
|
matchThen = matcher: block: func:
|
|
let m = builtins.match matcher block;
|
|
in if m == null then
|
|
dontMatch block
|
|
else {
|
|
matched = true;
|
|
block = func m;
|
|
};
|
|
|
|
dontMatch = block: {
|
|
matched = false;
|
|
inherit block;
|
|
};
|
|
|
|
}
|