diff options
Diffstat (limited to 'lib/python/qmk/keymap.py')
-rw-r--r-- | lib/python/qmk/keymap.py | 75 |
1 files changed, 64 insertions, 11 deletions
diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py index 266532f503..2d5921e7a8 100644 --- a/lib/python/qmk/keymap.py +++ b/lib/python/qmk/keymap.py @@ -1,19 +1,19 @@ """Functions that help you work with QMK keymaps. """ -from pathlib import Path import json -import subprocess import sys +from pathlib import Path +from subprocess import DEVNULL +import argcomplete +from milc import cli from pygments.lexers.c_cpp import CLexer from pygments.token import Token from pygments import lex -from milc import cli - -from qmk.keyboard import rules_mk import qmk.path -import qmk.commands +from qmk.keyboard import find_keyboard_from_dir, rules_mk +from qmk.errors import CppError # The `keymap.c` template to use when a keyboard doesn't have its own DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H @@ -42,7 +42,7 @@ def template_json(keyboard): template_file = Path('keyboards/%s/templates/keymap.json' % keyboard) template = {'keyboard': keyboard} if template_file.exists(): - template.update(json.loads(template_file.read_text())) + template.update(json.load(template_file.open(encoding='utf-8'))) return template @@ -58,7 +58,7 @@ def template_c(keyboard): """ template_file = Path('keyboards/%s/templates/keymap.c' % keyboard) if template_file.exists(): - template = template_file.read_text() + template = template_file.read_text(encoding='utf-8') else: template = DEFAULT_KEYMAP_C @@ -74,6 +74,54 @@ def _strip_any(keycode): return keycode +def find_keymap_from_dir(): + """Returns `(keymap_name, source)` for the directory we're currently in. + + """ + relative_cwd = qmk.path.under_qmk_firmware() + + if relative_cwd and len(relative_cwd.parts) > 1: + # If we're in `qmk_firmware/keyboards` and `keymaps` is in our path, try to find the keyboard name. + if relative_cwd.parts[0] == 'keyboards' and 'keymaps' in relative_cwd.parts: + current_path = Path('/'.join(relative_cwd.parts[1:])) # Strip 'keyboards' from the front + + if 'keymaps' in current_path.parts and current_path.name != 'keymaps': + while current_path.parent.name != 'keymaps': + current_path = current_path.parent + + return current_path.name, 'keymap_directory' + + # If we're in `qmk_firmware/layouts` guess the name from the community keymap they're in + elif relative_cwd.parts[0] == 'layouts' and is_keymap_dir(relative_cwd): + return relative_cwd.name, 'layouts_directory' + + # If we're in `qmk_firmware/users` guess the name from the userspace they're in + elif relative_cwd.parts[0] == 'users': + # Guess the keymap name based on which userspace they're in + return relative_cwd.parts[1], 'users_directory' + + return None, None + + +def keymap_completer(prefix, action, parser, parsed_args): + """Returns a list of keymaps for tab completion. + """ + try: + if parsed_args.keyboard: + return list_keymaps(parsed_args.keyboard) + + keyboard = find_keyboard_from_dir() + + if keyboard: + return list_keymaps(keyboard) + + except Exception as e: + argcomplete.warn(f'Error: {e.__class__.__name__}: {str(e)}') + return [] + + return [] + + def is_keymap_dir(keymap, c=True, json=True, additional_files=None): """Return True if Path object `keymap` has a keymap file inside. @@ -313,7 +361,7 @@ def list_keymaps(keyboard, c=True, json=True, additional_files=None, fullpath=Fa return sorted(names) -def _c_preprocess(path, stdin=None): +def _c_preprocess(path, stdin=DEVNULL): """ Run a file through the C pre-processor Args: @@ -323,7 +371,12 @@ def _c_preprocess(path, stdin=None): Returns: the stdout of the pre-processor """ - pre_processed_keymap = qmk.commands.run(['cpp', path] if path else ['cpp'], stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + cmd = ['cpp', str(path)] if path else ['cpp'] + pre_processed_keymap = cli.run(cmd, stdin=stdin) + if 'fatal error' in pre_processed_keymap.stderr: + for line in pre_processed_keymap.stderr.split('\n'): + if 'fatal error' in line: + raise (CppError(line)) return pre_processed_keymap.stdout @@ -469,7 +522,7 @@ def parse_keymap_c(keymap_file, use_cpp=True): if use_cpp: keymap_file = _c_preprocess(keymap_file) else: - keymap_file = keymap_file.read_text() + keymap_file = keymap_file.read_text(encoding='utf-8') keymap = dict() keymap['layers'] = _get_layers(keymap_file) |