dream2nix/docs/hooks/render_options.py
DavHau 4e9fd61a12 reference-docs: fix option rendering issue
remove tree-style preprocessing since it is not needed anymore
2024-07-18 15:30:23 +00:00

109 lines
3.6 KiB
Python

import logging
import json
from pathlib import Path
from collections import OrderedDict
from typing import Dict, Tuple
from urllib.request import UnknownHandler
from mkdocs.structure.pages import Page
from mkdocs.structure.nav import Navigation, Section
from mkdocs.structure.files import Files
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.plugins import event_priority
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
log = logging.getLogger("mkdocs")
def is_reference_page(page: Page) -> bool:
return page.file.src_path.startswith("reference/")
def pygments(code: str, lang: str) -> str:
return highlight(code, get_lexer_by_name(lang), HtmlFormatter())
def sort_options(item: Tuple[str, Dict], module_name: str) -> int:
"""
Sort the modules. First the one the page is about,
then single options, then the rest, alphabetically
"""
name, option = item
if name == module_name:
return -1
elif len(option["children"]) == 0:
return 0
else:
return ord(name[0])
def on_page_markdown(
markdown: str, page: Page, config: MkDocsConfig, files: Files
) -> str | None:
"""Check whether the source path starts with "reference/".
If it does:
- render a header template, containing values from the source markdown file
- render the source markdown file
- render an options.json file containing nixos option definitions from the
same directory where the source file is found. Then render those options.
"""
if not is_reference_page(page):
return markdown
src_path = Path(config.docs_dir) / page.file.src_path
module_name = src_path.parent.stem
env = config.theme.get_env()
env.filters["pygments"] = pygments
header = env.get_template("reference_header.html").render(meta=page.meta)
options_path = src_path.parent / "options.json"
if not options_path.exists():
log.error(f"{options_path} does not exist")
return None
with open(options_path, "r") as f:
options = json.load(f)
del options["_module.args"]
reference = env.get_template("reference_options.html").render(options=options)
return "\n\n".join([header, markdown, reference])
@event_priority(-100)
def on_nav(nav: Navigation, config: MkDocsConfig, files: Files) -> Navigation | None:
"""Customize the navigation: If a reference section is found,
filter for a "state" variable defined in a markdown files front-matter.
Leave all items where "state" equals "released" as-is, but put
all others in an "experimental" section below that."""
try:
reference_section = next(filter(lambda i: i.title == "Reference", nav.items))
reference_index = nav.items.index(reference_section)
except StopIteration:
# Return the navigation as-is if we don't find
# a reference section
return nav
experimental = []
internal = []
released = []
for page in reference_section.children:
# to have metadata from the yaml front-matter available
page.read_source(config)
state = page.meta.get("state")
if state == "internal":
internal.append(page)
elif state == "released":
released.append(page)
else:
experimental.append(page)
experimental_section = Section("Experimental Modules", experimental)
internal_section = Section("Internal Modules", internal)
reference_section.children = released + [experimental_section, internal_section]
nav.items[reference_index] = reference_section
return nav