diff --git a/.github/scripts/generate-nix-options-docs.py b/.github/scripts/generate-nix-options-docs.py
index 23cd3b90..6f5d35bd 100755
--- a/.github/scripts/generate-nix-options-docs.py
+++ b/.github/scripts/generate-nix-options-docs.py
@@ -1,80 +1,112 @@
#!/usr/bin/env python3
"""
-Converts NixOS options JSON into clean, table-formatted Markdown.
+Converts NixOS options JSON into clean Markdown documentation.
"""
import json
import sys
import re
+SECTIONS = [
+ {
+ "title": "NixOS",
+ "subtitle": "**System-level options via `programs.mango`.**",
+ },
+ {
+ "title": "Home Manager",
+ "subtitle": "**Configure mangowm declaratively via `wayland.windowManager.mango`.**",
+ },
+]
+
+HEADER = (
+ "---\n"
+ "title: Nix Module Options\n"
+ "description: NixOS and Home Manager configuration options for mangowm.\n"
+ "---\n\n"
+ "> **Note:** This document is automatically generated from the Nix module source code.\n\n"
+)
+
def clean_description(desc: str) -> str:
- """Removes Nix tags, fixes dangling periods, and formats blockquotes."""
+ """Strips Nix inline markup tags, fixes dangling periods, and formats blockquotes."""
if not desc:
return "*No description provided.*"
- desc = re.sub(r'\{[a-zA-Z]+\}', '', desc).replace('\n.', '.')
+ # Strip Nix inline markup: {tag}`content` → `content`; bare tags → ""
+ desc = re.sub(r'\{(?:var|option|manpage|file|env|command|program)\}(`[^`]+`)', r'\1', desc)
+ desc = re.sub(r'\{(?:var|option|manpage|file|env|command|program)\}', '', desc)
+ # Remove period left on its own line after tag removal
+ desc = re.sub(r'\n\s*\.(\s|$)', r'.\1', desc)
lines = desc.splitlines()
cleaned = []
- in_note = False
-
+ in_block = False
+
for line in lines:
- if line.startswith("::: {.note"):
- in_note = True
- cleaned.append("> **Note:**\n>")
+ m = re.match(r':::\s*\{\.(\w+)\}', line)
+ if m:
+ block_type = m.group(1).capitalize()
+ in_block = True
+ cleaned.append(f"> **{block_type}:**\n>")
elif line.startswith(":::"):
- in_note = False
+ in_block = False
else:
- cleaned.append(f"> {line}" if in_note else line)
+ cleaned.append(f"> {line}" if in_block else line)
return "\n".join(cleaned)
-def format_default_value(default_data) -> str:
- """Safely formats the default value, handling HTML escaping for tables."""
- if default_data is None:
- return "*None*"
+def format_value(val_data) -> str:
+ """Formats a value as inline code or a nix code block."""
+ if val_data is None:
+ return None
- val_text = default_data.get("text", "") if isinstance(default_data, dict) and default_data.get("_type") == "literalExpression" else str(default_data)
- val_text = val_text.replace('|', '|')
+ if isinstance(val_data, dict) and val_data.get("_type") == "literalMD":
+ return val_data.get("text", "").strip()
+ elif isinstance(val_data, dict) and val_data.get("_type") == "literalExpression":
+ text = val_data.get("text", "").strip()
+ elif isinstance(val_data, bool):
+ text = "true" if val_data else "false"
+ elif val_data == {} or val_data == []:
+ text = "{ }" if val_data == {} else "[ ]"
+ else:
+ text = str(val_data).strip()
- if '\n' in val_text:
- safe_html = val_text.replace('<', '<').replace('>', '>').replace('\n', '
')
- return f"{safe_html}"
-
- return f"`{val_text}`"
+ if '\n' in text:
+ return f"\n```nix\n{text}\n```"
+ return f"`{text}`"
+
+def write_section(out, data, title, subtitle):
+ out.write(f"## {title}\n\n{subtitle}\n\n")
+ for key, opt in sorted(data.items()):
+ if key.startswith("_module"):
+ continue
+
+ desc = clean_description(opt.get("description", ""))
+ opt_type = str(opt.get("type", "unknown"))
+ default_val = format_value(opt.get("default"))
+ example_val = format_value(opt.get("example"))
+
+ block = f"### `{key}`\n\n{desc}\n\n**Type:** `{opt_type}`\n\n"
+ if default_val is not None:
+ block += f"**Default:** {default_val}\n\n"
+ if example_val is not None:
+ block += f"**Example:** {example_val}\n\n"
+ block += "---\n\n"
+ out.write(block)
def main():
if len(sys.argv) != 4:
- sys.exit("Usage: format_docs.py ")
+ sys.exit("Usage: generate-nix-options-docs.py ")
- input_json, output_md, title = sys.argv[1:4]
+ nixos_json, hm_json, output_md = sys.argv[1:4]
+ inputs = [nixos_json, hm_json]
- with open(input_json, 'r', encoding='utf-8') as f:
- data = json.load(f)
-
- with open(output_md, 'a', encoding='utf-8') as out:
- out.write(f"## {title}\n\n")
-
- for key, opt in sorted(data.items()):
- if key.startswith("_module"):
- continue
-
- desc = clean_description(opt.get("description", ""))
- opt_type = str(opt.get("type", "unknown")).replace('|', '|')
- default_val = format_default_value(opt.get("default"))
-
- markdown_block = (
- f"### `{key}`\n\n"
- f"{desc}\n\n"
- f"| Attribute | Value |\n"
- f"| :--- | :--- |\n"
- f"| **Type** | `{opt_type}` |\n"
- f"| **Default** | {default_val} |\n\n"
- f"---\n\n"
- )
- out.write(markdown_block)
-
- print(f"Appended {title} to {output_md} successfully.")
+ with open(output_md, 'w', encoding='utf-8') as out:
+ out.write(HEADER)
+ for path, section in zip(inputs, SECTIONS):
+ with open(path, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+ write_section(out, data, section["title"], section["subtitle"])
+ print(f"Written {section['title']} section.")
if __name__ == "__main__":
main()
diff --git a/.github/workflows/generate-nix-options-docs.yml b/.github/workflows/generate-nix-options-docs.yml
index e5fd0df2..465146be 100644
--- a/.github/workflows/generate-nix-options-docs.yml
+++ b/.github/workflows/generate-nix-options-docs.yml
@@ -6,6 +6,7 @@ on:
- 'nix/**-modules.nix'
- 'nix/generate-options.nix'
- 'flake.nix'
+ - '.github/scripts/generate-nix-options-docs.py'
pull_request:
paths:
- 'nix/**-modules.nix'
@@ -35,20 +36,10 @@ jobs:
- name: Format to Markdown
run: |
- OUTPUT_FILE="docs/nix-options.md"
-
- cat << 'EOF' > $OUTPUT_FILE
- ---
- title: Nix Module Options
- description: NixOS and Home Manager configuration options for mangowm.
- ---
-
- > **Note:** This document is automatically generated from the Nix module source code.
-
- EOF
-
- python3 ./.github/scripts/generate-nix-options-docs.py result-nixos/share/doc/nixos/options.json $OUTPUT_FILE "NixOS Module Options"
- python3 ./.github/scripts/generate-nix-options-docs.py result-hm/share/doc/nixos/options.json $OUTPUT_FILE "Home Manager Options"
+ python3 ./.github/scripts/generate-nix-options-docs.py \
+ result-nixos/share/doc/nixos/options.json \
+ result-hm/share/doc/nixos/options.json \
+ docs/nix-options.md
- name: Auto-commit changes
uses: stefanzweifel/git-auto-commit-action@v5
diff --git a/nix/hm-modules.nix b/nix/hm-modules.nix
index f00d9c68..f9a341a3 100644
--- a/nix/hm-modules.nix
+++ b/nix/hm-modules.nix
@@ -22,6 +22,7 @@ in
enable = mkOption {
type = types.bool;
default = false;
+ description = "Whether to enable mangowm, a Wayland compositor based on dwl.";
};
package = lib.mkOption {
type = lib.types.package;