dotfiles/talon/cursorless-talon/src/actions/actions.py

142 lines
4.5 KiB
Python

from typing import Callable, Union
from talon import Module, actions
from ..targets.target_types import (
CursorlessDestination,
CursorlessExplicitTarget,
CursorlessTarget,
ImplicitDestination,
)
from .bring_move import BringMoveTargets
from .execute_command import cursorless_execute_command_action
from .homophones import cursorless_homophones_action
from .replace import cursorless_replace_action
mod = Module()
mod.list(
"cursorless_simple_action",
desc="Cursorless internal: simple actions",
)
mod.list(
"cursorless_callback_action",
desc="Cursorless internal: actions implemented via a callback function",
)
mod.list(
"cursorless_custom_action",
desc="Cursorless internal: user-defined custom actions",
)
mod.list(
"cursorless_experimental_action",
desc="Cursorless internal: experimental actions",
)
ACTION_LIST_NAMES = [
"simple_action",
"callback_action",
"paste_action",
"bring_move_action",
"swap_action",
"wrap_action",
"insert_snippet_action",
"reformat_action",
"call_action",
"experimental_action",
"custom_action",
]
callback_actions: dict[str, Callable[[CursorlessExplicitTarget], None]] = {
"nextHomophone": cursorless_homophones_action,
}
# Don't wait for these actions to finish, usually because they hang on some kind of user interaction
no_wait_actions = [
"generateSnippet",
"rename",
]
# These are actions that we don't wait for, but still want to have a post action sleep
no_wait_actions_post_sleep = {
"rename": 0.3,
}
@mod.capture(
rule=(
"{user.cursorless_simple_action} |"
"{user.cursorless_experimental_action} |"
"{user.cursorless_callback_action} |"
"{user.cursorless_call_action} |"
"{user.cursorless_custom_action}"
)
)
def cursorless_action_or_ide_command(m) -> dict[str, str]:
try:
value = m.cursorless_custom_action
type = "ide_command"
except AttributeError:
value = m[0]
type = "cursorless_action"
return {
"value": value,
"type": type,
}
@mod.action_class
class Actions:
def cursorless_command(action_name: str, target: CursorlessExplicitTarget): # pyright: ignore [reportGeneralTypeIssues]
"""Perform cursorless command on target"""
if action_name in callback_actions:
callback_actions[action_name](target)
elif action_name in ["replaceWithTarget", "moveToTarget"]:
actions.user.private_cursorless_bring_move(
action_name, BringMoveTargets(target, ImplicitDestination())
)
elif action_name == "callAsFunction":
actions.user.private_cursorless_call(target)
elif action_name in no_wait_actions:
action = {"name": action_name, "target": target}
actions.user.private_cursorless_command_no_wait(action)
if action_name in no_wait_actions_post_sleep:
actions.sleep(no_wait_actions_post_sleep[action_name])
else:
action = {"name": action_name, "target": target}
actions.user.private_cursorless_command_and_wait(action)
def cursorless_vscode_command(command_id: str, target: CursorlessTarget): # pyright: ignore [reportGeneralTypeIssues]
"""
Perform vscode command on cursorless target
Deprecated: prefer `cursorless_ide_command`
"""
return actions.user.cursorless_ide_command(command_id, target)
def cursorless_ide_command(command_id: str, target: CursorlessTarget): # pyright: ignore [reportGeneralTypeIssues]
"""Perform ide command on cursorless target"""
return cursorless_execute_command_action(command_id, target)
def cursorless_insert(
destination: CursorlessDestination, # pyright: ignore [reportGeneralTypeIssues]
text: Union[str, list[str]],
):
"""Perform text insertion on Cursorless destination"""
if isinstance(text, str):
text = [text]
cursorless_replace_action(destination, text)
def private_cursorless_action_or_ide_command(
instruction: dict[str, str], # pyright: ignore [reportGeneralTypeIssues]
target: CursorlessTarget,
):
"""Perform cursorless action or ide command on target (internal use only)"""
type = instruction["type"]
value = instruction["value"]
if type == "cursorless_action":
actions.user.cursorless_command(value, target)
elif type == "ide_command":
actions.user.cursorless_ide_command(value, target)