1
0
Fork 0

QMK Userspace (#22222)

Co-authored-by: Duncan Sutherland <dunk2k_2000@hotmail.com>
This commit is contained in:
Nick Brassel 2023-11-28 07:53:43 +11:00 committed by GitHub
parent 094357c403
commit 5501e804ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1085 additions and 111 deletions

View file

@ -12,7 +12,8 @@ from pygments.token import Token
from pygments import lex
import qmk.path
from qmk.keyboard import find_keyboard_from_dir, keyboard_folder
from qmk.constants import QMK_FIRMWARE, QMK_USERSPACE, HAS_QMK_USERSPACE
from qmk.keyboard import find_keyboard_from_dir, keyboard_folder, keyboard_aliases
from qmk.errors import CppError
from qmk.info import info_json
@ -194,29 +195,38 @@ def _strip_any(keycode):
def find_keymap_from_dir(*args):
"""Returns `(keymap_name, source)` for the directory provided (or cwd if not specified).
"""
relative_path = qmk.path.under_qmk_firmware(*args)
def _impl_find_keymap_from_dir(relative_path):
if relative_path and len(relative_path.parts) > 1:
# If we're in `qmk_firmware/keyboards` and `keymaps` is in our path, try to find the keyboard name.
if relative_path.parts[0] == 'keyboards' and 'keymaps' in relative_path.parts:
current_path = Path('/'.join(relative_path.parts[1:])) # Strip 'keyboards' from the front
if relative_path and len(relative_path.parts) > 1:
# If we're in `qmk_firmware/keyboards` and `keymaps` is in our path, try to find the keyboard name.
if relative_path.parts[0] == 'keyboards' and 'keymaps' in relative_path.parts:
current_path = Path('/'.join(relative_path.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
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'
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_path.parts[0] == 'layouts' and is_keymap_dir(relative_path):
return relative_path.name, 'layouts_directory'
# If we're in `qmk_firmware/layouts` guess the name from the community keymap they're in
elif relative_path.parts[0] == 'layouts' and is_keymap_dir(relative_path):
return relative_path.name, 'layouts_directory'
# If we're in `qmk_firmware/users` guess the name from the userspace they're in
elif relative_path.parts[0] == 'users':
# Guess the keymap name based on which userspace they're in
return relative_path.parts[1], 'users_directory'
return None, None
# If we're in `qmk_firmware/users` guess the name from the userspace they're in
elif relative_path.parts[0] == 'users':
# Guess the keymap name based on which userspace they're in
return relative_path.parts[1], 'users_directory'
if HAS_QMK_USERSPACE:
name, source = _impl_find_keymap_from_dir(qmk.path.under_qmk_userspace(*args))
if name and source:
return name, source
return None, None
name, source = _impl_find_keymap_from_dir(qmk.path.under_qmk_firmware(*args))
if name and source:
return name, source
return (None, None)
def keymap_completer(prefix, action, parser, parsed_args):
@ -417,29 +427,45 @@ def locate_keymap(keyboard, keymap):
raise KeyError('Invalid keyboard: ' + repr(keyboard))
# Check the keyboard folder first, last match wins
checked_dirs = ''
keymap_path = ''
for dir in keyboard_folder(keyboard).split('/'):
if checked_dirs:
checked_dirs = '/'.join((checked_dirs, dir))
else:
checked_dirs = dir
search_dirs = [QMK_FIRMWARE]
keyboard_dirs = [keyboard_folder(keyboard)]
if HAS_QMK_USERSPACE:
# When we've got userspace, check there _last_ as we want them to override anything in the main repo.
search_dirs.append(QMK_USERSPACE)
# We also want to search for any aliases as QMK's folder structure may have changed, with an alias, but the user
# hasn't updated their keymap location yet.
keyboard_dirs.extend(keyboard_aliases(keyboard))
keyboard_dirs = list(set(keyboard_dirs))
keymap_dir = Path('keyboards') / checked_dirs / 'keymaps'
for search_dir in search_dirs:
for keyboard_dir in keyboard_dirs:
checked_dirs = ''
for dir in keyboard_dir.split('/'):
if checked_dirs:
checked_dirs = '/'.join((checked_dirs, dir))
else:
checked_dirs = dir
if (keymap_dir / keymap / 'keymap.c').exists():
keymap_path = keymap_dir / keymap / 'keymap.c'
if (keymap_dir / keymap / 'keymap.json').exists():
keymap_path = keymap_dir / keymap / 'keymap.json'
keymap_dir = Path(search_dir) / Path('keyboards') / checked_dirs / 'keymaps'
if keymap_path:
return keymap_path
if (keymap_dir / keymap / 'keymap.c').exists():
keymap_path = keymap_dir / keymap / 'keymap.c'
if (keymap_dir / keymap / 'keymap.json').exists():
keymap_path = keymap_dir / keymap / 'keymap.json'
if keymap_path:
return keymap_path
# Check community layouts as a fallback
info = info_json(keyboard)
for community_parent in Path('layouts').glob('*/'):
community_parents = list(Path('layouts').glob('*/'))
if HAS_QMK_USERSPACE and (Path(QMK_USERSPACE) / "layouts").exists():
community_parents.append(Path(QMK_USERSPACE) / "layouts")
for community_parent in community_parents:
for layout in info.get("community_layouts", []):
community_layout = community_parent / layout / keymap
if community_layout.exists():
@ -449,6 +475,16 @@ def locate_keymap(keyboard, keymap):
return community_layout / 'keymap.c'
def is_keymap_target(keyboard, keymap):
if keymap == 'all':
return True
if locate_keymap(keyboard, keymap):
return True
return False
def list_keymaps(keyboard, c=True, json=True, additional_files=None, fullpath=False):
"""List the available keymaps for a keyboard.
@ -473,26 +509,30 @@ def list_keymaps(keyboard, c=True, json=True, additional_files=None, fullpath=Fa
"""
names = set()
keyboards_dir = Path('keyboards')
kb_path = keyboards_dir / keyboard
# walk up the directory tree until keyboards_dir
# and collect all directories' name with keymap.c file in it
while kb_path != keyboards_dir:
keymaps_dir = kb_path / "keymaps"
for search_dir in [QMK_FIRMWARE, QMK_USERSPACE] if HAS_QMK_USERSPACE else [QMK_FIRMWARE]:
keyboards_dir = search_dir / Path('keyboards')
kb_path = keyboards_dir / keyboard
if keymaps_dir.is_dir():
for keymap in keymaps_dir.iterdir():
if is_keymap_dir(keymap, c, json, additional_files):
keymap = keymap if fullpath else keymap.name
names.add(keymap)
while kb_path != keyboards_dir:
keymaps_dir = kb_path / "keymaps"
if keymaps_dir.is_dir():
for keymap in keymaps_dir.iterdir():
if is_keymap_dir(keymap, c, json, additional_files):
keymap = keymap if fullpath else keymap.name
names.add(keymap)
kb_path = kb_path.parent
kb_path = kb_path.parent
# Check community layouts as a fallback
info = info_json(keyboard)
for community_parent in Path('layouts').glob('*/'):
community_parents = list(Path('layouts').glob('*/'))
if HAS_QMK_USERSPACE and (Path(QMK_USERSPACE) / "layouts").exists():
community_parents.append(Path(QMK_USERSPACE) / "layouts")
for community_parent in community_parents:
for layout in info.get("community_layouts", []):
cl_path = community_parent / layout
if cl_path.is_dir():