From e69da2db2c59a8017f0c9dee9933dd508d22b356 Mon Sep 17 00:00:00 2001
From: Ryan <fauxpark@gmail.com>
Date: Mon, 2 Nov 2020 19:41:01 +1100
Subject: [PATCH] `qmk info`: Add `--ascii` flag (#10793)

* `qmk info`: Add `--ascii` flag

* Fix typo

* Force ASCII for Windows/MSYS2

* Make it gooder

* Remove redundant windows check

* ...And this too

* Make pytest work on Windows
---
 lib/python/qmk/cli/info.py                | 12 +++++---
 lib/python/qmk/keyboard.py                | 37 ++++++++++++++++++-----
 lib/python/qmk/tests/test_cli_commands.py | 17 +++++++++--
 3 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/lib/python/qmk/cli/info.py b/lib/python/qmk/cli/info.py
index 44ce1186aa..9ab299a21e 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(kb_info_json, title_caps=True):
             else:
                 cli.echo('{fg_cyan}layer_%s{fg_reset}:', layer_num)
 
-            print(render_layout(kb_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(kb_info_json, title_caps=True):
         else:
             cli.echo('{fg_blue}matrix_%s{fg_reset}:', layout_name)
 
-        print(render_layout(kb_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(kb_info_json):
@@ -124,6 +127,7 @@ def print_text_output(kb_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 9ebb2d77d3..a4c2873757 100644
--- a/lib/python/qmk/keyboard.py
+++ b/lib/python/qmk/keyboard.py
@@ -9,6 +9,25 @@ from glob import glob
 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
 
 
@@ -72,10 +91,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)
@@ -97,13 +118,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
@@ -119,13 +140,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