Add support for tab completion (#12411)
* Add support for tab completion * make flake8 happy * Add documentation
This commit is contained in:
parent
b33e6793de
commit
588bcdc8ca
@ -29,6 +29,7 @@
|
|||||||
* [Overview](cli.md)
|
* [Overview](cli.md)
|
||||||
* [Configuration](cli_configuration.md)
|
* [Configuration](cli_configuration.md)
|
||||||
* [Commands](cli_commands.md)
|
* [Commands](cli_commands.md)
|
||||||
|
* [Tab Completion](cli_tab_complete.md)
|
||||||
|
|
||||||
* Using QMK
|
* Using QMK
|
||||||
* Guides
|
* Guides
|
||||||
|
27
docs/cli_tab_complete.md
Normal file
27
docs/cli_tab_complete.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Tab Completion for QMK
|
||||||
|
|
||||||
|
If you are using Bash 4.2 or later, Zsh, or FiSH you can enable Tab Completion for the QMK CLI. This will let you tab complete the names of flags, keyboards, files, and other `qmk` options.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
There are several ways you can setup tab completion.
|
||||||
|
|
||||||
|
### For Your User Only
|
||||||
|
|
||||||
|
Add this to the end of your `.profile` or `.bashrc`:
|
||||||
|
|
||||||
|
source ~/qmk_firmware/util/qmk_tab_complete.sh
|
||||||
|
|
||||||
|
If you put `qmk_firmware` into another location you will need to adjust this path.
|
||||||
|
|
||||||
|
### System Wide Symlink
|
||||||
|
|
||||||
|
If you want the tab completion available to all users of the system you can add a symlink to the `qmk_tab_complete.sh` script:
|
||||||
|
|
||||||
|
`ln -s ~/qmk_firmware/util/qmk_tab_complete.sh /etc/profile.d/qmk_tab_complete.sh`
|
||||||
|
|
||||||
|
### System Wide Copy
|
||||||
|
|
||||||
|
In some cases a symlink may not work. Instead you can copy the file directly into place. Be aware that updates to the tab complete script may happen from time to time, you will want to recopy the file periodically.
|
||||||
|
|
||||||
|
cp util/qmk_tab_complete.sh /etc/profile.d
|
@ -4,7 +4,7 @@ We list each subcommand here explicitly because all the reliable ways of searchi
|
|||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli, __VERSION__
|
||||||
|
|
||||||
from . import c2json
|
from . import c2json
|
||||||
from . import cformat
|
from . import cformat
|
||||||
@ -47,5 +47,15 @@ from . import pytest
|
|||||||
# void: 3.9
|
# void: 3.9
|
||||||
|
|
||||||
if sys.version_info[0] != 3 or sys.version_info[1] < 7:
|
if sys.version_info[0] != 3 or sys.version_info[1] < 7:
|
||||||
cli.log.error('Your Python is too old! Please upgrade to Python 3.7 or later.')
|
print('Error: Your Python is too old! Please upgrade to Python 3.7 or later.')
|
||||||
|
exit(127)
|
||||||
|
|
||||||
|
milc_version = __VERSION__.split('.')
|
||||||
|
|
||||||
|
if int(milc_version[0]) < 2 and int(milc_version[1]) < 3:
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
requirements = Path('requirements.txt').resolve()
|
||||||
|
|
||||||
|
print(f'Your MILC library is too old! Please upgrade: python3 -m pip install -U -r {str(requirements)}')
|
||||||
exit(127)
|
exit(127)
|
||||||
|
@ -2,20 +2,21 @@
|
|||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from argcomplete.completers import FilesCompleter
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
import qmk.keymap
|
import qmk.keymap
|
||||||
import qmk.path
|
import qmk.path
|
||||||
from qmk.json_encoders import InfoJSONEncoder
|
from qmk.json_encoders import InfoJSONEncoder
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('--no-cpp', arg_only=True, action='store_false', help='Do not use \'cpp\' on keymap.c')
|
@cli.argument('--no-cpp', arg_only=True, action='store_false', help='Do not use \'cpp\' on keymap.c')
|
||||||
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
||||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||||
@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, required=True, help='The keyboard\'s name')
|
@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, required=True, help='The keyboard\'s name')
|
||||||
@cli.argument('-km', '--keymap', arg_only=True, required=True, help='The keymap\'s name')
|
@cli.argument('-km', '--keymap', arg_only=True, required=True, help='The keymap\'s name')
|
||||||
@cli.argument('filename', arg_only=True, help='keymap.c file')
|
@cli.argument('filename', arg_only=True, completer=FilesCompleter('.c'), help='keymap.c file')
|
||||||
@cli.subcommand('Creates a keymap.json from a keymap.c file.')
|
@cli.subcommand('Creates a keymap.json from a keymap.c file.')
|
||||||
def c2json(cli):
|
def c2json(cli):
|
||||||
"""Generate a keymap.json from a keymap.c file.
|
"""Generate a keymap.json from a keymap.c file.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
from shutil import which
|
from shutil import which
|
||||||
|
|
||||||
|
from argcomplete.completers import FilesCompleter
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
from qmk.path import normpath
|
from qmk.path import normpath
|
||||||
@ -33,7 +34,7 @@ def cformat_run(files, all_files):
|
|||||||
|
|
||||||
@cli.argument('-a', '--all-files', arg_only=True, action='store_true', help='Format all core files.')
|
@cli.argument('-a', '--all-files', arg_only=True, action='store_true', help='Format all core files.')
|
||||||
@cli.argument('-b', '--base-branch', default='origin/master', help='Branch to compare to diffs to.')
|
@cli.argument('-b', '--base-branch', default='origin/master', help='Branch to compare to diffs to.')
|
||||||
@cli.argument('files', nargs='*', arg_only=True, help='Filename(s) to format.')
|
@cli.argument('files', nargs='*', arg_only=True, completer=FilesCompleter('.c'), help='Filename(s) to format.')
|
||||||
@cli.subcommand("Format C code according to QMK's style.", hidden=False if cli.config.user.developer else True)
|
@cli.subcommand("Format C code according to QMK's style.", hidden=False if cli.config.user.developer else True)
|
||||||
def cformat(cli):
|
def cformat(cli):
|
||||||
"""Format C code according to QMK's style.
|
"""Format C code according to QMK's style.
|
||||||
|
@ -2,17 +2,19 @@
|
|||||||
|
|
||||||
You can compile a keymap already in the repo or using a QMK Configurator export.
|
You can compile a keymap already in the repo or using a QMK Configurator export.
|
||||||
"""
|
"""
|
||||||
|
from argcomplete.completers import FilesCompleter
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
import qmk.path
|
import qmk.path
|
||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
|
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
|
from qmk.keymap import keymap_completer
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), help='The configurator export to compile')
|
@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='The configurator export to compile')
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
|
||||||
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
|
@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
|
||||||
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
|
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
|
||||||
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
|
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
|
||||||
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
|
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
|
||||||
|
@ -4,12 +4,13 @@ You can compile a keymap already in the repo or using a QMK Configurator export.
|
|||||||
A bootloader must be specified.
|
A bootloader must be specified.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from argcomplete.completers import FilesCompleter
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
import qmk.path
|
import qmk.path
|
||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
|
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
|
|
||||||
|
|
||||||
def print_bootloader_help():
|
def print_bootloader_help():
|
||||||
@ -30,11 +31,11 @@ def print_bootloader_help():
|
|||||||
cli.echo('For more info, visit https://docs.qmk.fm/#/flashing')
|
cli.echo('For more info, visit https://docs.qmk.fm/#/flashing')
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), help='The configurator export JSON to compile.')
|
@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='The configurator export JSON to compile.')
|
||||||
@cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
|
@cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
|
||||||
@cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
|
@cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
|
||||||
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
|
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
|
||||||
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
|
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
|
||||||
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
|
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
|
||||||
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
|
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
|
||||||
|
@ -8,7 +8,7 @@ from milc import cli
|
|||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
from qmk.json_schema import json_load
|
from qmk.json_schema import json_load
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
from qmk.path import is_keyboard, normpath
|
from qmk.path import is_keyboard, normpath
|
||||||
|
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ def matrix_pins(matrix_pins):
|
|||||||
|
|
||||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.')
|
||||||
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
|
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
@automagic_keymap
|
@automagic_keymap
|
||||||
|
@ -6,11 +6,12 @@ from milc import cli
|
|||||||
from qmk.decorators import automagic_keyboard
|
from qmk.decorators import automagic_keyboard
|
||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
from qmk.path import is_keyboard, normpath
|
from qmk.path import is_keyboard, normpath
|
||||||
|
from qmk.keyboard import keyboard_completer
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||||
@cli.argument('-kb', '--keyboard', help='Keyboard to generate LUFA Keyboard.h for.')
|
@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='Keyboard to generate LUFA Keyboard.h for.')
|
||||||
@cli.subcommand('Used by the make system to generate LUFA Keyboard.h from info.json', hidden=True)
|
@cli.subcommand('Used by the make system to generate LUFA Keyboard.h from info.json', hidden=True)
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
def generate_dfu_header(cli):
|
def generate_dfu_header(cli):
|
||||||
|
@ -11,7 +11,7 @@ from qmk.decorators import automagic_keyboard, automagic_keymap
|
|||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
from qmk.json_encoders import InfoJSONEncoder
|
from qmk.json_encoders import InfoJSONEncoder
|
||||||
from qmk.json_schema import load_jsonschema
|
from qmk.json_schema import load_jsonschema
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
from qmk.path import is_keyboard
|
from qmk.path import is_keyboard
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ def strip_info_json(kb_info_json):
|
|||||||
return validator(kb_info_json)
|
return validator(kb_info_json)
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to show info for.')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.')
|
||||||
@cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
|
@cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
|
||||||
@cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True)
|
@cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True)
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
|
@ -5,7 +5,7 @@ from milc import cli
|
|||||||
from qmk.constants import COL_LETTERS, ROW_LETTERS
|
from qmk.constants import COL_LETTERS, ROW_LETTERS
|
||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
from qmk.path import is_keyboard, normpath
|
from qmk.path import is_keyboard, normpath
|
||||||
|
|
||||||
usb_properties = {
|
usb_properties = {
|
||||||
@ -17,7 +17,7 @@ usb_properties = {
|
|||||||
|
|
||||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.')
|
||||||
@cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True)
|
@cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True)
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
@automagic_keymap
|
@automagic_keymap
|
||||||
|
@ -8,7 +8,7 @@ from milc import cli
|
|||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
from qmk.json_schema import json_load
|
from qmk.json_schema import json_load
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
from qmk.path import is_keyboard, normpath
|
from qmk.path import is_keyboard, normpath
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict):
|
|||||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||||
@cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode")
|
@cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode")
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.')
|
||||||
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
|
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
@automagic_keymap
|
@automagic_keymap
|
||||||
|
@ -10,7 +10,7 @@ from milc import cli
|
|||||||
from qmk.json_encoders import InfoJSONEncoder
|
from qmk.json_encoders import InfoJSONEncoder
|
||||||
from qmk.constants import COL_LETTERS, ROW_LETTERS
|
from qmk.constants import COL_LETTERS, ROW_LETTERS
|
||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.keyboard import keyboard_folder, render_layouts, render_layout
|
from qmk.keyboard import keyboard_completer, keyboard_folder, render_layouts, render_layout
|
||||||
from qmk.keymap import locate_keymap
|
from qmk.keymap import locate_keymap
|
||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
from qmk.path import is_keyboard
|
from qmk.path import is_keyboard
|
||||||
@ -124,7 +124,7 @@ def print_text_output(kb_info_json):
|
|||||||
show_keymap(kb_info_json, False)
|
show_keymap(kb_info_json, False)
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to show info for.')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.')
|
||||||
@cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
|
@cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
|
||||||
@cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.')
|
@cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.')
|
||||||
@cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.')
|
@cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.')
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from argcomplete.completers import FilesCompleter
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
import qmk.keymap
|
import qmk.keymap
|
||||||
@ -10,7 +11,7 @@ import qmk.path
|
|||||||
|
|
||||||
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
||||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||||
@cli.argument('filename', type=qmk.path.FileType('r'), arg_only=True, help='Configurator JSON file')
|
@cli.argument('filename', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
|
||||||
@cli.subcommand('Creates a keymap.c from a QMK Configurator export.')
|
@cli.subcommand('Creates a keymap.c from a QMK Configurator export.')
|
||||||
def json2c(cli):
|
def json2c(cli):
|
||||||
"""Generate a keymap.c from a configurator export.
|
"""Generate a keymap.c from a configurator export.
|
||||||
|
@ -4,6 +4,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from argcomplete.completers import FilesCompleter
|
||||||
from milc import cli
|
from milc import cli
|
||||||
from kle2xy import KLE2xy
|
from kle2xy import KLE2xy
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ from qmk.converter import kle2qmk
|
|||||||
from qmk.json_encoders import InfoJSONEncoder
|
from qmk.json_encoders import InfoJSONEncoder
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('filename', help='The KLE raw txt to convert')
|
@cli.argument('filename', completer=FilesCompleter('.json'), help='The KLE raw txt to convert')
|
||||||
@cli.argument('-f', '--force', action='store_true', help='Flag to overwrite current info.json')
|
@cli.argument('-f', '--force', action='store_true', help='Flag to overwrite current info.json')
|
||||||
@cli.subcommand('Convert a KLE layout to a Configurator JSON', hidden=False if cli.config.user.developer else True)
|
@cli.subcommand('Convert a KLE layout to a Configurator JSON', hidden=False if cli.config.user.developer else True)
|
||||||
def kle2json(cli):
|
def kle2json(cli):
|
||||||
|
@ -4,12 +4,13 @@ from milc import cli
|
|||||||
|
|
||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
|
from qmk.keyboard import keyboard_completer
|
||||||
from qmk.keymap import locate_keymap
|
from qmk.keymap import locate_keymap
|
||||||
from qmk.path import is_keyboard, keyboard
|
from qmk.path import is_keyboard, keyboard
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('--strict', action='store_true', help='Treat warnings as errors.')
|
@cli.argument('--strict', action='store_true', help='Treat warnings as errors.')
|
||||||
@cli.argument('-kb', '--keyboard', help='The keyboard to check.')
|
@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='The keyboard to check.')
|
||||||
@cli.argument('-km', '--keymap', help='The keymap to check.')
|
@cli.argument('-km', '--keymap', help='The keymap to check.')
|
||||||
@cli.subcommand('Check keyboard and keymap for common mistakes.')
|
@cli.subcommand('Check keyboard and keymap for common mistakes.')
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
|
@ -4,10 +4,10 @@ from milc import cli
|
|||||||
|
|
||||||
import qmk.keymap
|
import qmk.keymap
|
||||||
from qmk.decorators import automagic_keyboard
|
from qmk.decorators import automagic_keyboard
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
|
|
||||||
|
|
||||||
@cli.argument("-kb", "--keyboard", type=keyboard_folder, help="Specify keyboard name. Example: 1upkeyboards/1up60hse")
|
@cli.argument("-kb", "--keyboard", type=keyboard_folder, completer=keyboard_completer, help="Specify keyboard name. Example: 1upkeyboards/1up60hse")
|
||||||
@cli.subcommand("List the keymaps for a specific keyboard")
|
@cli.subcommand("List the keymaps for a specific keyboard")
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
def list_keymaps(cli):
|
def list_keymaps(cli):
|
||||||
|
@ -5,11 +5,11 @@ from pathlib import Path
|
|||||||
|
|
||||||
import qmk.path
|
import qmk.path
|
||||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||||
from qmk.keyboard import keyboard_folder
|
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Specify keyboard name. Example: 1upkeyboards/1up60hse')
|
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Specify keyboard name. Example: 1upkeyboards/1up60hse')
|
||||||
@cli.argument('-km', '--keymap', help='Specify the name for the new keymap directory')
|
@cli.argument('-km', '--keymap', help='Specify the name for the new keymap directory')
|
||||||
@cli.subcommand('Creates a new keymap for the keyboard of your choosing')
|
@cli.subcommand('Creates a new keymap for the keyboard of your choosing')
|
||||||
@automagic_keyboard
|
@automagic_keyboard
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
"""Helpful decorators that subcommands can use.
|
"""Helpful decorators that subcommands can use.
|
||||||
"""
|
"""
|
||||||
import functools
|
import functools
|
||||||
from pathlib import Path
|
|
||||||
from time import monotonic
|
from time import monotonic
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
from qmk.keymap import is_keymap_dir
|
from qmk.keyboard import find_keyboard_from_dir
|
||||||
from qmk.path import is_keyboard, under_qmk_firmware
|
from qmk.keymap import find_keymap_from_dir
|
||||||
|
|
||||||
|
|
||||||
def automagic_keyboard(func):
|
def automagic_keyboard(func):
|
||||||
@ -17,27 +16,13 @@ def automagic_keyboard(func):
|
|||||||
"""
|
"""
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
# Check to make sure their copy of MILC supports config_source
|
|
||||||
if not hasattr(cli, 'config_source'):
|
|
||||||
cli.log.error("This subcommand requires a newer version of the QMK CLI. Please upgrade using `pip3 install --upgrade qmk` or your package manager.")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Ensure that `--keyboard` was not passed and CWD is under `qmk_firmware/keyboards`
|
# Ensure that `--keyboard` was not passed and CWD is under `qmk_firmware/keyboards`
|
||||||
if cli.config_source[cli._entrypoint.__name__]['keyboard'] != 'argument':
|
if cli.config_source[cli._entrypoint.__name__]['keyboard'] != 'argument':
|
||||||
relative_cwd = under_qmk_firmware()
|
keyboard = find_keyboard_from_dir()
|
||||||
|
|
||||||
if relative_cwd and len(relative_cwd.parts) > 1 and relative_cwd.parts[0] == 'keyboards':
|
if keyboard:
|
||||||
# Attempt to extract the keyboard name from the current directory
|
cli.config[cli._entrypoint.__name__]['keyboard'] = keyboard
|
||||||
current_path = Path('/'.join(relative_cwd.parts[1:]))
|
cli.config_source[cli._entrypoint.__name__]['keyboard'] = 'keyboard_directory'
|
||||||
|
|
||||||
if 'keymaps' in current_path.parts:
|
|
||||||
# Strip current_path of anything after `keymaps`
|
|
||||||
keymap_index = len(current_path.parts) - current_path.parts.index('keymaps') - 1
|
|
||||||
current_path = current_path.parents[keymap_index]
|
|
||||||
|
|
||||||
if is_keyboard(current_path):
|
|
||||||
cli.config[cli._entrypoint.__name__]['keyboard'] = str(current_path)
|
|
||||||
cli.config_source[cli._entrypoint.__name__]['keyboard'] = 'keyboard_directory'
|
|
||||||
|
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
@ -51,36 +36,13 @@ def automagic_keymap(func):
|
|||||||
"""
|
"""
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
# Check to make sure their copy of MILC supports config_source
|
|
||||||
if not hasattr(cli, 'config_source'):
|
|
||||||
cli.log.error("This subcommand requires a newer version of the QMK CLI. Please upgrade using `pip3 install --upgrade qmk` or your package manager.")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Ensure that `--keymap` was not passed and that we're under `qmk_firmware`
|
# Ensure that `--keymap` was not passed and that we're under `qmk_firmware`
|
||||||
if cli.config_source[cli._entrypoint.__name__]['keymap'] != 'argument':
|
if cli.config_source[cli._entrypoint.__name__]['keymap'] != 'argument':
|
||||||
relative_cwd = under_qmk_firmware()
|
keymap_name, keymap_type = find_keymap_from_dir()
|
||||||
|
|
||||||
if relative_cwd and len(relative_cwd.parts) > 1:
|
if keymap_name:
|
||||||
# If we're in `qmk_firmware/keyboards` and `keymaps` is in our path, try to find the keyboard name.
|
cli.config[cli._entrypoint.__name__]['keymap'] = keymap_name
|
||||||
if relative_cwd.parts[0] == 'keyboards' and 'keymaps' in relative_cwd.parts:
|
cli.config_source[cli._entrypoint.__name__]['keymap'] = keymap_type
|
||||||
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
|
|
||||||
cli.config[cli._entrypoint.__name__]['keymap'] = current_path.name
|
|
||||||
cli.config_source[cli._entrypoint.__name__]['keymap'] = '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):
|
|
||||||
cli.config[cli._entrypoint.__name__]['keymap'] = relative_cwd.name
|
|
||||||
cli.config_source[cli._entrypoint.__name__]['keymap'] = '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
|
|
||||||
cli.config[cli._entrypoint.__name__]['keymap'] = relative_cwd.parts[1]
|
|
||||||
cli.config_source[cli._entrypoint.__name__]['keymap'] = 'users_directory'
|
|
||||||
|
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ from glob import glob
|
|||||||
from qmk.c_parse import parse_config_h_file
|
from qmk.c_parse import parse_config_h_file
|
||||||
from qmk.json_schema import json_load
|
from qmk.json_schema import json_load
|
||||||
from qmk.makefile import parse_rules_mk_file
|
from qmk.makefile import parse_rules_mk_file
|
||||||
from qmk.path import is_keyboard
|
from qmk.path import is_keyboard, under_qmk_firmware
|
||||||
|
|
||||||
BOX_DRAWING_CHARACTERS = {
|
BOX_DRAWING_CHARACTERS = {
|
||||||
"unicode": {
|
"unicode": {
|
||||||
@ -33,6 +33,24 @@ BOX_DRAWING_CHARACTERS = {
|
|||||||
base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep
|
base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep
|
||||||
|
|
||||||
|
|
||||||
|
def find_keyboard_from_dir():
|
||||||
|
"""Returns a keyboard name based on the user's current directory.
|
||||||
|
"""
|
||||||
|
relative_cwd = under_qmk_firmware()
|
||||||
|
|
||||||
|
if relative_cwd and len(relative_cwd.parts) > 1 and relative_cwd.parts[0] == 'keyboards':
|
||||||
|
# Attempt to extract the keyboard name from the current directory
|
||||||
|
current_path = Path('/'.join(relative_cwd.parts[1:]))
|
||||||
|
|
||||||
|
if 'keymaps' in current_path.parts:
|
||||||
|
# Strip current_path of anything after `keymaps`
|
||||||
|
keymap_index = len(current_path.parts) - current_path.parts.index('keymaps') - 1
|
||||||
|
current_path = current_path.parents[keymap_index]
|
||||||
|
|
||||||
|
if is_keyboard(current_path):
|
||||||
|
return str(current_path)
|
||||||
|
|
||||||
|
|
||||||
def keyboard_folder(keyboard):
|
def keyboard_folder(keyboard):
|
||||||
"""Returns the actual keyboard folder.
|
"""Returns the actual keyboard folder.
|
||||||
|
|
||||||
@ -61,6 +79,12 @@ def _find_name(path):
|
|||||||
return path.replace(base_path, "").replace(os.path.sep + "rules.mk", "")
|
return path.replace(base_path, "").replace(os.path.sep + "rules.mk", "")
|
||||||
|
|
||||||
|
|
||||||
|
def keyboard_completer(prefix, action, parser, parsed_args):
|
||||||
|
"""Returns a list of keyboards for tab completion.
|
||||||
|
"""
|
||||||
|
return list_keyboards()
|
||||||
|
|
||||||
|
|
||||||
def list_keyboards():
|
def list_keyboards():
|
||||||
"""Returns a list of all keyboards.
|
"""Returns a list of all keyboards.
|
||||||
"""
|
"""
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
"""Functions that help you work with QMK keymaps.
|
"""Functions that help you work with QMK keymaps.
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
|
||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import argcomplete
|
||||||
|
from milc import cli
|
||||||
from pygments.lexers.c_cpp import CLexer
|
from pygments.lexers.c_cpp import CLexer
|
||||||
from pygments.token import Token
|
from pygments.token import Token
|
||||||
from pygments import lex
|
from pygments import lex
|
||||||
|
|
||||||
from milc import cli
|
|
||||||
|
|
||||||
from qmk.keyboard import rules_mk
|
|
||||||
import qmk.path
|
import qmk.path
|
||||||
import qmk.commands
|
import qmk.commands
|
||||||
|
from qmk.keyboard import find_keyboard_from_dir, rules_mk
|
||||||
|
|
||||||
# The `keymap.c` template to use when a keyboard doesn't have its own
|
# The `keymap.c` template to use when a keyboard doesn't have its own
|
||||||
DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H
|
DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H
|
||||||
@ -74,6 +74,54 @@ def _strip_any(keycode):
|
|||||||
return 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):
|
def is_keymap_dir(keymap, c=True, json=True, additional_files=None):
|
||||||
"""Return True if Path object `keymap` has a keymap file inside.
|
"""Return True if Path object `keymap` has a keymap file inside.
|
||||||
|
|
||||||
|
@ -5,5 +5,5 @@ colorama
|
|||||||
dotty-dict
|
dotty-dict
|
||||||
hjson
|
hjson
|
||||||
jsonschema>=3
|
jsonschema>=3
|
||||||
milc>=1.1.0
|
milc>=1.3.0
|
||||||
pygments
|
pygments
|
||||||
|
2
util/qmk_tab_complete.sh
Normal file
2
util/qmk_tab_complete.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Register qmk with tab completion
|
||||||
|
eval "$(register-python-argcomplete --no-defaults qmk)"
|
Loading…
Reference in New Issue
Block a user