summaryrefslogtreecommitdiffstats
path: root/lib/python/qmk/info.py
diff options
context:
space:
mode:
authorlokher <lokher@gmail.com>2023-04-26 16:32:15 +0800
committerlokher <lokher@gmail.com>2023-04-26 16:32:15 +0800
commite4f4ceaf3f2e3d25fb282273a81f9b58790fc427 (patch)
treec0a257eab0ffe5238fdf2c04882e8ee1fe8fc46e /lib/python/qmk/info.py
parent103badc87cb50db1ff3851c84331e86ba78fb681 (diff)
merge upstream 713427c
Diffstat (limited to 'lib/python/qmk/info.py')
-rw-r--r--lib/python/qmk/info.py80
1 files changed, 60 insertions, 20 deletions
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index 7e588b5182..b7ee055eef 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -1,16 +1,16 @@
"""Functions that help us generate and use info.json files.
"""
+import re
from pathlib import Path
-
import jsonschema
from dotty_dict import dotty
+
from milc import cli
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
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.keyboard import config_h, rules_mk
-from qmk.keymap import list_keymaps, locate_keymap
from qmk.commands import parse_configurator_json
from qmk.makefile import parse_rules_mk_file
from qmk.math import compute
@@ -18,15 +18,30 @@ from qmk.math import compute
true_values = ['1', 'on', 'yes']
false_values = ['0', 'off', 'no']
-# TODO: reduce this list down
-SAFE_LAYOUT_TOKENS = {
- 'ansi',
- 'iso',
- 'wkl',
- 'tkl',
- 'preonic',
- 'planck',
-}
+
+def _keyboard_in_layout_name(keyboard, layout):
+ """Validate that a layout macro does not contain name of keyboard
+ """
+ # TODO: reduce this list down
+ safe_layout_tokens = {
+ 'ansi',
+ 'iso',
+ 'jp',
+ 'jis',
+ 'ortho',
+ 'wkl',
+ 'tkl',
+ 'preonic',
+ 'planck',
+ }
+
+ # Ignore tokens like 'split_3x7_4' or just '2x4'
+ layout = re.sub(r"_split_\d+x\d+_\d+", '', layout)
+ layout = re.sub(r"_\d+x\d+", '', layout)
+
+ name_fragments = set(keyboard.split('/')) - safe_layout_tokens
+
+ return any(fragment in layout for fragment in name_fragments)
def _valid_community_layout(layout):
@@ -53,18 +68,27 @@ def _validate(keyboard, info_data):
community_layouts_names = list(map(lambda layout: f'LAYOUT_{layout}', community_layouts))
# Make sure we have at least one layout
- if len(layouts) == 0:
+ 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.')
+ # 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():
+ offset_x = min([k['x'] for k in layout_data['layout']])
+ if offset_x > 0:
+ _log_warning(info_data, f'Layout "{layout_name}" is offset on X axis by {offset_x}')
+
+ offset_y = min([k['y'] for k in layout_data['layout']])
+ if offset_y > 0:
+ _log_warning(info_data, f'Layout "{layout_name}" is offset on Y axis by {offset_y}')
+
# Providing only LAYOUT_all "because I define my layouts in a 3rd party tool"
if len(layouts) == 1 and 'LAYOUT_all' in layouts:
_log_warning(info_data, '"LAYOUT_all" should be "LAYOUT" unless additional layouts are provided.')
# Extended layout name checks - ignoring community_layouts and "safe" values
- name_fragments = set(keyboard.split('/')) - SAFE_LAYOUT_TOKENS
potential_layouts = set(layouts.keys()) - set(community_layouts_names)
for layout in potential_layouts:
- if any(fragment in layout for fragment in name_fragments):
+ if _keyboard_in_layout_name(keyboard, layout):
_log_warning(info_data, f'Layout "{layout}" should not contain name of keyboard.')
# Filter out any non-existing community layouts
@@ -99,10 +123,6 @@ def info_json(keyboard):
'maintainer': 'qmk',
}
- # Populate the list of JSON keymaps
- for keymap in list_keymaps(keyboard, c=False, fullpath=True):
- info_data['keymaps'][keymap.name] = {'url': f'https://raw.githubusercontent.com/qmk/qmk_firmware/master/{keymap}/keymap.json'}
-
# Populate layout data
layouts, aliases = _search_keyboard_h(keyboard)
@@ -112,6 +132,7 @@ def info_json(keyboard):
for layout_name, layout_json in layouts.items():
if not layout_name.startswith('LAYOUT_kc'):
layout_json['c_macro'] = True
+ layout_json['json_layout'] = False
info_data['layouts'][layout_name] = layout_json
# Merge in the data from info.json, config.h, and rules.mk
@@ -561,8 +582,16 @@ def _process_defaults(info_data):
for default_type in defaults_map.keys():
thing_map = defaults_map[default_type]
if default_type in info_data:
- for key, value in thing_map.get(info_data[default_type], {}).items():
- info_data[key] = value
+ merged_count = 0
+ thing_items = thing_map.get(info_data[default_type], {}).items()
+ for key, value in thing_items:
+ if key not in info_data:
+ info_data[key] = value
+ merged_count += 1
+
+ if merged_count == 0 and len(thing_items) > 0:
+ _log_warning(info_data, 'All defaults for \'%s\' were skipped, potential redundant config or misconfiguration detected' % (default_type))
+
return info_data
@@ -748,6 +777,7 @@ def arm_processor_rules(info_data, rules):
"""
info_data['processor_type'] = 'arm'
info_data['protocol'] = 'ChibiOS'
+ info_data['platform_key'] = 'chibios'
if 'STM32' in info_data['processor']:
info_data['platform'] = 'STM32'
@@ -755,6 +785,7 @@ def arm_processor_rules(info_data, rules):
info_data['platform'] = rules['MCU_SERIES']
elif 'ARM_ATSAM' in rules:
info_data['platform'] = 'ARM_ATSAM'
+ info_data['platform_key'] = 'arm_atsam'
return info_data
@@ -764,6 +795,7 @@ def avr_processor_rules(info_data, rules):
"""
info_data['processor_type'] = 'avr'
info_data['platform'] = rules['ARCH'] if 'ARCH' in rules else 'unknown'
+ info_data['platform_key'] = 'avr'
info_data['protocol'] = 'V-USB' if info_data['processor'] in VUSB_PROCESSORS else 'LUFA'
# FIXME(fauxpark/anyone): Eventually we should detect the protocol by looking at PROTOCOL inherited from mcu_selection.mk:
@@ -818,6 +850,7 @@ def merge_info_jsons(keyboard, info_data):
msg = 'Number of keys for %s does not match! info.json specifies %d keys, C macro specifies %d'
_log_error(info_data, msg % (layout_name, len(layout['layout']), len(info_data['layouts'][layout_name]['layout'])))
else:
+ info_data['layouts'][layout_name]['json_layout'] = True
for new_key, existing_key in zip(layout['layout'], info_data['layouts'][layout_name]['layout']):
existing_key.update(new_key)
else:
@@ -825,6 +858,7 @@ def merge_info_jsons(keyboard, info_data):
_log_error(info_data, f'Layout "{layout_name}" has no "matrix" definition in either "info.json" or "<keyboard>.h"!')
else:
layout['c_macro'] = False
+ layout['json_layout'] = True
info_data['layouts'][layout_name] = layout
# Update info_data with the new data
@@ -864,6 +898,9 @@ def find_info_json(keyboard):
def keymap_json_config(keyboard, keymap):
"""Extract keymap level config
"""
+ # TODO: resolve keymap.py and info.py circular dependencies
+ from qmk.keymap import locate_keymap
+
keymap_folder = locate_keymap(keyboard, keymap).parent
km_info_json = parse_configurator_json(keymap_folder / 'keymap.json')
@@ -873,6 +910,9 @@ def keymap_json_config(keyboard, keymap):
def keymap_json(keyboard, keymap):
"""Generate the info.json data for a specific keymap.
"""
+ # TODO: resolve keymap.py and info.py circular dependencies
+ from qmk.keymap import locate_keymap
+
keymap_folder = locate_keymap(keyboard, keymap).parent
# Files to scan