Move layout macro OOB checks to lint (#22610)

master
Joel Challis 2024-01-22 11:35:51 +00:00 committed by GitHub
parent 1522695cef
commit 58721a433b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 12 deletions

View File

@ -33,18 +33,11 @@ def _generate_layouts(keyboard, kb_info_json):
layout_keys = [] layout_keys = []
layout_matrix = [['KC_NO'] * col_num for _ in range(row_num)] layout_matrix = [['KC_NO'] * col_num for _ in range(row_num)]
for index, key_data in enumerate(layout_data['layout']): for key_data in layout_data['layout']:
row, col = key_data['matrix'] row, col = key_data['matrix']
identifier = f'k{ROW_LETTERS[row]}{COL_LETTERS[col]}' identifier = f'k{ROW_LETTERS[row]}{COL_LETTERS[col]}'
if row >= row_num or col >= col_num: if row >= row_num or col >= col_num:
key_name = key_data.get('label', identifier) cli.log.error(f'Skipping layouts due to {layout_name} containing invalid matrix values')
if row >= row_num:
cli.log.error(f'{keyboard}/{layout_name}: Matrix row for key {index} ({key_name}) is {row} but must be less than {row_num}')
if col >= col_num:
cli.log.error(f'{keyboard}/{layout_name}: Matrix column for key {index} ({key_name}) is {col} but must be less than {col_num}')
return [] return []
layout_matrix[row][col] = identifier layout_matrix[row][col] = identifier

View File

@ -7,7 +7,7 @@ from dotty_dict import dotty
from milc import cli from milc import cli
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS from qmk.constants import COL_LETTERS, ROW_LETTERS, CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
from qmk.c_parse import find_layouts, parse_config_h_file, find_led_config from qmk.c_parse import find_layouts, parse_config_h_file, find_led_config
from qmk.json_schema import deep_update, json_load, validate from qmk.json_schema import deep_update, json_load, validate
from qmk.keyboard import config_h, rules_mk from qmk.keyboard import config_h, rules_mk
@ -78,9 +78,11 @@ def _find_invalid_encoder_index(info_data):
return ret return ret
def _additional_validation(keyboard, info_data): def _validate_layouts(keyboard, info_data):
"""Non schema checks """Non schema checks
""" """
col_num = info_data.get('matrix_size', {}).get('cols', 0)
row_num = info_data.get('matrix_size', {}).get('rows', 0)
layouts = info_data.get('layouts', {}) layouts = info_data.get('layouts', {})
layout_aliases = info_data.get('layout_aliases', {}) layout_aliases = info_data.get('layout_aliases', {})
community_layouts = info_data.get('community_layouts', []) community_layouts = info_data.get('community_layouts', [])
@ -90,6 +92,16 @@ def _additional_validation(keyboard, info_data):
if len(layouts) == 0 or all(not layout.get('json_layout', False) for layout in layouts.values()): if len(layouts) == 0 or all(not layout.get('json_layout', False) for layout in layouts.values()):
_log_error(info_data, 'No LAYOUTs defined! Need at least one layout defined in info.json.') _log_error(info_data, 'No LAYOUTs defined! Need at least one layout defined in info.json.')
# Make sure all matrix values are in bounds
for layout_name, layout_data in layouts.items():
for index, key_data in enumerate(layout_data['layout']):
row, col = key_data['matrix']
key_name = key_data.get('label', f'k{ROW_LETTERS[row]}{COL_LETTERS[col]}')
if row >= row_num:
_log_error(info_data, f'{layout_name}: Matrix row for key {index} ({key_name}) is {row} but must be less than {row_num}')
if col >= col_num:
_log_error(info_data, f'{layout_name}: Matrix column for key {index} ({key_name}) is {col} but must be less than {col_num}')
# Warn if physical positions are offset (at least one key should be at x=0, and at least one key at y=0) # Warn if physical positions are offset (at least one key should be at x=0, and at least one key at y=0)
for layout_name, layout_data in layouts.items(): for layout_name, layout_data in layouts.items():
offset_x = min([_get_key_left_position(k) for k in layout_data['layout']]) offset_x = min([_get_key_left_position(k) for k in layout_data['layout']])
@ -122,12 +134,20 @@ def _additional_validation(keyboard, info_data):
if layout_name not in layouts and layout_name not in layout_aliases: if layout_name not in layouts and layout_name not in layout_aliases:
_log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name)) _log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name))
def _validate_keycodes(keyboard, info_data):
"""Non schema checks
"""
# keycodes with length > 7 must have short forms for visualisation purposes # keycodes with length > 7 must have short forms for visualisation purposes
for decl in info_data.get('keycodes', []): for decl in info_data.get('keycodes', []):
if len(decl["key"]) > 7: if len(decl["key"]) > 7:
if not decl.get("aliases", []): if not decl.get("aliases", []):
_log_error(info_data, f'Keycode {decl["key"]} has no short form alias') _log_error(info_data, f'Keycode {decl["key"]} has no short form alias')
def _validate_encoders(keyboard, info_data):
"""Non schema checks
"""
# encoder IDs in layouts must be in range and not duplicated # encoder IDs in layouts must be in range and not duplicated
found = _find_invalid_encoder_index(info_data) found = _find_invalid_encoder_index(info_data)
for layout_name, encoder_index, reason in found: for layout_name, encoder_index, reason in found:
@ -141,7 +161,10 @@ def _validate(keyboard, info_data):
try: try:
validate(info_data, 'qmk.api.keyboard.v1') validate(info_data, 'qmk.api.keyboard.v1')
_additional_validation(keyboard, info_data) # Additional validation
_validate_layouts(keyboard, info_data)
_validate_keycodes(keyboard, info_data)
_validate_encoders(keyboard, info_data)
except jsonschema.ValidationError as e: except jsonschema.ValidationError as e:
json_path = '.'.join([str(p) for p in e.absolute_path]) json_path = '.'.join([str(p) for p in e.absolute_path])