Skip to content

Commit 66731e4

Browse files
Added predicate
1 parent ea5a542 commit 66731e4

22 files changed

+178
-19
lines changed

packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ export interface QueryCapture {
3636
* content ranges. */
3737
readonly allowMultiple: boolean;
3838

39+
/** Whether this scope should expand contiguously to its siblings. */
40+
readonly contiguous: boolean;
41+
3942
/** The insertion delimiter to use if any */
4043
readonly insertionDelimiter: string | undefined;
4144
}
@@ -63,6 +66,7 @@ export interface MutableQueryCapture extends QueryCapture {
6366
readonly document: TextDocument;
6467
range: Range;
6568
allowMultiple: boolean;
69+
contiguous: boolean;
6670
insertionDelimiter: string | undefined;
6771
}
6872

packages/cursorless-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export class TreeSitterQuery {
8282
range: getNodeRange(node),
8383
insertionDelimiter: undefined,
8484
allowMultiple: false,
85+
contiguous: false,
8586
})),
8687
}),
8788
)
@@ -114,6 +115,7 @@ export class TreeSitterQuery {
114115
.map(({ range }) => range)
115116
.reduce((accumulator, range) => range.union(accumulator)),
116117
allowMultiple: captures.some((capture) => capture.allowMultiple),
118+
contiguous: captures.some((capture) => capture.contiguous),
117119
insertionDelimiter: captures.find(
118120
(capture) => capture.insertionDelimiter != null,
119121
)?.insertionDelimiter,

packages/cursorless-engine/src/languages/TreeSitterQuery/checkCaptureStartEnd.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import assert from "assert";
55

66
interface TestCase {
77
name: string;
8-
captures: Omit<QueryCapture, "allowMultiple" | "insertionDelimiter">[];
8+
captures: Omit<
9+
QueryCapture,
10+
"allowMultiple" | "contiguous" | "insertionDelimiter"
11+
>[];
912
isValid: boolean;
1013
expectedErrorMessageIds: string[];
1114
}
@@ -192,6 +195,7 @@ suite("checkCaptureStartEnd", () => {
192195
testCase.captures.map((capture) => ({
193196
...capture,
194197
allowMultiple: false,
198+
contiguous: false,
195199
insertionDelimiter: undefined,
196200
})),
197201
messages,

packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,23 @@ class AllowMultiple extends QueryPredicateOperator<AllowMultiple> {
185185
}
186186
}
187187

188+
/** Indicates that it's okay for this scope to extend contiguously it through its siblings. */
189+
class Contiguous extends QueryPredicateOperator<Contiguous> {
190+
name = "contiguous!" as const;
191+
schema = z.union([z.tuple([q.node]), z.tuple([q.node, q.string])]);
192+
193+
run(nodeInfo: MutableQueryCapture, pattern?: string) {
194+
if (pattern != null) {
195+
const text = nodeInfo.document.getText(nodeInfo.range);
196+
nodeInfo.contiguous = new RegExp(pattern, "s").test(text);
197+
} else {
198+
nodeInfo.contiguous = true;
199+
}
200+
201+
return true;
202+
}
203+
}
204+
188205
/**
189206
* A predicate operator that logs a node, for debugging.
190207
*/
@@ -254,6 +271,7 @@ export const queryPredicateOperators = [
254271
new ChildRange(),
255272
new ShrinkToMatch(),
256273
new AllowMultiple(),
274+
new Contiguous(),
257275
new InsertionDelimiter(),
258276
new SingleOrMultilineDelimiter(),
259277
new HasMultipleChildrenOfType(),

packages/cursorless-engine/src/languages/TreeSitterQuery/rewriteStartOfEndOf.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ function fillOutCapture(capture: NameRange): MutableQueryCapture {
5454
return {
5555
...capture,
5656
allowMultiple: false,
57+
contiguous: false,
5758
insertionDelimiter: undefined,
5859
document: null as unknown as TextDocument,
5960
node: null as unknown as SyntaxNode,

packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ function* generateTargetRangesInDirection(
116116
}
117117

118118
function isAdjacent(scope1: TargetScope, scope2: TargetScope): boolean {
119+
if (!scope1.contiguous || !scope2.contiguous) {
120+
return false;
121+
}
122+
119123
if (scope1.domain.isRangeEqual(scope2.domain)) {
120124
return true;
121125
}

packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/BaseTreeSitterScopeHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,5 @@ export abstract class BaseTreeSitterScopeHandler extends BaseScopeHandler {
9595

9696
export interface ExtendedTargetScope extends TargetScope {
9797
allowMultiple: boolean;
98+
contiguous: boolean;
9899
}

packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterIterationScopeHandler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class TreeSitterIterationScopeHandler extends BaseTreeSitterScopeHandler
4242
return undefined;
4343
}
4444

45-
const { range: contentRange, allowMultiple } = capture;
45+
const { range: contentRange, allowMultiple, contiguous } = capture;
4646

4747
const domain =
4848
getRelatedRange(match, scopeTypeType, "iteration.domain", false) ??
@@ -52,6 +52,7 @@ export class TreeSitterIterationScopeHandler extends BaseTreeSitterScopeHandler
5252
editor,
5353
domain,
5454
allowMultiple,
55+
contiguous,
5556
getTargets: (isReversed) => [
5657
new PlainTarget({
5758
editor,

packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ export class TreeSitterScopeHandler extends BaseTreeSitterScopeHandler {
4848
return undefined;
4949
}
5050

51-
const { range: contentRange, allowMultiple, insertionDelimiter } = capture;
51+
const {
52+
range: contentRange,
53+
allowMultiple,
54+
contiguous,
55+
insertionDelimiter,
56+
} = capture;
5257

5358
const domain =
5459
getRelatedRange(match, scopeTypeType, "domain", true) ?? contentRange;
@@ -87,6 +92,7 @@ export class TreeSitterScopeHandler extends BaseTreeSitterScopeHandler {
8792
editor,
8893
domain,
8994
allowMultiple,
95+
contiguous,
9096
getTargets: (isReversed) => [
9197
new ScopeTypeTarget({
9298
scopeTypeType,

packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterTextFragmentScopeHandler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class TreeSitterTextFragmentScopeHandler extends BaseTreeSitterScopeHandl
3838
return undefined;
3939
}
4040

41-
const { range: contentRange, allowMultiple } = capture;
41+
const { range: contentRange, allowMultiple, contiguous } = capture;
4242

4343
if (allowMultiple) {
4444
throw Error(
@@ -50,6 +50,7 @@ export class TreeSitterTextFragmentScopeHandler extends BaseTreeSitterScopeHandl
5050
editor,
5151
domain: contentRange,
5252
allowMultiple,
53+
contiguous,
5354
getTargets: (isReversed) => [
5455
new PlainTarget({
5556
editor,

0 commit comments

Comments
 (0)