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 passthrough: bool pop_not_found: bool mapping: Dict[[int,str],Callable] = field(default_factory=dict) global keymappings global keymap_stack 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(): key = symbol_to_num(key) return Keybinding(key, modifiers) keymap_stack = [ Keymap('insert', pinned=True, passthrough=False, pop_not_found=False), Keymap('normal', pinned=True, passthrough=False, pop_not_found=False), ] keymappings = { 'insert': keymap_stack[0], 'normal': keymap_stack[1], } def kb(mode: str, binding: str, f: Callable): b = parse_keybinding(binding) keymappings[mode].mapping[b] = f def keymap_push(keymap: Keymap): keymap_stack.append(keymap_push) def keymap_pop(): keymap_stack.pop()