diff options
author | Zach White <skullydazed@users.noreply.github.com> | 2020-05-26 13:05:41 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-26 13:05:41 -0700 |
commit | 751316c34465ea77e066c3052729b207f3d62e0c (patch) | |
tree | cb99656b93c156757e2fd7c84fe716f9c300ca89 /lib/python/qmk/keyboard.py | |
parent | 5d3bf8a050f3c0beb1f91147dc1ab54de36cbb05 (diff) | |
download | qmk_firmware-751316c34465ea77e066c3052729b207f3d62e0c.tar.gz qmk_firmware-751316c34465ea77e066c3052729b207f3d62e0c.zip |
[CLI] Add a subcommand for getting information about a keyboard (#8666)
You can now use `qmk info` to get information about keyboards and keymaps.
Co-authored-by: Erovia <Erovia@users.noreply.github.com>
Diffstat (limited to 'lib/python/qmk/keyboard.py')
-rw-r--r-- | lib/python/qmk/keyboard.py | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/lib/python/qmk/keyboard.py b/lib/python/qmk/keyboard.py new file mode 100644 index 000000000..d1f2a301d --- /dev/null +++ b/lib/python/qmk/keyboard.py | |||
@@ -0,0 +1,111 @@ | |||
1 | """Functions that help us work with keyboards. | ||
2 | """ | ||
3 | from array import array | ||
4 | from math import ceil | ||
5 | from pathlib import Path | ||
6 | |||
7 | from qmk.c_parse import parse_config_h_file | ||
8 | from qmk.makefile import parse_rules_mk_file | ||
9 | |||
10 | |||
11 | def config_h(keyboard): | ||
12 | """Parses all the config.h files for a keyboard. | ||
13 | |||
14 | Args: | ||
15 | keyboard: name of the keyboard | ||
16 | |||
17 | Returns: | ||
18 | a dictionary representing the content of the entire config.h tree for a keyboard | ||
19 | """ | ||
20 | config = {} | ||
21 | cur_dir = Path('keyboards') | ||
22 | rules = rules_mk(keyboard) | ||
23 | keyboard = Path(rules['DEFAULT_FOLDER'] if 'DEFAULT_FOLDER' in rules else keyboard) | ||
24 | |||
25 | for dir in keyboard.parts: | ||
26 | cur_dir = cur_dir / dir | ||
27 | config = {**config, **parse_config_h_file(cur_dir / 'config.h')} | ||
28 | |||
29 | return config | ||
30 | |||
31 | |||
32 | def rules_mk(keyboard): | ||
33 | """Get a rules.mk for a keyboard | ||
34 | |||
35 | Args: | ||
36 | keyboard: name of the keyboard | ||
37 | |||
38 | Returns: | ||
39 | a dictionary representing the content of the entire rules.mk tree for a keyboard | ||
40 | """ | ||
41 | keyboard = Path(keyboard) | ||
42 | cur_dir = Path('keyboards') | ||
43 | rules = parse_rules_mk_file(cur_dir / keyboard / 'rules.mk') | ||
44 | |||
45 | if 'DEFAULT_FOLDER' in rules: | ||
46 | keyboard = Path(rules['DEFAULT_FOLDER']) | ||
47 | |||
48 | for i, dir in enumerate(keyboard.parts): | ||
49 | cur_dir = cur_dir / dir | ||
50 | rules = parse_rules_mk_file(cur_dir / 'rules.mk', rules) | ||
51 | |||
52 | return rules | ||
53 | |||
54 | |||
55 | def render_layout(layout_data, key_labels=None): | ||
56 | """Renders a single layout. | ||
57 | """ | ||
58 | textpad = [array('u', ' ' * 200) for x in range(50)] | ||
59 | |||
60 | for key in layout_data: | ||
61 | x = ceil(key.get('x', 0) * 4) | ||
62 | y = ceil(key.get('y', 0) * 3) | ||
63 | w = ceil(key.get('w', 1) * 4) | ||
64 | h = ceil(key.get('h', 1) * 3) | ||
65 | |||
66 | if key_labels: | ||
67 | label = key_labels.pop(0) | ||
68 | if label.startswith('KC_'): | ||
69 | label = label[3:] | ||
70 | else: | ||
71 | label = key.get('label', '') | ||
72 | |||
73 | label_len = w - 2 | ||
74 | label_leftover = label_len - len(label) | ||
75 | |||
76 | if len(label) > label_len: | ||
77 | label = label[:label_len] | ||
78 | |||
79 | label_blank = ' ' * label_len | ||
80 | label_border = '─' * label_len | ||
81 | label_middle = label + ' '*label_leftover # noqa: yapf insists there be no whitespace around * | ||
82 | |||
83 | top_line = array('u', '┌' + label_border + '┐') | ||
84 | lab_line = array('u', '│' + label_middle + '│') | ||
85 | mid_line = array('u', '│' + label_blank + '│') | ||
86 | bot_line = array('u', '└' + label_border + "┘") | ||
87 | |||
88 | textpad[y][x:x + w] = top_line | ||
89 | textpad[y + 1][x:x + w] = lab_line | ||
90 | for i in range(h - 3): | ||
91 | textpad[y + i + 2][x:x + w] = mid_line | ||
92 | textpad[y + h - 1][x:x + w] = bot_line | ||
93 | |||
94 | lines = [] | ||
95 | for line in textpad: | ||
96 | if line.tounicode().strip(): | ||
97 | lines.append(line.tounicode().rstrip()) | ||
98 | |||
99 | return '\n'.join(lines) | ||
100 | |||
101 | |||
102 | def render_layouts(info_json): | ||
103 | """Renders all the layouts from an `info_json` structure. | ||
104 | """ | ||
105 | layouts = {} | ||
106 | |||
107 | for layout in info_json['layouts']: | ||
108 | layout_data = info_json['layouts'][layout]['layout'] | ||
109 | layouts[layout] = render_layout(layout_data) | ||
110 | |||
111 | return layouts | ||