mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-05-19 21:38:07 -04:00
fix(scripts): improve nix options doc generator
- Restore missing description on hm enable option (fixes nix build warning)
- Rewrite format_default_value into format_value with example support and nix code blocks
- Fix Nix markup stripping: {tag}`content` now preserves backtick content
- Generalize ::: block handling beyond {.note} to any block type
- Switch output from Markdown table to labeled fields format
This commit is contained in:
parent
c3ec4c6142
commit
d5db98cfb7
3 changed files with 87 additions and 63 deletions
130
.github/scripts/generate-nix-options-docs.py
vendored
130
.github/scripts/generate-nix-options-docs.py
vendored
|
|
@ -1,80 +1,112 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Converts NixOS options JSON into clean, table-formatted Markdown.
|
Converts NixOS options JSON into clean Markdown documentation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import re
|
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:
|
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:
|
if not desc:
|
||||||
return "*No description provided.*"
|
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()
|
lines = desc.splitlines()
|
||||||
cleaned = []
|
cleaned = []
|
||||||
in_note = False
|
in_block = False
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.startswith("::: {.note"):
|
m = re.match(r':::\s*\{\.(\w+)\}', line)
|
||||||
in_note = True
|
if m:
|
||||||
cleaned.append("> **Note:**\n>")
|
block_type = m.group(1).capitalize()
|
||||||
|
in_block = True
|
||||||
|
cleaned.append(f"> **{block_type}:**\n>")
|
||||||
elif line.startswith(":::"):
|
elif line.startswith(":::"):
|
||||||
in_note = False
|
in_block = False
|
||||||
else:
|
else:
|
||||||
cleaned.append(f"> {line}" if in_note else line)
|
cleaned.append(f"> {line}" if in_block else line)
|
||||||
|
|
||||||
return "\n".join(cleaned)
|
return "\n".join(cleaned)
|
||||||
|
|
||||||
def format_default_value(default_data) -> str:
|
def format_value(val_data) -> str:
|
||||||
"""Safely formats the default value, handling HTML escaping for tables."""
|
"""Formats a value as inline code or a nix code block."""
|
||||||
if default_data is None:
|
if val_data is None:
|
||||||
return "*None*"
|
return None
|
||||||
|
|
||||||
val_text = default_data.get("text", "") if isinstance(default_data, dict) and default_data.get("_type") == "literalExpression" else str(default_data)
|
if isinstance(val_data, dict) and val_data.get("_type") == "literalMD":
|
||||||
val_text = val_text.replace('|', '|')
|
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:
|
if '\n' in text:
|
||||||
safe_html = val_text.replace('<', '<').replace('>', '>').replace('\n', '<br>')
|
return f"\n```nix\n{text}\n```"
|
||||||
return f"<code>{safe_html}</code>"
|
return f"`{text}`"
|
||||||
|
|
||||||
return f"`{val_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():
|
def main():
|
||||||
if len(sys.argv) != 4:
|
if len(sys.argv) != 4:
|
||||||
sys.exit("Usage: format_docs.py <input.json> <output.md> <title>")
|
sys.exit("Usage: generate-nix-options-docs.py <nixos.json> <hm.json> <output.md>")
|
||||||
|
|
||||||
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:
|
with open(output_md, 'w', encoding='utf-8') as out:
|
||||||
data = json.load(f)
|
out.write(HEADER)
|
||||||
|
for path, section in zip(inputs, SECTIONS):
|
||||||
with open(output_md, 'a', encoding='utf-8') as out:
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
out.write(f"## {title}\n\n")
|
data = json.load(f)
|
||||||
|
write_section(out, data, section["title"], section["subtitle"])
|
||||||
for key, opt in sorted(data.items()):
|
print(f"Written {section['title']} section.")
|
||||||
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.")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
19
.github/workflows/generate-nix-options-docs.yml
vendored
19
.github/workflows/generate-nix-options-docs.yml
vendored
|
|
@ -6,6 +6,7 @@ on:
|
||||||
- 'nix/**-modules.nix'
|
- 'nix/**-modules.nix'
|
||||||
- 'nix/generate-options.nix'
|
- 'nix/generate-options.nix'
|
||||||
- 'flake.nix'
|
- 'flake.nix'
|
||||||
|
- '.github/scripts/generate-nix-options-docs.py'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'nix/**-modules.nix'
|
- 'nix/**-modules.nix'
|
||||||
|
|
@ -35,20 +36,10 @@ jobs:
|
||||||
|
|
||||||
- name: Format to Markdown
|
- name: Format to Markdown
|
||||||
run: |
|
run: |
|
||||||
OUTPUT_FILE="docs/nix-options.md"
|
python3 ./.github/scripts/generate-nix-options-docs.py \
|
||||||
|
result-nixos/share/doc/nixos/options.json \
|
||||||
cat << 'EOF' > $OUTPUT_FILE
|
result-hm/share/doc/nixos/options.json \
|
||||||
---
|
docs/nix-options.md
|
||||||
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"
|
|
||||||
|
|
||||||
- name: Auto-commit changes
|
- name: Auto-commit changes
|
||||||
uses: stefanzweifel/git-auto-commit-action@v5
|
uses: stefanzweifel/git-auto-commit-action@v5
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ in
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
description = "Whether to enable mangowm, a Wayland compositor based on dwl.";
|
||||||
};
|
};
|
||||||
package = lib.mkOption {
|
package = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue