Last active
December 9, 2020 09:22
-
-
Save 3v1n0/f5f05005811669d81155abe0826477c8 to your computer and use it in GitHub Desktop.
Make VSCode default key-bindings more HJLK friendly using Alt to alternate to them
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/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
Thanks