Skip to content

Commit 8b7cba9

Browse files
Support insertSnippet action (#304)
* Support insertSnippet action Handle action modifiers before positional modifiers * Fixes from Andreas PR review session * Tweaks from PR feedback * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Make halt overridable * Clean up snippet error handling * Throw error if multiple snippet definitions match a context * Improve comment * Update comment * Cleanup * More cleanup * Add doc string * Support cascading scope types for snippets * Update doc string * Removed duplicate test * Restructure tests * At link to issue Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 97e5e89 commit 8b7cba9

File tree

5 files changed

+153
-56
lines changed

5 files changed

+153
-56
lines changed

src/actions/actions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def vscode_command_no_wait(command_id: str, target: dict, command_options: dict
8686
"swap_action": {"swap": "swapTargets"},
8787
"move_bring_action": {"bring": "replaceWithTarget", "move": "moveToTarget"},
8888
"wrap_action": {"wrap": "wrapWithPairedDelimiter", "repack": "rewrap"},
89+
"insert_snippet_action": {"snippet": "insertSnippet"},
8990
"reformat_action": {"format": "applyFormatter"},
9091
}
9192

src/actions/wrap.py

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,12 @@
11
from typing import Any
22

3-
from talon import Context, Module, actions, app
3+
from talon import Module, actions
44

5-
from ..csv_overrides import init_csv_and_watch_changes
65
from ..paired_delimiter import paired_delimiters_map
76

87
mod = Module()
98

10-
mod.tag(
11-
"cursorless_experimental_snippets",
12-
desc="tag for enabling experimental snippet support",
13-
)
14-
159
mod.list("cursorless_wrap_action", desc="Cursorless wrap action")
16-
mod.list("cursorless_wrapper_snippet", desc="Cursorless wrapper snippet")
17-
18-
experimental_snippets_ctx = Context()
19-
experimental_snippets_ctx.matches = r"""
20-
tag: user.cursorless_experimental_snippets
21-
"""
22-
23-
24-
# NOTE: Please do not change these dicts. Use the CSVs for customization.
25-
# See https://www.cursorless.org/docs/user/customization/
26-
wrapper_snippets = {
27-
"else": "ifElseStatement.alternative",
28-
"if else": "ifElseStatement.consequence",
29-
"if": "ifStatement.consequence",
30-
"try": "tryCatchStatement.body",
31-
"link": "link.text",
32-
}
3310

3411

3512
@mod.capture(
@@ -72,18 +49,3 @@ def cursorless_wrap(action_type: str, targets: dict, cursorless_wrapper: dict):
7249
actions.user.cursorless_single_target_command_with_arg_list(
7350
action, targets, cursorless_wrapper["extra_args"]
7451
)
75-
76-
77-
def on_ready():
78-
init_csv_and_watch_changes(
79-
"experimental/wrapper_snippets",
80-
{
81-
"wrapper_snippet": wrapper_snippets,
82-
},
83-
allow_unknown_values=True,
84-
default_list_name="wrapper_snippet",
85-
ctx=experimental_snippets_ctx,
86-
)
87-
88-
89-
app.register("ready", on_ready)

src/command.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from talon import Module, actions, speech_system
44

5+
from .primitive_target import IMPLICIT_TARGET
6+
57
mod = Module()
68

79
last_phrase = None
@@ -47,17 +49,7 @@ def cursorless_single_target_command_no_wait(
4749
)
4850

4951
def cursorless_single_target_command_with_arg_list(
50-
action: str, target: str, args: list[Any]
51-
):
52-
"""Execute single-target cursorless command with argument list"""
53-
actions.user.cursorless_single_target_command(
54-
action,
55-
target,
56-
*args,
57-
)
58-
59-
def cursorless_single_target_command_with_arg_list(
60-
action: str, target: str, args: list[Any]
52+
action: str, target: dict, args: list[Any]
6153
):
6254
"""Execute single-target cursorless command with argument list"""
6355
actions.user.cursorless_single_target_command(
@@ -83,12 +75,23 @@ def cursorless_single_target_command_get(
8375
),
8476
)
8577

78+
def cursorless_implicit_target_command(
79+
action: str,
80+
arg1: Any = NotSet,
81+
arg2: Any = NotSet,
82+
arg3: Any = NotSet,
83+
):
84+
"""Execute cursorless command with implicit target"""
85+
actions.user.cursorless_single_target_command(
86+
action, IMPLICIT_TARGET, arg1, arg2, arg3
87+
)
88+
8689
def cursorless_multiple_target_command(
8790
action: str,
8891
targets: list[dict],
89-
arg1: any = NotSet,
90-
arg2: any = NotSet,
91-
arg3: any = NotSet,
92+
arg1: Any = NotSet,
93+
arg2: Any = NotSet,
94+
arg3: Any = NotSet,
9295
):
9396
"""Execute multi-target cursorless command"""
9497
actions.user.vscode_with_plugin_and_wait(
@@ -103,9 +106,9 @@ def cursorless_multiple_target_command(
103106
def cursorless_multiple_target_command_no_wait(
104107
action: str,
105108
targets: list[dict],
106-
arg1: any = NotSet,
107-
arg2: any = NotSet,
108-
arg3: any = NotSet,
109+
arg1: Any = NotSet,
110+
arg2: Any = NotSet,
111+
arg3: Any = NotSet,
109112
):
110113
"""Execute multi-target cursorless command"""
111114
actions.user.vscode_with_plugin(

src/cursorless-snippets.talon

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
app: vscode
2+
tag: user.cursorless_experimental_snippets
3+
-
4+
5+
{user.cursorless_insert_snippet_action} <user.cursorless_insertion_snippet>:
6+
user.cursorless_implicit_target_command(cursorless_insert_snippet_action, cursorless_insertion_snippet)
7+
8+
{user.cursorless_insert_snippet_action} <user.cursorless_insertion_snippet> <user.cursorless_positional_target>:
9+
user.cursorless_single_target_command(cursorless_insert_snippet_action, cursorless_positional_target, cursorless_insertion_snippet)
10+
11+
{user.cursorless_insert_snippet_action} {user.cursorless_insertion_snippet_single_phrase} <user.text> [{user.cursorless_phrase_terminator}]:
12+
user.cursorless_insert_snippet_with_phrase(cursorless_insert_snippet_action, cursorless_insertion_snippet_single_phrase, text)

src/snippets.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from talon import Context, Module, actions, app
2+
3+
from .csv_overrides import init_csv_and_watch_changes
4+
5+
mod = Module()
6+
mod.list("cursorless_insert_snippet_action", desc="Cursorless insert snippet action")
7+
8+
mod.tag(
9+
"cursorless_experimental_snippets",
10+
desc="tag for enabling experimental snippet support",
11+
)
12+
13+
mod.list("cursorless_wrapper_snippet", desc="Cursorless wrapper snippet")
14+
mod.list(
15+
"cursorless_insertion_snippet_no_phrase",
16+
desc="Cursorless insertion snippets that don't accept a phrase",
17+
)
18+
mod.list(
19+
"cursorless_insertion_snippet_single_phrase",
20+
desc="Cursorless insertion snippet that can accept a single phrase",
21+
)
22+
mod.list("cursorless_phrase_terminator", "Contains term used to terminate a phrase")
23+
24+
25+
@mod.capture(
26+
rule="{user.cursorless_insertion_snippet_no_phrase} | {user.cursorless_insertion_snippet_single_phrase}"
27+
)
28+
def cursorless_insertion_snippet(m) -> str:
29+
try:
30+
return m.cursorless_insertion_snippet_no_phrase
31+
except AttributeError:
32+
pass
33+
34+
return m.cursorless_insertion_snippet_single_phrase.split(".")[0]
35+
36+
37+
experimental_snippets_ctx = Context()
38+
experimental_snippets_ctx.matches = r"""
39+
tag: user.cursorless_experimental_snippets
40+
"""
41+
42+
43+
# NOTE: Please do not change these dicts. Use the CSVs for customization.
44+
# See https://www.cursorless.org/docs/user/customization/
45+
wrapper_snippets = {
46+
"else": "ifElseStatement.alternative",
47+
"funk": "functionDeclaration.body",
48+
"if else": "ifElseStatement.consequence",
49+
"if": "ifStatement.consequence",
50+
"try": "tryCatchStatement.body",
51+
"link": "link.text",
52+
}
53+
54+
# NOTE: Please do not change these dicts. Use the CSVs for customization.
55+
# See https://www.cursorless.org/docs/user/customization/
56+
insertion_snippets_no_phrase = {
57+
"if": "ifStatement",
58+
"if else": "ifElseStatement",
59+
"try": "tryCatchStatement",
60+
}
61+
62+
# NOTE: Please do not change these dicts. Use the CSVs for customization.
63+
# See https://www.cursorless.org/docs/user/customization/
64+
insertion_snippets_single_phrase = {
65+
"funk": "functionDeclaration.name",
66+
"link": "link.text",
67+
}
68+
69+
70+
@mod.action_class
71+
class Actions:
72+
def cursorless_insert_snippet_with_phrase(
73+
action: str, snippet_description: str, text: str
74+
):
75+
"""Perform cursorless wrap action"""
76+
snippet_name, snippet_variable = snippet_description.split(".")
77+
actions.user.cursorless_implicit_target_command(
78+
action, snippet_name, {snippet_variable: text}
79+
)
80+
81+
82+
def on_ready():
83+
init_csv_and_watch_changes(
84+
"experimental/wrapper_snippets",
85+
{
86+
"wrapper_snippet": wrapper_snippets,
87+
},
88+
allow_unknown_values=True,
89+
default_list_name="wrapper_snippet",
90+
ctx=experimental_snippets_ctx,
91+
)
92+
init_csv_and_watch_changes(
93+
"experimental/insertion_snippets",
94+
{
95+
"insertion_snippet_no_phrase": insertion_snippets_no_phrase,
96+
},
97+
allow_unknown_values=True,
98+
default_list_name="insertion_snippet_no_phrase",
99+
ctx=experimental_snippets_ctx,
100+
)
101+
init_csv_and_watch_changes(
102+
"experimental/insertion_snippets_single_phrase",
103+
{
104+
"insertion_snippet_single_phrase": insertion_snippets_single_phrase,
105+
},
106+
allow_unknown_values=True,
107+
default_list_name="insertion_snippet_single_phrase",
108+
ctx=experimental_snippets_ctx,
109+
)
110+
init_csv_and_watch_changes(
111+
"experimental/miscellaneous",
112+
{
113+
"phrase_terminator": {"over": "phraseTerminator"},
114+
},
115+
ctx=experimental_snippets_ctx,
116+
)
117+
118+
119+
app.register("ready", on_ready)

0 commit comments

Comments
 (0)