forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CLI] Add a subcommand for getting information about a keyboard (qmk#…
…8666) You can now use `qmk info` to get information about keyboards and keymaps. Co-authored-by: Erovia <Erovia@users.noreply.github.com>
- Loading branch information
1 parent
5d3bf8a
commit 751316c
Showing
17 changed files
with
921 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
"""Functions for working with config.h files. | ||
""" | ||
from pathlib import Path | ||
|
||
from milc import cli | ||
|
||
from qmk.comment_remover import comment_remover | ||
|
||
default_key_entry = {'x': -1, 'y': 0, 'w': 1} | ||
|
||
|
||
def c_source_files(dir_names): | ||
"""Returns a list of all *.c, *.h, and *.cpp files for a given list of directories | ||
Args: | ||
dir_names | ||
List of directories relative to `qmk_firmware`. | ||
""" | ||
files = [] | ||
for dir in dir_names: | ||
files.extend(file for file in Path(dir).glob('**/*') if file.suffix in ['.c', '.h', '.cpp']) | ||
return files | ||
|
||
|
||
def find_layouts(file): | ||
"""Returns list of parsed LAYOUT preprocessor macros found in the supplied include file. | ||
""" | ||
file = Path(file) | ||
aliases = {} # Populated with all `#define`s that aren't functions | ||
parsed_layouts = {} | ||
|
||
# Search the file for LAYOUT macros and aliases | ||
file_contents = file.read_text() | ||
file_contents = comment_remover(file_contents) | ||
file_contents = file_contents.replace('\\\n', '') | ||
|
||
for line in file_contents.split('\n'): | ||
if line.startswith('#define') and '(' in line and 'LAYOUT' in line: | ||
# We've found a LAYOUT macro | ||
macro_name, layout, matrix = _parse_layout_macro(line.strip()) | ||
|
||
# Reject bad macro names | ||
if macro_name.startswith('LAYOUT_kc') or not macro_name.startswith('LAYOUT'): | ||
continue | ||
|
||
# Parse the matrix data | ||
matrix_locations = _parse_matrix_locations(matrix, file, macro_name) | ||
|
||
# Parse the layout entries into a basic structure | ||
default_key_entry['x'] = -1 # Set to -1 so _default_key(key) will increment it to 0 | ||
layout = layout.strip() | ||
parsed_layout = [_default_key(key) for key in layout.split(',')] | ||
|
||
for key in parsed_layout: | ||
key['matrix'] = matrix_locations.get(key['label']) | ||
|
||
parsed_layouts[macro_name] = { | ||
'key_count': len(parsed_layout), | ||
'layout': parsed_layout, | ||
'filename': str(file), | ||
} | ||
|
||
elif '#define' in line: | ||
# Attempt to extract a new layout alias | ||
try: | ||
_, pp_macro_name, pp_macro_text = line.strip().split(' ', 2) | ||
aliases[pp_macro_name] = pp_macro_text | ||
except ValueError: | ||
continue | ||
|
||
# Populate our aliases | ||
for alias, text in aliases.items(): | ||
if text in parsed_layouts and 'KEYMAP' not in alias: | ||
parsed_layouts[alias] = parsed_layouts[text] | ||
|
||
return parsed_layouts | ||
|
||
|
||
def parse_config_h_file(config_h_file, config_h=None): | ||
"""Extract defines from a config.h file. | ||
""" | ||
if not config_h: | ||
config_h = {} | ||
|
||
config_h_file = Path(config_h_file) | ||
|
||
if config_h_file.exists(): | ||
config_h_text = config_h_file.read_text() | ||
config_h_text = config_h_text.replace('\\\n', '') | ||
|
||
for linenum, line in enumerate(config_h_text.split('\n')): | ||
line = line.strip() | ||
|
||
if '//' in line: | ||
line = line[:line.index('//')].strip() | ||
|
||
if not line: | ||
continue | ||
|
||
line = line.split() | ||
|
||
if line[0] == '#define': | ||
if len(line) == 1: | ||
cli.log.error('%s: Incomplete #define! On or around line %s' % (config_h_file, linenum)) | ||
elif len(line) == 2: | ||
config_h[line[1]] = True | ||
else: | ||
config_h[line[1]] = ' '.join(line[2:]) | ||
|
||
elif line[0] == '#undef': | ||
if len(line) == 2: | ||
if line[1] in config_h: | ||
if config_h[line[1]] is True: | ||
del config_h[line[1]] | ||
else: | ||
config_h[line[1]] = False | ||
else: | ||
cli.log.error('%s: Incomplete #undef! On or around line %s' % (config_h_file, linenum)) | ||
|
||
return config_h | ||
|
||
|
||
def _default_key(label=None): | ||
"""Increment x and return a copy of the default_key_entry. | ||
""" | ||
default_key_entry['x'] += 1 | ||
new_key = default_key_entry.copy() | ||
|
||
if label: | ||
new_key['label'] = label | ||
|
||
return new_key | ||
|
||
|
||
def _parse_layout_macro(layout_macro): | ||
"""Split the LAYOUT macro into its constituent parts | ||
""" | ||
layout_macro = layout_macro.replace('\\', '').replace(' ', '').replace('\t', '').replace('#define', '') | ||
macro_name, layout = layout_macro.split('(', 1) | ||
layout, matrix = layout.split(')', 1) | ||
|
||
return macro_name, layout, matrix | ||
|
||
|
||
def _parse_matrix_locations(matrix, file, macro_name): | ||
"""Parse raw matrix data into a dictionary keyed by the LAYOUT identifier. | ||
""" | ||
matrix_locations = {} | ||
|
||
for row_num, row in enumerate(matrix.split('},{')): | ||
if row.startswith('LAYOUT'): | ||
cli.log.error('%s: %s: Nested layout macro detected. Matrix data not available!', file, macro_name) | ||
break | ||
|
||
row = row.replace('{', '').replace('}', '') | ||
for col_num, identifier in enumerate(row.split(',')): | ||
if identifier != 'KC_NO': | ||
matrix_locations[identifier] = (row_num, col_num) | ||
|
||
return matrix_locations |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.