107 lines
2.6 KiB
Python
107 lines
2.6 KiB
Python
from fide import *
|
|
from typing import List, Dict, Callable
|
|
from dataclasses import dataclass, field
|
|
|
|
@dataclass(slots=True, frozen=True)
|
|
class Keybinding:
|
|
key: str
|
|
modifiers: int
|
|
|
|
@dataclass(slots=True)
|
|
class Keymap:
|
|
name: str
|
|
pinned: bool
|
|
fallthrough: bool
|
|
pop_not_found: bool
|
|
mapping: Dict[[int,str],Callable] = field(default_factory=dict)
|
|
|
|
|
|
global keymappings
|
|
global keymap_stack
|
|
global reverse_binding
|
|
|
|
def modsym_to_flag(sym: str):
|
|
match sym:
|
|
case 'S': return 1
|
|
case 'C': return 64
|
|
case 'RC': return 128
|
|
case 'A': return 256
|
|
case 'RA': return 512
|
|
case 'M': return 1024
|
|
# TODO Get which keycode these are
|
|
case 'right meta':
|
|
return 'RM'
|
|
case 'right shift':
|
|
return 'RS'
|
|
return None
|
|
|
|
def symbol_to_num(sym: str):
|
|
match sym:
|
|
case '!': return '1'
|
|
case '@': return '2'
|
|
case '#': return '3'
|
|
case '$': return '4'
|
|
case '%': return '5'
|
|
case '^': return '6'
|
|
case '&': return '7'
|
|
case '*': return '8'
|
|
case '(': return '9'
|
|
case ')': return '0'
|
|
# TODO Get which keycode these are
|
|
return sym
|
|
|
|
def parse_keybinding(keybinding: str) -> str:
|
|
keys = keybinding.replace(' ', '').split('-')
|
|
if not keys:
|
|
# TODO: We need to return some kind of error
|
|
return None
|
|
keys_len = len(keys)
|
|
if keys_len > 1: # We have modifiers
|
|
modifiers = 0
|
|
for i in range(keys_len - 1):
|
|
flag = modsym_to_flag(keys[i])
|
|
if flag:
|
|
modifiers |= flag
|
|
else:
|
|
# TODO: Also throw some kind of parsing error
|
|
return None
|
|
else:
|
|
modifiers = 0
|
|
if len(keys[-1]) > 1: # We have a multi-stroke keybinding, we don't handle that yet
|
|
key = keys[-1]
|
|
else:
|
|
key = keys[-1][0]
|
|
if key.isupper():
|
|
modifiers |= 1
|
|
key = key.lower()
|
|
if not key.isalnum():
|
|
modifiers |= 1
|
|
key = symbol_to_num(key)
|
|
|
|
return Keybinding(key, modifiers)
|
|
|
|
|
|
keymap_stack = [
|
|
Keymap('insert', pinned=True, fallthrough=True, pop_not_found=False),
|
|
Keymap('normal', pinned=True, fallthrough=False, pop_not_found=False),
|
|
]
|
|
|
|
keymappings = {
|
|
'insert': keymap_stack[0],
|
|
'normal': keymap_stack[1],
|
|
}
|
|
|
|
# Do we even need this?
|
|
reverse_binding = {}
|
|
|
|
def kb(mode: str, binding: str, f: Callable):
|
|
keybinding = parse_keybinding(binding)
|
|
keymappings[mode].mapping[keybinding] = f
|
|
reverse_binding[keybinding] = binding
|
|
|
|
def keymap_push(keymap: Keymap):
|
|
keymap_stack.append(keymap)
|
|
|
|
def keymap_pop():
|
|
keymap_stack.pop()
|