talon-scripts/community/apps/emacs/emacs_commands.py
2025-08-19 08:06:37 -04:00

72 lines
2.0 KiB
Python

import csv
from dataclasses import dataclass
from pathlib import Path
from typing import NamedTuple, Optional
from talon import Context, Module, actions, app, resource
mod = Module()
mod.list("emacs_command", desc="Emacs commands")
ctx = Context()
class Command(NamedTuple):
name: str
keys: Optional[str] = None
short: Optional[str] = None
spoken: Optional[str] = None
# Maps command name to Command.
emacs_commands = {}
@mod.action_class
class Actions:
def emacs_command_keybinding(command_name: str) -> Optional[str]:
"Looks up the keybinding for command_name in emacs_commands.csv."
return emacs_commands.get(command_name, Command(command_name)).keys
def emacs_command_short_form(command_name: str) -> Optional[str]:
"Looks up the short form for command_name in emacs_commands.csv."
return emacs_commands.get(command_name, Command(command_name)).short
@resource.watch("emacs_commands.csv")
def load_commands(f):
rows = list(csv.reader(f))
# Check headers
assert rows[0] == ["Command", " Key binding", " Short form", " Spoken form"]
commands = []
for row in rows[1:]:
if 0 == len(row):
continue
if len(row) > 4:
print(
f"emacs_commands.csv: More than four values in row: {row}. "
+ " Ignoring the extras"
)
name, keys, short, spoken = (
[x.strip() or None for x in row] + [None, None, None]
)[:4]
commands.append(Command(name=name, keys=keys, short=short, spoken=spoken))
# Update global command info.
global emacs_commands
emacs_commands = {c.name: c for c in commands}
# Generate spoken forms and apply overrides.
try:
command_list = actions.user.create_spoken_forms_from_list(
[c.name for c in commands], generate_subsequences=False
)
except:
pass
else:
for c in commands:
if c.spoken:
command_list[c.spoken] = c.name
ctx.lists["self.emacs_command"] = command_list