diff options
-rwxr-xr-x | lib/python/qmk/cli/info.py | 12 | ||||
-rw-r--r-- | lib/python/qmk/keyboard.py | 55 | ||||
-rw-r--r-- | lib/python/qmk/tests/test_cli_commands.py | 17 |
3 files changed, 70 insertions, 14 deletions
diff --git a/lib/python/qmk/cli/info.py b/lib/python/qmk/cli/info.py index 0e64d40742..92f0b25c0f 100755 --- a/lib/python/qmk/cli/info.py +++ b/lib/python/qmk/cli/info.py @@ -3,6 +3,7 @@ Compile an info.json for a particular keyboard and pretty-print it. """ import json +import platform from milc import cli @@ -12,6 +13,8 @@ from qmk.keymap import locate_keymap from qmk.info import info_json from qmk.path import is_keyboard +platform_id = platform.platform().lower() + ROW_LETTERS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop' COL_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijilmnopqrstuvwxyz' @@ -36,13 +39,13 @@ def show_keymap(info_json, title_caps=True): else: cli.echo('{fg_cyan}layer_%s{fg_reset}:', layer_num) - print(render_layout(info_json['layouts'][layout_name]['layout'], layer)) + print(render_layout(kb_info_json['layouts'][layout_name]['layout'], cli.config.info.ascii, layer)) def show_layouts(kb_info_json, title_caps=True): """Render the layouts with info.json labels. """ - for layout_name, layout_art in render_layouts(kb_info_json).items(): + for layout_name, layout_art in render_layouts(kb_info_json, cli.config.info.ascii).items(): title = layout_name.title() if title_caps else layout_name cli.echo('{fg_cyan}%s{fg_reset}:', title) print(layout_art) # Avoid passing dirty data to cli.echo() @@ -69,7 +72,7 @@ def show_matrix(info_json, title_caps=True): else: cli.echo('{fg_blue}matrix_%s{fg_reset}:', layout_name) - print(render_layout(info_json['layouts'][layout_name]['layout'], labels)) + print(render_layout(kb_info_json['layouts'][layout_name]['layout'], cli.config.info.ascii, labels)) def print_friendly_output(info_json): @@ -124,6 +127,7 @@ def print_text_output(info_json): @cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.') @cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.') @cli.argument('-f', '--format', default='friendly', arg_only=True, help='Format to display the data in (friendly, text, json) (Default: friendly).') +@cli.argument('--ascii', action='store_true', default='windows' in platform_id, help='Render layout box drawings in ASCII only.') @cli.subcommand('Keyboard information.') @automagic_keyboard @automagic_keymap @@ -132,7 +136,7 @@ def info(cli): """ # Determine our keyboard(s) if not cli.config.info.keyboard: - cli.log.error('Missing paramater: --keyboard') + cli.log.error('Missing parameter: --keyboard') cli.subcommands['info'].print_help() return False diff --git a/lib/python/qmk/keyboard.py b/lib/python/qmk/keyboard.py index d1f2a301df..33f182e8f9 100644 --- a/lib/python/qmk/keyboard.py +++ b/lib/python/qmk/keyboard.py @@ -7,6 +7,43 @@ from pathlib import Path from qmk.c_parse import parse_config_h_file from qmk.makefile import parse_rules_mk_file +BOX_DRAWING_CHARACTERS = { + "unicode": { + "tl": "┌", + "tr": "┐", + "bl": "└", + "br": "┘", + "v": "│", + "h": "─", + }, + "ascii": { + "tl": " ", + "tr": " ", + "bl": "|", + "br": "|", + "v": "|", + "h": "_", + }, +} + +base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep + + +def _find_name(path): + """Determine the keyboard name by stripping off the base_path and rules.mk. + """ + return path.replace(base_path, "").replace(os.path.sep + "rules.mk", "") + + +def list_keyboards(): + """Returns a list of all keyboards. + """ + # We avoid pathlib here because this is performance critical code. + kb_wildcard = os.path.join(base_path, "**", "rules.mk") + paths = [path for path in glob(kb_wildcard, recursive=True) if 'keymaps' not in path] + + return sorted(map(_find_name, paths)) + def config_h(keyboard): """Parses all the config.h files for a keyboard. @@ -52,10 +89,12 @@ def rules_mk(keyboard): return rules -def render_layout(layout_data, key_labels=None): +def render_layout(layout_data, render_ascii, key_labels=None): """Renders a single layout. """ textpad = [array('u', ' ' * 200) for x in range(50)] + style = 'ascii' if render_ascii else 'unicode' + box_chars = BOX_DRAWING_CHARACTERS[style] for key in layout_data: x = ceil(key.get('x', 0) * 4) @@ -77,13 +116,13 @@ def render_layout(layout_data, key_labels=None): label = label[:label_len] label_blank = ' ' * label_len - label_border = '─' * label_len + label_border = box_chars['h'] * label_len label_middle = label + ' '*label_leftover # noqa: yapf insists there be no whitespace around * - top_line = array('u', '┌' + label_border + '┐') - lab_line = array('u', '│' + label_middle + '│') - mid_line = array('u', '│' + label_blank + '│') - bot_line = array('u', '└' + label_border + "┘") + top_line = array('u', box_chars['tl'] + label_border + box_chars['tr']) + lab_line = array('u', box_chars['v'] + label_middle + box_chars['v']) + mid_line = array('u', box_chars['v'] + label_blank + box_chars['v']) + bot_line = array('u', box_chars['bl'] + label_border + box_chars['br']) textpad[y][x:x + w] = top_line textpad[y + 1][x:x + w] = lab_line @@ -99,13 +138,13 @@ def render_layout(layout_data, key_labels=None): return '\n'.join(lines) -def render_layouts(info_json): +def render_layouts(info_json, render_ascii): """Renders all the layouts from an `info_json` structure. """ layouts = {} for layout in info_json['layouts']: layout_data = info_json['layouts'][layout]['layout'] - layouts[layout] = render_layout(layout_data) + layouts[layout] = render_layout(layout_data, render_ascii) return layouts diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index 7ac0bcbde7..7c261db6cd 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py @@ -1,7 +1,11 @@ +import platform + from subprocess import STDOUT, PIPE from qmk.commands import run +is_windows = 'windows' in platform.platform().lower() + def check_subcommand(command, *args): cmd = ['bin/qmk', command] + list(args) @@ -148,7 +152,11 @@ def test_info_keymap_render(): check_returncode(result) assert 'Keyboard Name: handwired/onekey/pytest' in result.stdout assert 'Processor: STM32F303' in result.stdout - assert '│A │' in result.stdout + + if is_windows: + assert '|A |' in result.stdout + else: + assert '│A │' in result.stdout def test_info_matrix_render(): @@ -157,7 +165,12 @@ def test_info_matrix_render(): assert 'Keyboard Name: handwired/onekey/pytest' in result.stdout assert 'Processor: STM32F303' in result.stdout assert 'LAYOUT_ortho_1x1' in result.stdout - assert '│0A│' in result.stdout + + if is_windows: + assert '|0A|' in result.stdout + else: + assert '│0A│' in result.stdout + assert 'Matrix for "LAYOUT_ortho_1x1"' in result.stdout |