Make VSCode default key-bindings more HJLK friendly using Alt to alternate to them
#/usr/bin/python3 | |
import json | |
import sys | |
import os | |
import re | |
import copy | |
input = sys.argv[1] | |
if not input or not os.path.exists(input): | |
print('No such file', input) | |
sys.exit(1) | |
ALLOWED_MODIFIERS = ['shift', 'meta'] | |
ALLOWED_MODIFIERS_PER_KEY = { | |
'left': ['ctrl+shift'], | |
'right': ['ctrl+shift'], | |
'up': ['ctrl+shift'], | |
'down': ['ctrl+shift'], | |
'home': ['ctrl', 'ctrl+shift'], | |
'end': ['ctrl', 'ctrl+shift'], | |
'f3': ['ctrl', 'ctrl+shift'], | |
'z': ['ctrl', 'ctrl+shift'], | |
'x': ['ctrl'], | |
'c': ['ctrl'], | |
'v': ['ctrl'], | |
'f': ['ctrl'], | |
} | |
MODIFIER_TRANSLATIONS = { | |
'left': { 'ctrl+shift': 'shift' }, | |
'right': { 'ctrl+shift': 'shift' }, | |
'pagedown': { None: 'ctrl' }, | |
'pageup': { None: 'ctrl' }, | |
'z': { 'ctrl': None, 'ctrl+shift': None }, | |
'x': { 'ctrl': None }, | |
'c': { 'ctrl': None }, | |
'v': { 'ctrl': None }, | |
'f': { 'ctrl': None }, | |
} | |
MODIFIER_KEY_TRANSLATIONS = { | |
'up': { None: 'k', 'ctrl': None }, | |
'down': { None: 'j', 'ctrl': None }, | |
'left': { None: 'h', 'ctrl': 'b', 'ctrl+shift': 'b' }, | |
'right': { None: 'l', 'ctrl': 'e', 'ctrl+shift': 'e' }, | |
'pageup': { None: 'b', 'shift': 'u', 'ctrl': None, 'ctrl+shift': None }, | |
'pagedown': { None: 'f', 'ctrl': None, 'ctrl+shift': None }, | |
'home': { None: '1' }, | |
'end': { None: ['0', '4'] }, # 4 matches '$' in most layouts | |
'f3': { None: 'n' }, | |
'z': { None: 'u', 'ctrl+shift': ['ctrl+r', 'shift+r'] }, | |
'x': { 'ctrl': 'd' }, | |
'c': { 'ctrl': 'y' }, | |
'v': { 'ctrl': 'p' }, | |
'f': { 'ctrl': '[Slash]' }, | |
} | |
SCAN_CODE_TRANSLATIONS = { | |
'[ArrowLeft]': 'left', | |
'[ArrowUp]': 'arrow', | |
'[ArrowRight]': 'right', | |
'[ArrowDown]': 'down', | |
'[PageUp]': 'pageup', | |
'[PageDown]': 'pagedown', | |
'[End]': 'end', | |
'[Home]': 'home', | |
} | |
HADCODED_EXTRAS = [ | |
# Add support for Alt+Shift+{w,e,b} to move by white-spaces | |
{ 'key': 'alt+j', 'command': 'workbench.action.quickOpenSelectNext', 'when': 'inQuickOpen' }, | |
{ 'key': 'alt+k', 'command': 'workbench.action.quickOpenSelectPrevious', 'when': 'inQuickOpen' }, | |
{ 'key': 'alt+w', 'command': 'cursorWordStartRight', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+shift+w', 'command': 'cursorWordStartRightSelect', 'when': 'textInputFocus' }, | |
# FIXME: Use 'by': 'halfPage' once we have it | |
{ 'key': 'alt+u', 'variants': ['ctrl'], 'command': 'cursorMove', 'args': {'to': 'up', 'by': 'line', 'value': 20 }, 'when': 'textInputFocus' }, | |
{ 'key': 'alt+u', 'variants': ['shift'], 'command': 'cursorMove', 'args': {'to': 'up', 'by': 'line', 'value': 20, 'select': True }, 'when': 'textInputFocus' }, | |
{ 'key': 'alt+d', 'variants': ['ctrl'], 'command': 'cursorMove', 'args': {'to': 'down', 'by': 'line', 'value': 20 }, 'when': 'textInputFocus' }, | |
{ 'key': 'alt+d', 'variants': ['shift'], 'command': 'cursorMove', 'args': {'to': 'down', 'by': 'line', 'value': 20, 'select': True }, 'when': 'textInputFocus' }, | |
{ 'key': 'alt+y', 'variants': ['ctrl', 'shift'], 'command': 'scrollLineUp', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+e', 'variants': ['ctrl'], 'command': 'scrollLineDown', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+i', 'variants': ['ctrl', 'shift'], 'command': 'workbench.action.navigateToLastEditLocation', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+o', 'variants': ['ctrl', 'shift'], 'command': 'workbench.action.navigateForward', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+g alt+g', 'command': 'cursorTop', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+g alt+shift+g', 'command': 'cursorTopSelect', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+shift+g', 'command': 'cursorBottom', 'when': 'textInputFocus' }, | |
{ 'key': 'alt+ctrl+shift+g', 'command': 'cursorBottomSelect', 'when': 'textInputFocus' }, | |
# FIXME: use [Percent] once defined | |
{ 'key': 'alt+shift+5', 'command': 'editor.action.jumpToBracket', 'when': 'textInputFocus' }, | |
] | |
def arrow_to_hjkl(arrow, modifier=None): | |
arrow = SCAN_CODE_TRANSLATIONS.get(arrow, arrow) | |
if arrow in MODIFIER_KEY_TRANSLATIONS.keys(): | |
key_translations = MODIFIER_KEY_TRANSLATIONS.get(arrow, {}) | |
return key_translations.get(modifier, key_translations.get(None)) | |
print('// These keybindings are auto-generated with',sys.argv[0]) | |
with open(input) as f: | |
input_str = re.sub(r'\\\n', '', f.read()) | |
input_str = re.sub(r'//.*\n', '\n', input_str) | |
data = json.loads(input_str) | |
for binding in data: | |
translations = '|'.join(MODIFIER_KEY_TRANSLATIONS.keys()) | |
match = re.match('^((shift|meta|ctrl|ctrl\+shift)\+)?({})'.format(translations), | |
binding['key']) | |
if not match: | |
continue | |
# print (binding) | |
modifier = match.group(2) | |
key = match.group(3) | |
new_keys = arrow_to_hjkl(key, modifier) | |
if not new_keys: | |
continue | |
if not isinstance(new_keys, list): | |
new_keys = [new_keys] | |
for new_key in new_keys: | |
new_binding = copy.copy(binding) | |
new_binding['key'] = 'alt+' | |
if not modifier or modifier in ALLOWED_MODIFIERS or modifier in ALLOWED_MODIFIERS_PER_KEY.get(key, []): | |
if key in MODIFIER_TRANSLATIONS.keys(): | |
modifier = MODIFIER_TRANSLATIONS.get(key, {}).get(modifier, modifier) | |
if modifier: | |
new_binding['key'] += '{}+'.format(modifier) | |
new_binding['key'] += '{}'.format(new_key) | |
if new_binding['key'] != binding['key']: | |
print('{},'.format(json.dumps(new_binding))) | |
# else: | |
# print('NOTCHANGED: {},'.format(json.dumps(new_binding))) | |
print('// Hardcoded keybindings') | |
for binding in HADCODED_EXTRAS: | |
variants = binding.get('variants', None) | |
if variants: | |
binding = copy.copy(binding) | |
del binding['variants'] | |
for variant in variants: | |
variant_binding = copy.copy(binding) | |
variant_binding['key'] = '{}+{}'.format(variant, binding['key']) | |
print('{},'.format(json.dumps(variant_binding))) | |
else: | |
print('{},'.format(json.dumps(binding))) | |
print('// End of generated keybindings') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Thanks