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: [
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
]

View file

@ -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":

View file

@ -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":

View file

@ -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":

View file

@ -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 = [

View file

@ -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):

View file

@ -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:

View file

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