aboutsummaryrefslogtreecommitdiff
path: root/scripts/mandoc_gen.py
blob: 66dedd1f0b74f5c5aee4ed2402705a4b812f0dfc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/bin/env python3

# This script converts API YAML files into markdown documentation
# and prints it to standard out.

from datetime import datetime
import re
import yaml

def escape(text, spaces=False):
    """
    Escapes text for safe inclusion in groff documents.
    - Escapes backslashes as '\\e'
    - Escapes periods at the start of a line as '\\&.'
    """
    escaped_lines = []
    for line in text.splitlines():
        # Escape backslashes
        line = line.replace("\\", r"\[rs]")
        # Escape leading period or apostrophe (groff macro triggers)
        if line.startswith('.'):
            line = r'\&' + line
        elif line.startswith("'"):
            line = r'\&' + line
        if spaces:
            line = line.replace(' ', '\\ ')
        escaped_lines.append(line)
    return '\n'.join(escaped_lines)

def arg_signature(name, arg):
    sig = name
    if "type" in arg:
        sig = sig + ": " + arg["type"]
    if "default" in arg:
        sig = sig + " = " + arg["default"]
    return sig

def get_signature(name, info):
    if "type" in info:
        return ".BI " +escape(f'{name} : {info["type"]}', spaces=True)
    sig = f'{name} : func('
    if info["args"]:
        sig += ", ".join(arg_signature(name,arg) for name,arg in info["args"].items())
        sig += " -> " + info["return"].get("type", "Void")
    else:
        sig += "-> " + info["return"].get("type", "Void")
    sig += ')'
    return ".BI " + escape(sig, spaces=True)

template = ''''\\" t
.\\" Copyright (c) {year} Bruce Hill
.\\" All rights reserved.
.\\"
.TH {name} 3 {date} "Tomo man-pages"
.SH NAME
{name} \\- {short}
.SH LIBRARY
Tomo Standard Library
.SH SYNOPSIS
.nf
{signature}
.fi
.SH DESCRIPTION
{description}
'''

arg_prefix = '''
.TS
allbox;
lb lb lbx lb
l l l l.
Name	Type	Description	Default'''

def write_method(f, name, info):
    def add_line(line): f.write(line + "\n")
    year = datetime.now().strftime("%Y")
    date = datetime.now().strftime("%Y-%m-%d")
    signature = get_signature(name, info)
    add_line(template.format(year=year, date=date, name=name, short=info["short"], description=info["description"], signature=signature))

    if "args" in info and info["args"]:
        add_line(".SH ARGUMENTS")
        add_line(arg_prefix)
        for arg,arg_info in info["args"].items():
            default = escape(arg_info['default'], spaces=True) if 'default' in arg_info else '-'
            description = arg_info['description'].replace('\n', ' ')
            add_line(f"{arg}\t{arg_info.get('type', '')}\t{description}\t{default}")
        add_line(".TE")

    if "return" in info:
        add_line(".SH RETURN")
        add_line(info['return'].get('description', 'Nothing.'))

    if "note" in info:
        add_line(".SH NOTES")
        add_line(info["note"])

    if "errors" in info:
        add_line(".SH ERRORS")
        add_line(info["errors"])

    if "example" in info:
        add_line(".SH EXAMPLES")
        add_line(".EX")
        add_line(escape(info['example']))
        add_line(".EE")

def convert_to_markdown(yaml_doc:str)->str:
    data = yaml.safe_load(yaml_doc)

    for name,info in data.items():
        with open(f"man/man3/tomo-{name}.3", "w") as f:
            print(f"Wrote to man/man3/tomo-{name}.3")
            write_method(f, name, data[name])

if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        all_files = ""
        for filename in sys.argv[1:]:
            with open(filename, "r") as f:
                all_files += f.read()
        convert_to_markdown(all_files)
    else:
        convert_to_markdown(sys.stdin.read())