From 69e9c80ec3e1af38a8a88b44737a138b39c45d21 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Tue, 15 Feb 2022 05:19:13 +1100 Subject: [PATCH] Reworked docs rendering using jinja2. --- data/templates/xap/docs/docs.md.j2 | 7 ++ data/templates/xap/docs/response_flags.md.j2 | 9 +++ .../templates/xap/docs/term_definitions.md.j2 | 5 ++ data/templates/xap/docs/type_docs.md.j2 | 5 ++ data/xap/xap_0.0.1.hjson | 6 +- docs/xap_0.0.1.md | 7 +- docs/xap_0.1.0.md | 13 +-- docs/xap_0.2.0.md | 13 +-- lib/python/qmk/cli/__init__.py | 3 +- lib/python/qmk/xap/common.py | 15 +++- lib/python/qmk/xap/gen_docs/generator.py | 80 ++----------------- requirements.txt | 1 + 12 files changed, 70 insertions(+), 94 deletions(-) create mode 100644 data/templates/xap/docs/docs.md.j2 create mode 100644 data/templates/xap/docs/response_flags.md.j2 create mode 100644 data/templates/xap/docs/term_definitions.md.j2 create mode 100644 data/templates/xap/docs/type_docs.md.j2 diff --git a/data/templates/xap/docs/docs.md.j2 b/data/templates/xap/docs/docs.md.j2 new file mode 100644 index 0000000000..7d6225ff7b --- /dev/null +++ b/data/templates/xap/docs/docs.md.j2 @@ -0,0 +1,7 @@ +{%- for item in xap.documentation.order -%} +{%- if not item[0:1] == '!' -%} +{{ xap.documentation.get(item) }} +{% else %} +{%- include item[1:] %} +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/data/templates/xap/docs/response_flags.md.j2 b/data/templates/xap/docs/response_flags.md.j2 new file mode 100644 index 0000000000..852db16fd9 --- /dev/null +++ b/data/templates/xap/docs/response_flags.md.j2 @@ -0,0 +1,9 @@ +|{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %} Bit {{ bitnum }} |{% endfor %} +|{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %} -- |{% endfor %} +|{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %} `{{ bitinfo.define }}` |{%- endfor %} + +{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %} +{%- if bitinfo.define != "-" -%} +* Bit {{ bitnum }} (`{{ bitinfo.define }}`): {{ bitinfo.description }} +{% endif %} +{%- endfor %} \ No newline at end of file diff --git a/data/templates/xap/docs/term_definitions.md.j2 b/data/templates/xap/docs/term_definitions.md.j2 new file mode 100644 index 0000000000..8afdb9c3e2 --- /dev/null +++ b/data/templates/xap/docs/term_definitions.md.j2 @@ -0,0 +1,5 @@ +| Name | Definition | +| -- | -- | +{%- for type, definition in xap.term_definitions | dictsort %} +| _{{ type }}_ | {{ definition }} | +{%- endfor %} \ No newline at end of file diff --git a/data/templates/xap/docs/type_docs.md.j2 b/data/templates/xap/docs/type_docs.md.j2 new file mode 100644 index 0000000000..787d942853 --- /dev/null +++ b/data/templates/xap/docs/type_docs.md.j2 @@ -0,0 +1,5 @@ +| Name | Definition | +| -- | -- | +{%- for type, definition in xap.type_docs | dictsort %} +| _{{ type }}_ | {{ definition }} | +{%- endfor %} \ No newline at end of file diff --git a/data/xap/xap_0.0.1.hjson b/data/xap/xap_0.0.1.hjson index 34fd21d623..9b19526244 100755 --- a/data/xap/xap_0.0.1.hjson +++ b/data/xap/xap_0.0.1.hjson @@ -9,13 +9,13 @@ order: [ page_header type_docs - !type_docs! + !type_docs.md.j2 term_definitions - !term_definitions! + !term_definitions.md.j2 request_response reserved_tokens response_flags - !response_flags! + !response_flags.md.j2 example_conversation ] diff --git a/docs/xap_0.0.1.md b/docs/xap_0.0.1.md index ff45f1ae45..336176c33c 100644 --- a/docs/xap_0.0.1.md +++ b/docs/xap_0.0.1.md @@ -41,10 +41,11 @@ This token is followed by a `u8` signifying the length of data in the request. Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length: | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | -|--|--|--|--|--|--|--|--| -| - | - | - | - | - | - | - | Success | +| -- | -- | -- | -- | -- | -- | -- | -- | +| `-` | `-` | `-` | `-` | `-` | `-` | `-` | `SUCCESS` | + +* Bit 0 (`SUCCESS`): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token). -* `Bit 0`: When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token). ### Example "conversation": diff --git a/docs/xap_0.1.0.md b/docs/xap_0.1.0.md index 8d53f276bf..f3911d7220 100644 --- a/docs/xap_0.1.0.md +++ b/docs/xap_0.1.0.md @@ -50,13 +50,14 @@ Any request will generate at least one corresponding response, with the exceptio Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length: | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | -|--|--|--|--|--|--|--|--| -| Unlocked | Unlocking | - | - | - | - | Secure Failure | Success | +| -- | -- | -- | -- | -- | -- | -- | -- | +| `UNLOCKED` | `UNLOCK_IN_PROGRESS` | `-` | `-` | `-` | `-` | `SECURE_FAILURE` | `SUCCESS` | + +* Bit 7 (`UNLOCKED`): When this bit is set, an _unlock sequence_ has completed, and _secure routes_ may be invoked. +* Bit 6 (`UNLOCK_IN_PROGRESS`): When this bit is set, an _unlock sequence_ is in progress. +* Bit 1 (`SECURE_FAILURE`): When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed. +* Bit 0 (`SUCCESS`): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token). -* `Bit 7`: When this bit is set, an _unlock sequence_ has completed, and _secure routes_ may be invoked. -* `Bit 6`: When this bit is set, an _unlock sequence_ is in progress. -* `Bit 1`: When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed. -* `Bit 0`: When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token). ### Example "conversation": diff --git a/docs/xap_0.2.0.md b/docs/xap_0.2.0.md index 8d53f276bf..f3911d7220 100644 --- a/docs/xap_0.2.0.md +++ b/docs/xap_0.2.0.md @@ -50,13 +50,14 @@ Any request will generate at least one corresponding response, with the exceptio Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length: | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | -|--|--|--|--|--|--|--|--| -| Unlocked | Unlocking | - | - | - | - | Secure Failure | Success | +| -- | -- | -- | -- | -- | -- | -- | -- | +| `UNLOCKED` | `UNLOCK_IN_PROGRESS` | `-` | `-` | `-` | `-` | `SECURE_FAILURE` | `SUCCESS` | + +* Bit 7 (`UNLOCKED`): When this bit is set, an _unlock sequence_ has completed, and _secure routes_ may be invoked. +* Bit 6 (`UNLOCK_IN_PROGRESS`): When this bit is set, an _unlock sequence_ is in progress. +* Bit 1 (`SECURE_FAILURE`): When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed. +* Bit 0 (`SUCCESS`): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token). -* `Bit 7`: When this bit is set, an _unlock sequence_ has completed, and _secure routes_ may be invoked. -* `Bit 6`: When this bit is set, an _unlock sequence_ is in progress. -* `Bit 1`: When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed. -* `Bit 0`: When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token). ### Example "conversation": diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py index 5bc809d503..3197d9d7f2 100644 --- a/lib/python/qmk/cli/__init__.py +++ b/lib/python/qmk/cli/__init__.py @@ -16,7 +16,8 @@ import_names = { # A mapping of package name to importable name 'pep8-naming': 'pep8ext_naming', 'pyusb': 'usb.core', - 'qmk-dotty-dict': 'dotty_dict' + 'qmk-dotty-dict': 'dotty_dict', + 'Jinja2': 'jinja2' } safe_commands = [ diff --git a/lib/python/qmk/xap/common.py b/lib/python/qmk/xap/common.py index bec82d727b..d1e0d5dbb0 100755 --- a/lib/python/qmk/xap/common.py +++ b/lib/python/qmk/xap/common.py @@ -1,10 +1,21 @@ """This script handles the XAP protocol data files. """ -import re +import os import hjson +from jinja2 import Environment, FileSystemLoader, select_autoescape +from qmk.constants import QMK_FIRMWARE from typing import OrderedDict -from qmk.constants import QMK_FIRMWARE + +def _get_jinja2_env(data_templates_xap_subdir: str): + templates_dir = os.path.join(QMK_FIRMWARE, 'data', 'templates', 'xap', data_templates_xap_subdir) + j2 = Environment(loader=FileSystemLoader(templates_dir), autoescape=select_autoescape()) + return j2 + + +def render_xap_output(data_templates_xap_subdir, file_to_render, defs): + j2 = _get_jinja2_env(data_templates_xap_subdir) + return j2.get_template(file_to_render).render(xap=defs, xap_str=hjson.dumps(defs)) def _merge_ordered_dicts(dicts): diff --git a/lib/python/qmk/xap/gen_docs/generator.py b/lib/python/qmk/xap/gen_docs/generator.py index 3e0ce52896..bcb90351e9 100755 --- a/lib/python/qmk/xap/gen_docs/generator.py +++ b/lib/python/qmk/xap/gen_docs/generator.py @@ -2,64 +2,7 @@ """ import hjson from qmk.constants import QMK_FIRMWARE -from qmk.xap.common import get_xap_definition_files, update_xap_definitions - - -def _update_type_docs(overall): - defs = overall['type_docs'] - - type_docs = [] - for (k, v) in sorted(defs.items(), key=lambda x: x[0]): - type_docs.append(f'| _{k}_ | {v} |') - - desc_str = "\n".join(type_docs) - - overall['documentation']['!type_docs!'] = f'''\ -| Name | Definition | -| -- | -- | -{desc_str} -''' - - -def _update_term_definitions(overall): - defs = overall['term_definitions'] - - term_descriptions = [] - for (k, v) in sorted(defs.items(), key=lambda x: x[0]): - term_descriptions.append(f'| _{k}_ | {v} |') - - desc_str = "\n".join(term_descriptions) - - overall['documentation']['!term_definitions!'] = f'''\ -| Name | Definition | -| -- | -- | -{desc_str} -''' - - -def _update_response_flags(overall): - flags = overall['response_flags']['bits'] - for n in range(0, 8): - if str(n) not in flags: - flags[str(n)] = {"name": "-", "description": "-"} - - header = '| ' + " | ".join([f'Bit {n}' for n in range(7, -1, -1)]) + ' |' - dividers = '|' + "|".join(['--' for n in range(7, -1, -1)]) + '|' - bit_names = '| ' + " | ".join([flags[str(n)]['name'] for n in range(7, -1, -1)]) + ' |' - - bit_descriptions = '' - for n in range(7, -1, -1): - bit_desc = flags[str(n)] - if bit_desc['name'] != '-': - desc = bit_desc['description'] - bit_descriptions = bit_descriptions + f'\n* `Bit {n}`: {desc}' - - overall['documentation']['!response_flags!'] = f'''\ -{header} -{dividers} -{bit_names} -{bit_descriptions} -''' +from qmk.xap.common import get_xap_definition_files, update_xap_definitions, render_xap_output def generate_docs(): @@ -69,27 +12,18 @@ def generate_docs(): overall = None for file in get_xap_definition_files(): - overall = update_xap_definitions(overall, hjson.load(file.open(encoding='utf-8'))) - try: - if 'type_docs' in overall: - _update_type_docs(overall) - if 'term_definitions' in overall: - _update_term_definitions(overall) - if 'response_flags' in overall: - _update_response_flags(overall) - except: - print(hjson.dumps(overall)) - exit(1) + # Inject dummy bits for unspecified response flags + for n in range(0, 8): + if str(n) not in overall['response_flags']['bits']: + overall['response_flags']['bits'][str(n)] = {'name': '', 'description': '', 'define': '-'} output_doc = QMK_FIRMWARE / "docs" / f"{file.stem}.md" docs_list.append(output_doc) - + output = render_xap_output('docs', 'docs.md.j2', overall) with open(output_doc, "w", encoding='utf-8') as out_file: - for e in overall['documentation']['order']: - out_file.write(overall['documentation'][e].strip()) - out_file.write('\n\n') + out_file.write(output) output_doc = QMK_FIRMWARE / "docs" / f"xap_protocol.md" with open(output_doc, "w", encoding='utf-8') as out_file: diff --git a/requirements.txt b/requirements.txt index 6357b4e2eb..7cf2c0b128 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ colorama fnvhash hid hjson +Jinja2 jsonschema>=3 milc>=1.4.2 pygments