diff --git a/src/actions/actions.py b/src/actions/actions.py index ccd7bbe3..25d8faf9 100644 --- a/src/actions/actions.py +++ b/src/actions/actions.py @@ -1,6 +1,6 @@ from talon import Module, app, actions from ..csv_overrides import init_csv_and_watch_changes -from .actions_simple import simple_action_defaults +from .actions_simple import simple_action_defaults, positional_action_defaults from .actions_callback import callback_action_defaults, callback_action_map from .actions_makeshift import ( makeshift_action_defaults, @@ -81,6 +81,7 @@ def vscode_command_no_wait(command_id: str, target: dict, command_options: dict default_values = { "simple_action": simple_action_defaults, + "positional_action": positional_action_defaults, "callback_action": callback_action_defaults, "makeshift_action": makeshift_action_defaults, "custom_action": custom_action_defaults, diff --git a/src/actions/actions_simple.py b/src/actions/actions_simple.py index 80c08572..8e456697 100644 --- a/src/actions/actions_simple.py +++ b/src/actions/actions_simple.py @@ -34,8 +34,18 @@ "unfold": "unfoldRegion", } +# NOTE: Please do not change these dicts. Use the CSVs for customization. +# See https://github.com/pokey/cursorless-talon/blob/main/docs/customization.md +positional_action_defaults = { + "paste": "pasteFromClipboard", +} + mod = Module() mod.list( "cursorless_simple_action", desc="Supported simple actions for cursorless navigation", ) +mod.list( + "cursorless_positional_action", + desc="Supported actions for cursorless that expect a positional target", +) diff --git a/src/actions/call.py b/src/actions/call.py index 659a7093..10cadab6 100644 --- a/src/actions/call.py +++ b/src/actions/call.py @@ -5,5 +5,5 @@ def run_call_action(target: dict): - targets = [target, IMPLICIT_TARGET] + targets = [target, IMPLICIT_TARGET.copy()] actions.user.cursorless_multiple_target_command("callAsFunction", targets) diff --git a/src/actions/move_bring.py b/src/actions/move_bring.py index 4e20958b..56bdcfd8 100644 --- a/src/actions/move_bring.py +++ b/src/actions/move_bring.py @@ -3,7 +3,7 @@ mod = Module() mod.list( - "cursorless_source_destination_connective", + "cursorless_positional_connective", desc="The connective used to separate source and destination targets", ) @@ -11,15 +11,13 @@ mod.list("cursorless_move_bring_action", desc="Cursorless move or bring actions") -@mod.capture( - rule=( - " [{user.cursorless_source_destination_connective} ]" - ) -) +@mod.capture(rule=(" []")) def cursorless_move_bring_targets(m) -> list[dict]: - target_list = m.cursorless_target_list + target_list = [m.cursorless_target] - if len(target_list) == 1: - target_list = target_list + [IMPLICIT_TARGET] + try: + target_list += [m.cursorless_positional_target] + except AttributeError: + target_list += [IMPLICIT_TARGET.copy()] - return target_list + return target_list \ No newline at end of file diff --git a/src/cheatsheet/sections/actions.py b/src/cheatsheet/sections/actions.py index 4abdcf8d..c30ec281 100644 --- a/src/cheatsheet/sections/actions.py +++ b/src/cheatsheet/sections/actions.py @@ -27,9 +27,9 @@ def get_actions(): } swap_connective = list(get_raw_list("swap_connective").keys())[0] - source_destination_connective = list( - get_raw_list("source_destination_connective").keys() - )[0] + positional_connectives = { + value: key for key, value in get_raw_list("positional_connective").items() + } make_dict_readable( simple_actions, @@ -39,10 +39,14 @@ def get_actions(): ) return { **simple_actions, - f"{complex_actions['replaceWithTarget']} {source_destination_connective} ": "Replace T2 with T1", - f"{complex_actions['replaceWithTarget']} ": "Replace S with T", - f"{complex_actions['moveToTarget']} {source_destination_connective} ": "Move T1 to T2", - f"{complex_actions['moveToTarget']} ": "Move T to S", + f"{complex_actions['replaceWithTarget']} T1 {positional_connectives['contentConnective']} T2": "Replace T2 with T1", + f"{complex_actions['replaceWithTarget']} T1 {positional_connectives['afterConnective']} T2": "Copy T2 after T1", + f"{complex_actions['replaceWithTarget']} T1 {positional_connectives['beforeConnective']} T2": "Copy T2 before T1", + f"{complex_actions['replaceWithTarget']} T": "Replace S with T", + f"{complex_actions['moveToTarget']} T1 {positional_connectives['contentConnective']} T2": "Move T1 to T2", + f"{complex_actions['moveToTarget']} T1 {positional_connectives['afterConnective']} T2": "Move T1 after T2", + f"{complex_actions['moveToTarget']} T1 {positional_connectives['beforeConnective']} T2": "Move T1 before T2", + f"{complex_actions['moveToTarget']} T": "Move T to S", f"{complex_actions['swapTargets']} {swap_connective} ": "Swap T1 with T2", f"{complex_actions['swapTargets']} ": "Swap S with T", f"{complex_actions['applyFormatter']} at ": "Reformat T as F", diff --git a/src/command.py b/src/command.py index 06829fc4..6c12b131 100644 --- a/src/command.py +++ b/src/command.py @@ -54,7 +54,7 @@ def cursorless_this_command( ): """Execute cursorless command, passing `this` as single target""" actions.user.cursorless_multiple_target_command( - action, [IMPLICIT_TARGET], arg1, arg2, arg3 + action, [IMPLICIT_TARGET.copy()], arg1, arg2, arg3 ) def cursorless_single_target_command_with_arg_list( diff --git a/src/connective.py b/src/connective.py index 74da2dca..a699cc3b 100644 --- a/src/connective.py +++ b/src/connective.py @@ -10,6 +10,14 @@ "until": "rangeExcludingEnd", } +# NOTE: Please do not change these dicts. Use the CSVs for customization. +# See https://github.com/pokey/cursorless-talon/blob/main/docs/customization.md +positional_connectives = { + "after": "afterConnective", + "before": "beforeConnective", + "to": "contentConnective", +} + default_range_connective = "rangeInclusive" @@ -20,7 +28,7 @@ def on_ready(): "range_connective": range_connectives, "list_connective": {"and": "listConnective"}, "swap_connective": {"with": "swapConnective"}, - "source_destination_connective": {"to": "sourceDestinationConnective"}, + "positional_connective": positional_connectives, }, ) diff --git a/src/cursorless-snippets.talon b/src/cursorless-snippets.talon index 95995d81..bccc7bcf 100644 --- a/src/cursorless-snippets.talon +++ b/src/cursorless-snippets.talon @@ -5,8 +5,8 @@ tag: user.cursorless_experimental_snippets {user.cursorless_insert_snippet_action} : user.cursorless_this_command(cursorless_insert_snippet_action, cursorless_insertion_snippet) -{user.cursorless_insert_snippet_action} : - user.cursorless_single_target_command(cursorless_insert_snippet_action, cursorless_target, cursorless_insertion_snippet) +{user.cursorless_insert_snippet_action} : + user.cursorless_single_target_command(cursorless_insert_snippet_action, cursorless_positional_target, cursorless_insertion_snippet) {user.cursorless_insert_snippet_action} {user.cursorless_insertion_snippet_single_phrase} [halt]: user.cursorless_insert_snippet_with_phrase(cursorless_insert_snippet_action, cursorless_insertion_snippet_single_phrase, text) \ No newline at end of file diff --git a/src/cursorless.talon b/src/cursorless.talon index dc02a39d..345463e9 100644 --- a/src/cursorless.talon +++ b/src/cursorless.talon @@ -4,6 +4,9 @@ app: vscode : user.cursorless_action_or_vscode_command(cursorless_action_or_vscode_command, cursorless_target) +{user.cursorless_positional_action} : + user.cursorless_single_target_command(cursorless_positional_action, cursorless_positional_target) + {user.cursorless_swap_action} : user.cursorless_multiple_target_command(cursorless_swap_action, cursorless_swap_targets) diff --git a/src/modifiers/position.py b/src/modifiers/position.py index 830d00b6..0472ff74 100644 --- a/src/modifiers/position.py +++ b/src/modifiers/position.py @@ -5,8 +5,6 @@ positions = { - "after": {"position": "after"}, - "before": {"position": "before"}, "start of": {"position": "before", "insideOutsideType": "inside"}, "end of": {"position": "after", "insideOutsideType": "inside"}, # Disabled for now because "below" can misrecognize with "blue" and we may move away from allowing positional modifiers in arbitrary places anyway diff --git a/src/positional_target.py b/src/positional_target.py new file mode 100644 index 00000000..a792212d --- /dev/null +++ b/src/positional_target.py @@ -0,0 +1,39 @@ +from talon import Module + +mod = Module() + + +@mod.capture(rule=("{user.cursorless_positional_connective} ")) +def cursorless_positional_target(m) -> list[dict]: + return process_positional_connective( + m.cursorless_positional_connective, m.cursorless_target + ) + + +def process_positional_connective(cursorless_positional_connective: str, target: dict): + if cursorless_positional_connective == "afterConnective": + return update_first_primitive_target(target, {"position": "after"}) + elif cursorless_positional_connective == "beforeConnective": + return update_first_primitive_target(target, {"position": "before"}) + + return target + + +def update_first_primitive_target(target: dict, fields: dict): + if target["type"] == "primitive": + return {**target, **fields} + elif target["type"] == "range": + return { + **target, + "start": update_first_primitive_target(target["start"], fields), + } + else: + elements = target["elements"] + + return { + **target, + "elements": [ + update_first_primitive_target(elements[0], fields), + *elements[1:], + ], + }