Reworked docs rendering using jinja2.

This commit is contained in:
Nick Brassel 2022-02-15 05:19:13 +11:00
parent 1e723e6647
commit 69e9c80ec3
12 changed files with 70 additions and 94 deletions

View File

@ -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 %}

View File

@ -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 %}

View File

@ -0,0 +1,5 @@
| Name | Definition |
| -- | -- |
{%- for type, definition in xap.term_definitions | dictsort %}
| _{{ type }}_ | {{ definition }} |
{%- endfor %}

View File

@ -0,0 +1,5 @@
| Name | Definition |
| -- | -- |
{%- for type, definition in xap.type_docs | dictsort %}
| _{{ type }}_ | {{ definition }} |
{%- endfor %}

View File

@ -9,13 +9,13 @@
order: [ order: [
page_header page_header
type_docs type_docs
!type_docs! !type_docs.md.j2
term_definitions term_definitions
!term_definitions! !term_definitions.md.j2
request_response request_response
reserved_tokens reserved_tokens
response_flags response_flags
!response_flags! !response_flags.md.j2
example_conversation example_conversation
] ]

View File

@ -42,9 +42,10 @@ Response messages will always be prefixed by the originating request _token_, di
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | | 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": ### Example "conversation":

View File

@ -51,12 +51,13 @@ Response messages will always be prefixed by the originating request _token_, di
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | | 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": ### Example "conversation":

View File

@ -51,12 +51,13 @@ Response messages will always be prefixed by the originating request _token_, di
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | | 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": ### Example "conversation":

View File

@ -16,7 +16,8 @@ import_names = {
# A mapping of package name to importable name # A mapping of package name to importable name
'pep8-naming': 'pep8ext_naming', 'pep8-naming': 'pep8ext_naming',
'pyusb': 'usb.core', 'pyusb': 'usb.core',
'qmk-dotty-dict': 'dotty_dict' 'qmk-dotty-dict': 'dotty_dict',
'Jinja2': 'jinja2'
} }
safe_commands = [ safe_commands = [

View File

@ -1,10 +1,21 @@
"""This script handles the XAP protocol data files. """This script handles the XAP protocol data files.
""" """
import re import os
import hjson import hjson
from jinja2 import Environment, FileSystemLoader, select_autoescape
from qmk.constants import QMK_FIRMWARE
from typing import OrderedDict 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): def _merge_ordered_dicts(dicts):

View File

@ -2,64 +2,7 @@
""" """
import hjson import hjson
from qmk.constants import QMK_FIRMWARE from qmk.constants import QMK_FIRMWARE
from qmk.xap.common import get_xap_definition_files, update_xap_definitions from qmk.xap.common import get_xap_definition_files, update_xap_definitions, render_xap_output
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}
'''
def generate_docs(): def generate_docs():
@ -69,27 +12,18 @@ def generate_docs():
overall = None overall = None
for file in get_xap_definition_files(): for file in get_xap_definition_files():
overall = update_xap_definitions(overall, hjson.load(file.open(encoding='utf-8'))) overall = update_xap_definitions(overall, hjson.load(file.open(encoding='utf-8')))
try: # Inject dummy bits for unspecified response flags
if 'type_docs' in overall: for n in range(0, 8):
_update_type_docs(overall) if str(n) not in overall['response_flags']['bits']:
if 'term_definitions' in overall: overall['response_flags']['bits'][str(n)] = {'name': '', 'description': '', 'define': '-'}
_update_term_definitions(overall)
if 'response_flags' in overall:
_update_response_flags(overall)
except:
print(hjson.dumps(overall))
exit(1)
output_doc = QMK_FIRMWARE / "docs" / f"{file.stem}.md" output_doc = QMK_FIRMWARE / "docs" / f"{file.stem}.md"
docs_list.append(output_doc) 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: with open(output_doc, "w", encoding='utf-8') as out_file:
for e in overall['documentation']['order']: out_file.write(output)
out_file.write(overall['documentation'][e].strip())
out_file.write('\n\n')
output_doc = QMK_FIRMWARE / "docs" / f"xap_protocol.md" output_doc = QMK_FIRMWARE / "docs" / f"xap_protocol.md"
with open(output_doc, "w", encoding='utf-8') as out_file: with open(output_doc, "w", encoding='utf-8') as out_file:

View File

@ -5,6 +5,7 @@ colorama
fnvhash fnvhash
hid hid
hjson hjson
Jinja2
jsonschema>=3 jsonschema>=3
milc>=1.4.2 milc>=1.4.2
pygments pygments