File: generate_command_docs.py

package info (click to toggle)
easyeffects 8.1.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 16,180 kB
  • sloc: cpp: 22,470; sh: 691; python: 448; javascript: 64; makefile: 8
file content (137 lines) | stat: -rwxr-xr-x 4,966 bytes parent folder | download
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
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python3
import os
import re
import xml.etree.ElementTree as ET

TAGS_FILE = "src/tags_plugin_name.hpp"
KCFG_DIR = "src/contents/kcfg"
OUTPUT_FILE = "src/contents/docs/database/plugins_properties.md"

def get_tags():
    ids = []
    if not os.path.exists(TAGS_FILE):
        print(f"Error: {TAGS_FILE} not found.")
        return ids

    regex = re.compile(r'CREATE_PROPERTY\s*\(\s*QString\s*,\s*\w+\s*,\s*QStringLiteral\s*\(\s*"([^"]+)"\s*\)\s*\)')
    with open(TAGS_FILE, 'r') as f:
        for line in f:
            if m := regex.search(line):
                ids.append(m.group(1))
    return sorted(ids)

def main():
    if not os.path.exists(KCFG_DIR):
        print(f"Error: Directory '{KCFG_DIR}' not found.")
        exit(1)

    tags = get_tags()

    lines = [
        "<!--",
        "  AUTOGENERATED FILE - DO NOT MODIFY MANUALLY.",
        "  This file is generated by: util/generate_command_docs.py",
        "-->",
        "",
        "# Plugin Properties",
        "",
        "The following properties can be modified or queried via the [local server](../user_interface/local_server.md).",
        "",
        "| Plugin ID | Property | Type | Default |",
        "| :--- | :--- | :--- | :--- |"
    ]

    found_plugins = 0

    for tag in tags:
        kcfg_path = os.path.join(KCFG_DIR, f"easyeffects_db_{tag}.kcfg")
        if not os.path.exists(kcfg_path):
            continue

        try:
            tree = ET.parse(kcfg_path)
            ns = {"kcfg": "http://www.kde.org/standards/kcfg/1.0"}

            esc = lambda s: str(s).replace("|", r"\|") if s else ""

            entries = {
                entry.get('name'): entry
                for group in tree.findall("kcfg:group", ns)
                for entry in group.findall("kcfg:entry", ns)
            }

            enum_defs = {}

            for name, entry in entries.items():
                # case for StringList labels used with Int properties
                if name.endswith("Labels") and entry.get('type') == 'StringList':
                    base = name[:-6] # strip 'Labels'
                    default_node = entry.find("kcfg:default", ns)
                    if default_node is not None and default_node.text:
                        enum_defs[base.lower()] = default_node.text.split(',')

                # case for Enum properties as is
                if entry.get('type') == "Enum":
                    choices_node = entry.find("kcfg:choices", ns)
                    if choices_node is not None:
                        labels = []
                        for c in choices_node.findall("kcfg:choice", ns):
                            lbl = c.find("kcfg:label", ns)
                            text = lbl.text if (lbl is not None and lbl.text) else c.get("name")
                            labels.append(text)
                        enum_defs[name.lower()] = labels


            hidden_props = {
                name for name in entries if name.lower()[:-6] in enum_defs and name.endswith("Labels")
            }

            for name, entry in entries.items():
                if name in hidden_props:
                    continue

                prop_type = entry.get('type')

                default_val = "-"
                default_node = entry.find("kcfg:default", ns)
                if default_node is not None:
                    if default_node.get("code") == "true":
                        default_val = "*calculated*"
                    elif default_node.text:
                        default_val = default_node.text

                choices = []
                if prop_type in ("Int", "Enum"):
                    if name.lower() in enum_defs:
                        choices = enum_defs[name.lower()]
                    else:
                        # suffix match among enums (longest wins) for banded props
                        # e.g. band1StereoSplitSource -> StereoSplitSource Enum
                        matches = [k for k in enum_defs if name.lower().endswith(k)]
                        if matches:
                            best_key = max(matches, key=len)
                            choices = enum_defs[best_key]

                def_col = f"`{esc(default_val)}`"

                if choices:
                    prop_type = "Enum"
                    fmt_choices = [f"{i}: `{c}`" for i, c in enumerate(choices)]
                    choices_str = ", ".join(fmt_choices)
                    def_col += f" <br><small>(Choices: {choices_str})</small>"

                lines.append(f"| **{esc(tag)}** | `{esc(name)}` | {esc(prop_type)} | {def_col} |")

            found_plugins += 1

        except Exception as e:
            print(f"Error parsing {kcfg_path}: {e}")

    with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
        f.write("\n".join(lines))
        f.write("\n")

    print(f"Documentation generated at: {OUTPUT_FILE} for {found_plugins} plugins.")

if __name__ == "__main__":
    main()