Skip to content

Commit 0b109fe

Browse files
authored
Properly position the cursor at the first stop in some cases when inserting snippets without editor support (talonhub#2017)
Applies when: - there is text on the line after the inserted snippet - the first stop in the snippet is on the last (or only) line Also documents an assumption in `move_to_correct_column` that caused the incorrect behavior. Per discussion on Slack, we may want to change the behavior of `move_to_correct_column` to not go to the end of the line, but this involves different tradeoffs that should be discussed further.
1 parent df286da commit 0b109fe

File tree

1 file changed

+44
-24
lines changed

1 file changed

+44
-24
lines changed

core/snippets/snippets_insert_raw_text.py

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,21 @@
2121
desc="""If true, inserting snippets as raw text will always be done through pasting""",
2222
)
2323

24-
RE_STOP = re.compile(r"\$(\d+|\w+)|\$\{(\d+|\w+)\}|\$\{(\d+|\w+):(.+)\}")
24+
RE_STOP = re.compile(
25+
r"""
26+
(?:\\\$) (?# Escaped $ - not a stop; skip and don't capture anything)
27+
|
28+
(?:
29+
\$(\d+|\w+) (?# $... where ... is a captured stop number or variable)
30+
|
31+
\$\{(\d+|\w+)\} (?# ${...} where ... is as above)
32+
|
33+
\$\{(\d+|\w+):(.+)\} (?# ${...:xxx} where ... is as above and xxx a default value)
34+
)
35+
""",
36+
re.VERBOSE,
37+
)
38+
2539
LAST_SNIPPET_HOLE_KEY_VALUE = 1000
2640

2741

@@ -157,34 +171,40 @@ def parse_snippet(body: str):
157171
# Some IM services will send the message on a tab
158172
body = format_tabs(body)
159173

160-
# Replace variable with appropriate value/text
161-
body = re.sub(r"\$TM_SELECTED_TEXT", lambda _: actions.edit.selected_text(), body)
162-
body = re.sub(r"\$CLIPBOARD", lambda _: actions.clip.text(), body)
163-
164174
lines = body.splitlines()
165175
stops: list[Stop] = []
166176

167177
for i, line in enumerate(lines):
168-
match = RE_STOP.search(line)
169-
170-
while match:
171-
stops.append(
172-
Stop(
173-
name=match.group(1) or match.group(2) or match.group(3),
174-
rows_up=len(lines) - i - 1,
175-
columns_left=0,
176-
row=i,
177-
col=match.start(),
178-
)
179-
)
180-
181-
# Remove tab stops and variables.
178+
start = 0
179+
while match := RE_STOP.search(line, start):
182180
stop_text = match.group(0)
183-
default_value = match.group(4) or ""
184-
line = line.replace(stop_text, default_value, 1)
185-
186-
# Might have multiple stops on the same line
187-
match = RE_STOP.search(line)
181+
if stop_text[0] == "\\":
182+
# Remove escape for $
183+
value = stop_text[1:]
184+
# Don't match now-unescaped $ as a stop
185+
start = match.end() - 1
186+
else:
187+
name = match.group(1) or match.group(2) or match.group(3)
188+
value = match.group(4) or ""
189+
190+
match name:
191+
case "TM_SELECTED_TEXT":
192+
value = actions.edit.selected_text() or value
193+
case "CLIPBOARD":
194+
value = actions.clip.text() or value
195+
case _:
196+
stops.append(
197+
Stop(
198+
name=name,
199+
rows_up=len(lines) - i - 1,
200+
columns_left=0,
201+
row=i,
202+
col=match.start(),
203+
)
204+
)
205+
206+
# Remove/replace escaped $, tab stops and variables.
207+
line = line.replace(stop_text, value, 1)
188208

189209
# Update existing line
190210
lines[i] = line

0 commit comments

Comments
 (0)