Reworked docs rendering using jinja2.

xap
Nick Brassel 3 years ago
parent 1e723e6647
commit 69e9c80ec3
  1. 7
      data/templates/xap/docs/docs.md.j2
  2. 9
      data/templates/xap/docs/response_flags.md.j2
  3. 5
      data/templates/xap/docs/term_definitions.md.j2
  4. 5
      data/templates/xap/docs/type_docs.md.j2
  5. 6
      data/xap/xap_0.0.1.hjson
  6. 7
      docs/xap_0.0.1.md
  7. 13
      docs/xap_0.1.0.md
  8. 13
      docs/xap_0.2.0.md
  9. 3
      lib/python/qmk/cli/__init__.py
  10. 15
      lib/python/qmk/xap/common.py
  11. 80
      lib/python/qmk/xap/gen_docs/generator.py
  12. 1
      requirements.txt

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

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save