|
| 1 | +from typing import Callable |
| 2 | + |
| 3 | +from talon import actions |
| 4 | + |
| 5 | +from .versions import COMMAND_VERSION |
| 6 | + |
| 7 | +# This ensures that we remember to update fallback if the response payload changes |
| 8 | +assert COMMAND_VERSION == 7 |
| 9 | + |
| 10 | +action_callbacks = { |
| 11 | + "getText": lambda: [actions.edit.selected_text()], |
| 12 | + "setSelection": actions.skip, |
| 13 | + "setSelectionBefore": actions.edit.left, |
| 14 | + "setSelectionAfter": actions.edit.right, |
| 15 | + "copyToClipboard": actions.edit.copy, |
| 16 | + "cutToClipboard": actions.edit.cut, |
| 17 | + "pasteFromClipboard": actions.edit.paste, |
| 18 | + "clearAndSetSelection": actions.edit.delete, |
| 19 | + "remove": actions.edit.delete, |
| 20 | + "editNewLineBefore": actions.edit.line_insert_up, |
| 21 | + "editNewLineAfter": actions.edit.line_insert_down, |
| 22 | +} |
| 23 | + |
| 24 | +modifier_callbacks = { |
| 25 | + "extendThroughStartOf.line": actions.user.select_line_start, |
| 26 | + "extendThroughEndOf.line": actions.user.select_line_end, |
| 27 | + "containingScope.document": actions.edit.select_all, |
| 28 | + "containingScope.paragraph": actions.edit.select_paragraph, |
| 29 | + "containingScope.line": actions.edit.select_line, |
| 30 | + "containingScope.token": actions.edit.select_word, |
| 31 | +} |
| 32 | + |
| 33 | + |
| 34 | +def call_as_function(callee: str): |
| 35 | + wrap_with_paired_delimiter(f"{callee}(", ")") |
| 36 | + |
| 37 | + |
| 38 | +def wrap_with_paired_delimiter(left: str, right: str): |
| 39 | + selected = actions.edit.selected_text() |
| 40 | + actions.insert(f"{left}{selected}{right}") |
| 41 | + for _ in right: |
| 42 | + actions.edit.left() |
| 43 | + |
| 44 | + |
| 45 | +def containing_token_if_empty(): |
| 46 | + if actions.edit.selected_text() == "": |
| 47 | + actions.edit.select_word() |
| 48 | + |
| 49 | + |
| 50 | +def perform_fallback(fallback: dict): |
| 51 | + try: |
| 52 | + modifier_callbacks = get_modifier_callbacks(fallback) |
| 53 | + action_callback = get_action_callback(fallback) |
| 54 | + for callback in reversed(modifier_callbacks): |
| 55 | + callback() |
| 56 | + return action_callback() |
| 57 | + except ValueError as ex: |
| 58 | + actions.app.notify(str(ex)) |
| 59 | + |
| 60 | + |
| 61 | +def get_action_callback(fallback: dict) -> Callable: |
| 62 | + action = fallback["action"] |
| 63 | + |
| 64 | + if action in action_callbacks: |
| 65 | + return action_callbacks[action] |
| 66 | + |
| 67 | + match action: |
| 68 | + case "insert": |
| 69 | + return lambda: actions.insert(fallback["text"]) |
| 70 | + case "callAsFunction": |
| 71 | + return lambda: call_as_function(fallback["callee"]) |
| 72 | + case "wrapWithPairedDelimiter": |
| 73 | + return lambda: wrap_with_paired_delimiter( |
| 74 | + fallback["left"], fallback["right"] |
| 75 | + ) |
| 76 | + |
| 77 | + raise ValueError(f"Unknown Cursorless fallback action: {action}") |
| 78 | + |
| 79 | + |
| 80 | +def get_modifier_callbacks(fallback: dict) -> list[Callable]: |
| 81 | + return [get_modifier_callback(modifier) for modifier in fallback["modifiers"]] |
| 82 | + |
| 83 | + |
| 84 | +def get_modifier_callback(modifier: dict) -> Callable: |
| 85 | + modifier_type = modifier["type"] |
| 86 | + |
| 87 | + match modifier_type: |
| 88 | + case "containingTokenIfEmpty": |
| 89 | + return containing_token_if_empty |
| 90 | + case "containingScope": |
| 91 | + scope_type_type = modifier["scopeType"]["type"] |
| 92 | + return get_simple_modifier_callback(f"{modifier_type}.{scope_type_type}") |
| 93 | + case "extendThroughStartOf": |
| 94 | + if "modifiers" not in modifier: |
| 95 | + return get_simple_modifier_callback(f"{modifier_type}.line") |
| 96 | + case "extendThroughEndOf": |
| 97 | + if "modifiers" not in modifier: |
| 98 | + return get_simple_modifier_callback(f"{modifier_type}.line") |
| 99 | + |
| 100 | + raise ValueError(f"Unknown Cursorless fallback modifier: {modifier_type}") |
| 101 | + |
| 102 | + |
| 103 | +def get_simple_modifier_callback(key: str) -> Callable: |
| 104 | + try: |
| 105 | + return modifier_callbacks[key] |
| 106 | + except KeyError: |
| 107 | + raise ValueError(f"Unknown Cursorless fallback modifier: {key}") |
0 commit comments