Skip to content

Commit a1eca3d

Browse files
AndreasArvidssonpre-commit-ci-lite[bot]phillco
authored
Properly expand to token when using "end of this" (#2782)
Fixes #1628 ## Checklist - [x] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [/] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [/] I have not broken the cheatsheet --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Phil Cohen <[email protected]>
1 parent c690d93 commit a1eca3d

File tree

2 files changed

+77
-6
lines changed

2 files changed

+77
-6
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
languageId: plaintext
2+
command:
3+
version: 7
4+
spokenForm: bring air to end of this
5+
action:
6+
name: replaceWithTarget
7+
source:
8+
type: primitive
9+
mark: {type: decoratedSymbol, symbolColor: default, character: a}
10+
destination:
11+
type: primitive
12+
insertionMode: to
13+
target:
14+
type: primitive
15+
mark: {type: cursor}
16+
modifiers:
17+
- {type: endOf}
18+
usePrePhraseSnapshot: false
19+
initialState:
20+
documentContents: |-
21+
a
22+
bbb
23+
selections:
24+
- anchor: {line: 1, character: 0}
25+
active: {line: 1, character: 0}
26+
marks:
27+
default.a:
28+
start: {line: 0, character: 0}
29+
end: {line: 0, character: 1}
30+
finalState:
31+
documentContents: |-
32+
a
33+
bbba
34+
selections:
35+
- anchor: {line: 1, character: 0}
36+
active: {line: 1, character: 0}

packages/cursorless-engine/src/processTargets/TargetPipelineRunner.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ class TargetPipeline {
208208
): Target[] {
209209
let markStage: MarkStage;
210210
let targetModifierStages: ModifierStage[];
211+
let automaticTokenExpansionBefore = false;
211212

212213
if (targetDescriptor.type === "implicit") {
213214
markStage = new ImplicitStage();
@@ -218,28 +219,62 @@ class TargetPipeline {
218219
this.modifierStageFactory,
219220
targetDescriptor.modifiers,
220221
);
222+
automaticTokenExpansionBefore =
223+
doAutomaticTokenExpansionBefore(targetDescriptor);
221224
}
222225

223226
// First, get the targets output by the mark
224227
const markOutputTargets = markStage.run();
225228

229+
const [preStages, postStages] = this.getPreAndPostStages(
230+
automaticTokenExpansionBefore,
231+
);
232+
226233
/**
227234
* The modifier pipeline that will be applied to construct our final targets
228235
*/
229236
const modifierStages = [
237+
...preStages,
230238
...targetModifierStages,
231239
...this.opts.actionFinalStages,
232-
233-
// This performs auto-expansion to token when you say eg "take this" with an
234-
// empty selection
235-
...(this.opts.noAutomaticTokenExpansion
236-
? []
237-
: [new ContainingTokenIfUntypedEmptyStage(this.modifierStageFactory)]),
240+
...postStages,
238241
];
239242

240243
// Run all targets through the modifier stages
241244
return processModifierStages(modifierStages, markOutputTargets);
242245
}
246+
247+
private getPreAndPostStages(
248+
automaticTokenExpansionBefore: boolean,
249+
): [ModifierStage[], ModifierStage[]] {
250+
if (this.opts.noAutomaticTokenExpansion) {
251+
return [[], []];
252+
}
253+
// This performs auto-expansion to token when you say eg "take this" with an
254+
// empty selection
255+
const stage = new ContainingTokenIfUntypedEmptyStage(
256+
this.modifierStageFactory,
257+
);
258+
if (automaticTokenExpansionBefore) {
259+
return [[stage], []];
260+
}
261+
return [[], [stage]];
262+
}
263+
}
264+
265+
/**
266+
* Determines whether we should automatically expand the token before the target.
267+
* True if the target has modifiers that are all "startOf" or "endOf".
268+
*/
269+
function doAutomaticTokenExpansionBefore(
270+
targetDescriptor: PrimitiveTargetDescriptor,
271+
): boolean {
272+
return (
273+
targetDescriptor.modifiers.length > 0 &&
274+
targetDescriptor.modifiers.every(
275+
({ type }) => type === "startOf" || type === "endOf",
276+
)
277+
);
243278
}
244279

245280
/** Convert a list of target modifiers to modifier stages */

0 commit comments

Comments
 (0)