summaryrefslogtreecommitdiff
path: root/lib/python/qmk/keymap.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python/qmk/keymap.py')
-rw-r--r--lib/python/qmk/keymap.py75
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)