From 20f142a7723b0362c0d936d600fb01c649cec951 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Mon, 19 Sep 2022 01:35:46 +0100 Subject: Tidy up LAYOUT macro generation (#18262) --- lib/python/qmk/cli/__init__.py | 1 - lib/python/qmk/cli/generate/keyboard_h.py | 69 +++++++++++++++++++++---- lib/python/qmk/cli/generate/layouts.py | 84 ------------------------------- lib/python/qmk/tests/test_cli_commands.py | 6 --- 4 files changed, 59 insertions(+), 101 deletions(-) delete mode 100755 lib/python/qmk/cli/generate/layouts.py (limited to 'lib/python/qmk') diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py index 02561da1fb..cf5b5ad87e 100644 --- a/lib/python/qmk/cli/__init__.py +++ b/lib/python/qmk/cli/__init__.py @@ -56,7 +56,6 @@ subcommands = [ 'qmk.cli.generate.info_json', 'qmk.cli.generate.keyboard_c', 'qmk.cli.generate.keyboard_h', - 'qmk.cli.generate.layouts', 'qmk.cli.generate.rgb_breathe_table', 'qmk.cli.generate.rules_mk', 'qmk.cli.generate.version_h', diff --git a/lib/python/qmk/cli/generate/keyboard_h.py b/lib/python/qmk/cli/generate/keyboard_h.py index 54ddb4cffd..910bd6a08d 100755 --- a/lib/python/qmk/cli/generate/keyboard_h.py +++ b/lib/python/qmk/cli/generate/keyboard_h.py @@ -1,33 +1,72 @@ """Used by the make system to generate keyboard.h from info.json. """ +from pathlib import Path + from milc import cli +from qmk.path import normpath from qmk.info import info_json from qmk.commands import dump_lines from qmk.keyboard import keyboard_completer, keyboard_folder -from qmk.path import normpath -from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE +from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE -def would_populate_layout_h(keyboard): - """Detect if a given keyboard is doing data driven layouts +def _generate_layouts(keyboard): + """Generates the layouts.h file. """ # Build the info.json file kb_info_json = info_json(keyboard) + if 'matrix_size' not in kb_info_json: + cli.log.error(f'{keyboard}: Invalid matrix config.') + return [] + + col_num = kb_info_json['matrix_size']['cols'] + row_num = kb_info_json['matrix_size']['rows'] + + lines = [] for layout_name in kb_info_json['layouts']: if kb_info_json['layouts'][layout_name]['c_macro']: continue if 'matrix' not in kb_info_json['layouts'][layout_name]['layout'][0]: - cli.log.debug('%s/%s: No matrix data!', keyboard, layout_name) + cli.log.debug(f'{keyboard}/{layout_name}: No matrix data!') continue - return True + layout_keys = [] + layout_matrix = [['KC_NO' for i in range(col_num)] for i in range(row_num)] + + for i, key in enumerate(kb_info_json['layouts'][layout_name]['layout']): + row = key['matrix'][0] + col = key['matrix'][1] + identifier = 'k%s%s' % (ROW_LETTERS[row], COL_LETTERS[col]) - return False + try: + layout_matrix[row][col] = identifier + layout_keys.append(identifier) + except IndexError: + key_name = key.get('label', identifier) + cli.log.error(f'Matrix data out of bounds for layout {layout_name} at index {i} ({key_name}): [{row}, {col}]') + return [] + lines.append('') + lines.append('#define %s(%s) {\\' % (layout_name, ', '.join(layout_keys))) + rows = ', \\\n'.join(['\t {' + ', '.join(row) + '}' for row in layout_matrix]) + rows += ' \\' + lines.append(rows) + lines.append('}') + + for alias, target in kb_info_json.get('layout_aliases', {}).items(): + lines.append('') + lines.append(f'#ifndef {alias}') + lines.append(f'# define {alias} {target}') + lines.append('#endif') + + return lines + + +@cli.argument('-i', '--include', nargs='?', arg_only=True, help='Optional file to include') @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") @cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, required=True, help='Keyboard to generate keyboard.h for.') @@ -35,13 +74,23 @@ def would_populate_layout_h(keyboard): def generate_keyboard_h(cli): """Generates the keyboard.h file. """ - has_layout_h = would_populate_layout_h(cli.args.keyboard) + keyboard_h = cli.args.include + dd_layouts = _generate_layouts(cli.args.keyboard) + valid_config = dd_layouts or keyboard_h # Build the layouts.h file. keyboard_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '#include "quantum.h"'] - if not has_layout_h: - keyboard_h_lines.append('#error(".h is only optional for data driven keyboards - kb.h == bad times")') + keyboard_h_lines.append('') + keyboard_h_lines.append('// Layout content') + if dd_layouts: + keyboard_h_lines.extend(dd_layouts) + if keyboard_h: + keyboard_h_lines.append(f'#include "{Path(keyboard_h).name}"') + + # Protect against poorly configured keyboards + if not valid_config: + keyboard_h_lines.append('#error(".h is required unless your keyboard uses data-driven configuration. Please rename your keyboard\'s header file to .h")') # Show the results dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet) diff --git a/lib/python/qmk/cli/generate/layouts.py b/lib/python/qmk/cli/generate/layouts.py deleted file mode 100755 index 8336f36b50..0000000000 --- a/lib/python/qmk/cli/generate/layouts.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Used by the make system to generate layouts.h from info.json. -""" -from milc import cli - -from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE -from qmk.decorators import automagic_keyboard, automagic_keymap -from qmk.info import info_json -from qmk.keyboard import keyboard_completer, keyboard_folder -from qmk.path import is_keyboard, normpath -from qmk.commands import dump_lines - - -@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') -@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") -@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.') -@cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True) -@automagic_keyboard -@automagic_keymap -def generate_layouts(cli): - """Generates the layouts.h file. - """ - # Determine our keyboard(s) - if not cli.config.generate_layouts.keyboard: - cli.log.error('Missing parameter: --keyboard') - cli.subcommands['info'].print_help() - return False - - if not is_keyboard(cli.config.generate_layouts.keyboard): - cli.log.error('Invalid keyboard: "%s"', cli.config.generate_layouts.keyboard) - return False - - # Build the info.json file - kb_info_json = info_json(cli.config.generate_layouts.keyboard) - - # Build the layouts.h file. - layouts_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once'] - - if 'matrix_size' not in kb_info_json: - cli.log.error('%s: Invalid matrix config.', cli.config.generate_layouts.keyboard) - return False - - col_num = kb_info_json['matrix_size']['cols'] - row_num = kb_info_json['matrix_size']['rows'] - - for layout_name in kb_info_json['layouts']: - if kb_info_json['layouts'][layout_name]['c_macro']: - continue - - if 'matrix' not in kb_info_json['layouts'][layout_name]['layout'][0]: - cli.log.debug('%s/%s: No matrix data!', cli.config.generate_layouts.keyboard, layout_name) - continue - - layout_keys = [] - layout_matrix = [['KC_NO' for i in range(col_num)] for i in range(row_num)] - - for i, key in enumerate(kb_info_json['layouts'][layout_name]['layout']): - row = key['matrix'][0] - col = key['matrix'][1] - identifier = 'k%s%s' % (ROW_LETTERS[row], COL_LETTERS[col]) - - try: - layout_matrix[row][col] = identifier - layout_keys.append(identifier) - except IndexError: - key_name = key.get('label', identifier) - cli.log.error('Matrix data out of bounds for layout %s at index %s (%s): %s, %s', layout_name, i, key_name, row, col) - return False - - layouts_h_lines.append('') - layouts_h_lines.append('#define %s(%s) {\\' % (layout_name, ', '.join(layout_keys))) - - rows = ', \\\n'.join(['\t {' + ', '.join(row) + '}' for row in layout_matrix]) - rows += ' \\' - layouts_h_lines.append(rows) - layouts_h_lines.append('}') - - for alias, target in kb_info_json.get('layout_aliases', {}).items(): - layouts_h_lines.append('') - layouts_h_lines.append(f'#ifndef {alias}') - layouts_h_lines.append(f'# define {alias} {target}') - layouts_h_lines.append('#endif') - - # Show the results - dump_lines(cli.args.output, layouts_h_lines, cli.args.quiet) diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index 185abb5f21..c8c4e2f80c 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py @@ -288,12 +288,6 @@ def test_generate_version_h(): assert '#define QMK_VERSION' in result.stdout -def test_generate_layouts(): - result = check_subcommand('generate-layouts', '-kb', 'handwired/pytest/basic') - check_returncode(result) - assert '#define LAYOUT_custom(k0A) {' in result.stdout - - def test_format_json_keyboard(): result = check_subcommand('format-json', '--format', 'keyboard', 'lib/python/qmk/tests/minimal_info.json') check_returncode(result) -- cgit v1.2.3