-
-
Notifications
You must be signed in to change notification settings - Fork 77
/
queryPredicateOperators.ts
138 lines (119 loc) · 4.34 KB
/
queryPredicateOperators.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { Range } from "@cursorless/common";
import z from "zod";
import { makeRangeFromPositions } from "../../util/nodeSelectors";
import { MutableQueryCapture } from "./QueryCapture";
import { QueryPredicateOperator } from "./QueryPredicateOperator";
import { q } from "./operatorArgumentSchemaTypes";
/**
* A predicate operator that returns true if the node is not of the given type.
* For example, `(not-type? @foo string)` will reject the match if the `@foo`
* capture is a `string` node. It is acceptable to pass in multiple types, e.g.
* `(not-type? @foo string comment)`.
*/
class NotType extends QueryPredicateOperator<NotType> {
name = "not-type?" as const;
schema = z.tuple([q.node, q.string]).rest(q.string);
run({ node }: MutableQueryCapture, ...types: string[]) {
return !types.includes(node.type);
}
}
/**
* A predicate operator that returns true if the node's parent is not of the
* given type. For example, `(not-parent-type? @foo string)` will reject the
* match if the `@foo` capture is a child of a `string` node. It is acceptable
* to pass in multiple types, e.g. `(not-parent-type? @foo string comment)`.
*/
class NotParentType extends QueryPredicateOperator<NotParentType> {
name = "not-parent-type?" as const;
schema = z.tuple([q.node, q.string]).rest(q.string);
run({ node }: MutableQueryCapture, ...types: string[]) {
return node.parent == null || !types.includes(node.parent.type);
}
}
/**
* A predicate operator that returns true if the node is the nth child of its
* parent. For example, `(is-nth-child? @foo 0)` will reject the match if the
* `@foo` capture is not the first child of its parent.
*/
class IsNthChild extends QueryPredicateOperator<IsNthChild> {
name = "is-nth-child?" as const;
schema = z.tuple([q.node, q.integer]);
run({ node }: MutableQueryCapture, n: number) {
return node.parent?.children.findIndex((n) => n.id === node.id) === n;
}
}
/**
* A predicate operator that modifies the range of the match to be a zero-width
* range at the start of the node. For example, `(#start-position! @foo)` will
* modify the range of the `@foo` capture to be a zero-width range at the start
* of the `@foo` node.
*/
class StartPosition extends QueryPredicateOperator<StartPosition> {
name = "start-position!" as const;
schema = z.tuple([q.node]);
run(nodeInfo: MutableQueryCapture) {
nodeInfo.range = new Range(nodeInfo.range.start, nodeInfo.range.start);
return true;
}
}
/**
* A predicate operator that modifies the range of the match to be a zero-width
* range at the end of the node. For example, `(#end-position! @foo)` will
* modify the range of the `@foo` capture to be a zero-width range at the end of
* the `@foo` node.
*/
class EndPosition extends QueryPredicateOperator<EndPosition> {
name = "end-position!" as const;
schema = z.tuple([q.node]);
run(nodeInfo: MutableQueryCapture) {
nodeInfo.range = new Range(nodeInfo.range.end, nodeInfo.range.end);
return true;
}
}
class ChildRange extends QueryPredicateOperator<ChildRange> {
name = "child-range!" as const;
schema = z.union([
z.tuple([q.node, q.integer]),
z.tuple([q.node, q.integer, q.integer]),
z.tuple([q.node, q.integer, q.integer, q.boolean]),
z.tuple([q.node, q.integer, q.integer, q.boolean, q.boolean]),
]);
run(
nodeInfo: MutableQueryCapture,
startIndex: number,
endIndex?: number,
excludeStart?: boolean,
excludeEnd?: boolean,
) {
const {
node: { children },
} = nodeInfo;
startIndex = startIndex < 0 ? children.length + startIndex : startIndex;
endIndex = endIndex == null ? -1 : endIndex;
endIndex = endIndex < 0 ? children.length + endIndex : endIndex;
const start = children[startIndex];
const end = children[endIndex];
nodeInfo.range = makeRangeFromPositions(
excludeStart ? start.endPosition : start.startPosition,
excludeEnd ? end.startPosition : end.endPosition,
);
return true;
}
}
class AllowMultiple extends QueryPredicateOperator<AllowMultiple> {
name = "allow-multiple!" as const;
schema = z.tuple([q.node]);
run(nodeInfo: MutableQueryCapture) {
nodeInfo.allowMultiple = true;
return true;
}
}
export const queryPredicateOperators = [
new NotType(),
new NotParentType(),
new IsNthChild(),
new StartPosition(),
new EndPosition(),
new ChildRange(),
new AllowMultiple(),
];