Skip to content

Commit 1164e2f

Browse files
authored
Migrate Typescript "value" to next gen; improve "name" (#1924)
## Checklist - [ ] 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
1 parent af14956 commit 1164e2f

21 files changed

+1111
-60
lines changed

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

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,21 @@ export abstract class QueryPredicateOperator<T extends HasSchema> {
4747
...args: AcceptFunctionArgs<z.infer<InferSchemaType<T>>>
4848
): boolean;
4949

50+
/**
51+
* Whether it is ok for a node argument to be missing. If true, then the
52+
* operator will just accept the pattern if the given node is missing. If
53+
* false, then the operator will throw an error if the node is missing.
54+
*
55+
* This is useful if we want to set some flag on a node, but only if it's
56+
* present.
57+
*
58+
* @returns A boolean indicating whether it is ok for a node argument to be
59+
* missing.
60+
*/
61+
protected allowMissingNode(): boolean {
62+
return false;
63+
}
64+
5065
/**
5166
* Given a list of operands, return a predicate function that can be used to
5267
* test whether a given match satisfies the predicate.
@@ -62,8 +77,21 @@ export abstract class QueryPredicateOperator<T extends HasSchema> {
6277
return result.success
6378
? {
6479
success: true,
65-
predicate: (match: MutableQueryMatch) =>
66-
this.run(...this.constructAcceptArgs(result.data, match)),
80+
predicate: (match: MutableQueryMatch) => {
81+
try {
82+
const acceptArgs = this.constructAcceptArgs(result.data, match);
83+
return this.run(...acceptArgs);
84+
} catch (err) {
85+
if (
86+
err instanceof CaptureNotFoundError &&
87+
this.allowMissingNode()
88+
) {
89+
return true;
90+
}
91+
92+
throw err;
93+
}
94+
},
6795
}
6896
: {
6997
success: false,
@@ -89,13 +117,7 @@ export abstract class QueryPredicateOperator<T extends HasSchema> {
89117
);
90118

91119
if (capture == null) {
92-
// FIXME: We could allow some predicates to be forgiving,
93-
// because it's possible to have a capture on an optional nodeInfo.
94-
// In that case we'd prob just return `true` if any capture was
95-
// `null`, but we should check that the given capture name
96-
// appears statically in the given pattern. But we don't yet
97-
// have a use case so let's leave it for now.
98-
throw new Error(`Could not find capture ${operand.name}`);
120+
throw new CaptureNotFoundError(operand.name);
99121
}
100122

101123
return capture;
@@ -117,3 +139,9 @@ interface FailedPredicateResult {
117139
}
118140

119141
type PredicateResult = SuccessfulPredicateResult | FailedPredicateResult;
142+
143+
class CaptureNotFoundError extends Error {
144+
constructor(operandName: string) {
145+
super(`Could not find capture ${operandName}`);
146+
}
147+
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,25 @@ class ShrinkToMatch extends QueryPredicateOperator<ShrinkToMatch> {
150150
}
151151
}
152152

153+
/**
154+
* Indicates that it is ok for multiple captures to have the same domain but
155+
* different targets. For example, if we have the query `(#allow-multiple!
156+
* @foo)`, then if we define the query so that `@foo` appears multiple times
157+
* with the same domain but different targets, then the given domain will end up
158+
* with multiple targets. The canonical example is `tags` in HTML / jsx.
159+
*
160+
* This operator is allowed to be applied to a capture that doesn't actually
161+
* appear; ie we can make it so that we allow multiple if the capture appears in
162+
* the pattern.
163+
*/
153164
class AllowMultiple extends QueryPredicateOperator<AllowMultiple> {
154165
name = "allow-multiple!" as const;
155166
schema = z.tuple([q.node]);
156167

168+
protected allowMissingNode(): boolean {
169+
return true;
170+
}
171+
157172
run(nodeInfo: MutableQueryCapture) {
158173
nodeInfo.allowMultiple = true;
159174

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

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -124,34 +124,6 @@ function typeMatcher(): NodeMatcher {
124124
};
125125
}
126126

127-
function valueMatcher() {
128-
const pFinder = patternFinder(
129-
"assignment_expression[right]",
130-
"augmented_assignment_expression[right]",
131-
"*[value]",
132-
"shorthand_property_identifier",
133-
);
134-
return matcher(
135-
(node: SyntaxNode) =>
136-
node.type === "jsx_attribute" ? node.lastChild : pFinder(node),
137-
selectWithLeadingDelimiter(
138-
":",
139-
"=",
140-
"+=",
141-
"-=",
142-
"*=",
143-
"/=",
144-
"%=",
145-
"**=",
146-
"&=",
147-
"|=",
148-
"^=",
149-
"<<=",
150-
">>=",
151-
),
152-
);
153-
}
154-
155127
const mapTypes = ["object", "object_pattern"];
156128
const listTypes = ["array", "array_pattern"];
157129

@@ -171,11 +143,6 @@ const nodeMatchers: Partial<
171143
],
172144
[":"],
173145
),
174-
value: cascadingMatcher(
175-
valueMatcher(),
176-
patternMatcher("return_statement.~return!"),
177-
patternMatcher("yield_expression.~yield!"),
178-
),
179146
ifStatement: "if_statement",
180147
comment: "comment",
181148
regularExpression: "regex",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
languageId: javascript
2+
command:
3+
version: 6
4+
spokenForm: change every value
5+
action:
6+
name: clearAndSetSelection
7+
target:
8+
type: primitive
9+
modifiers:
10+
- type: everyScope
11+
scopeType: {type: value}
12+
usePrePhraseSnapshot: true
13+
initialState:
14+
documentContents: |-
15+
function aaa() {
16+
const bbb = 0;
17+
const ccc = 0;
18+
}
19+
selections:
20+
- anchor: {line: 2, character: 18}
21+
active: {line: 2, character: 18}
22+
marks: {}
23+
finalState:
24+
documentContents: |-
25+
function aaa() {
26+
const bbb = ;
27+
const ccc = ;
28+
}
29+
selections:
30+
- anchor: {line: 1, character: 16}
31+
active: {line: 1, character: 16}
32+
- anchor: {line: 2, character: 16}
33+
active: {line: 2, character: 16}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
languageId: javascript
2+
command:
3+
version: 6
4+
spokenForm: change every value
5+
action:
6+
name: clearAndSetSelection
7+
target:
8+
type: primitive
9+
modifiers:
10+
- type: everyScope
11+
scopeType: {type: value}
12+
usePrePhraseSnapshot: true
13+
initialState:
14+
documentContents: |-
15+
const bbb = 0;
16+
const ccc = 0;
17+
selections:
18+
- anchor: {line: 1, character: 14}
19+
active: {line: 1, character: 14}
20+
marks: {}
21+
finalState:
22+
documentContents: |-
23+
const bbb = ;
24+
const ccc = ;
25+
selections:
26+
- anchor: {line: 0, character: 12}
27+
active: {line: 0, character: 12}
28+
- anchor: {line: 1, character: 12}
29+
active: {line: 1, character: 12}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
languageId: javascript
2+
command:
3+
version: 6
4+
spokenForm: change name
5+
action:
6+
name: clearAndSetSelection
7+
target:
8+
type: primitive
9+
modifiers:
10+
- type: containingScope
11+
scopeType: {type: name}
12+
usePrePhraseSnapshot: true
13+
initialState:
14+
documentContents: const aaa = "bbb", ccc = "ddd";
15+
selections:
16+
- anchor: {line: 0, character: 30}
17+
active: {line: 0, character: 30}
18+
marks: {}
19+
finalState:
20+
documentContents: const aaa = "bbb", = "ddd";
21+
selections:
22+
- anchor: {line: 0, character: 19}
23+
active: {line: 0, character: 19}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
languageId: javascript
2+
command:
3+
version: 6
4+
spokenForm: change name
5+
action:
6+
name: clearAndSetSelection
7+
target:
8+
type: primitive
9+
modifiers:
10+
- type: containingScope
11+
scopeType: {type: name}
12+
usePrePhraseSnapshot: true
13+
initialState:
14+
documentContents: |-
15+
const aaa = 0;
16+
let bbb = 0;
17+
var hhh = 0;
18+
ccc = 0;
19+
kkk += 1;
20+
const ddd = 0, eee = 0;
21+
let fff = 0, ggg = 0;
22+
var iii = 0;
23+
export const jjj = 0;
24+
export let kkk = 0;
25+
export var lll = 0;
26+
export const mmm = 0, nnn = 0;
27+
export let ooo = 0, ppp = 0;
28+
selections:
29+
- anchor: {line: 0, character: 14}
30+
active: {line: 0, character: 14}
31+
- anchor: {line: 1, character: 12}
32+
active: {line: 1, character: 12}
33+
- anchor: {line: 2, character: 12}
34+
active: {line: 2, character: 12}
35+
- anchor: {line: 3, character: 8}
36+
active: {line: 3, character: 8}
37+
- anchor: {line: 4, character: 9}
38+
active: {line: 4, character: 9}
39+
- anchor: {line: 5, character: 23}
40+
active: {line: 5, character: 23}
41+
- anchor: {line: 6, character: 21}
42+
active: {line: 6, character: 21}
43+
- anchor: {line: 7, character: 12}
44+
active: {line: 7, character: 12}
45+
- anchor: {line: 8, character: 21}
46+
active: {line: 8, character: 21}
47+
- anchor: {line: 9, character: 19}
48+
active: {line: 9, character: 19}
49+
- anchor: {line: 10, character: 19}
50+
active: {line: 10, character: 19}
51+
- anchor: {line: 11, character: 30}
52+
active: {line: 11, character: 30}
53+
- anchor: {line: 12, character: 28}
54+
active: {line: 12, character: 28}
55+
marks: {}
56+
finalState:
57+
documentContents: |-
58+
const = 0;
59+
let = 0;
60+
var = 0;
61+
= 0;
62+
+= 1;
63+
const = 0, = 0;
64+
let = 0, = 0;
65+
var = 0;
66+
export const = 0;
67+
export let = 0;
68+
export var = 0;
69+
export const = 0, = 0;
70+
export let = 0, = 0;
71+
selections:
72+
- anchor: {line: 0, character: 6}
73+
active: {line: 0, character: 6}
74+
- anchor: {line: 1, character: 4}
75+
active: {line: 1, character: 4}
76+
- anchor: {line: 2, character: 4}
77+
active: {line: 2, character: 4}
78+
- anchor: {line: 3, character: 0}
79+
active: {line: 3, character: 0}
80+
- anchor: {line: 4, character: 0}
81+
active: {line: 4, character: 0}
82+
- anchor: {line: 5, character: 6}
83+
active: {line: 5, character: 6}
84+
- anchor: {line: 5, character: 12}
85+
active: {line: 5, character: 12}
86+
- anchor: {line: 6, character: 4}
87+
active: {line: 6, character: 4}
88+
- anchor: {line: 6, character: 10}
89+
active: {line: 6, character: 10}
90+
- anchor: {line: 7, character: 4}
91+
active: {line: 7, character: 4}
92+
- anchor: {line: 8, character: 13}
93+
active: {line: 8, character: 13}
94+
- anchor: {line: 9, character: 11}
95+
active: {line: 9, character: 11}
96+
- anchor: {line: 10, character: 11}
97+
active: {line: 10, character: 11}
98+
- anchor: {line: 11, character: 13}
99+
active: {line: 11, character: 13}
100+
- anchor: {line: 11, character: 19}
101+
active: {line: 11, character: 19}
102+
- anchor: {line: 12, character: 11}
103+
active: {line: 12, character: 11}
104+
- anchor: {line: 12, character: 17}
105+
active: {line: 12, character: 17}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
languageId: javascript
2+
command:
3+
version: 6
4+
spokenForm: change name
5+
action:
6+
name: clearAndSetSelection
7+
target:
8+
type: primitive
9+
modifiers:
10+
- type: containingScope
11+
scopeType: {type: name}
12+
usePrePhraseSnapshot: true
13+
initialState:
14+
documentContents: |-
15+
hhh = 0, iii = 0, jjj=0;
16+
lll += 1, mmm += 1, nnn += 1;
17+
selections:
18+
- anchor: {line: 0, character: 0}
19+
active: {line: 0, character: 0}
20+
- anchor: {line: 0, character: 9}
21+
active: {line: 0, character: 9}
22+
- anchor: {line: 0, character: 18}
23+
active: {line: 0, character: 18}
24+
- anchor: {line: 1, character: 0}
25+
active: {line: 1, character: 0}
26+
- anchor: {line: 1, character: 10}
27+
active: {line: 1, character: 10}
28+
- anchor: {line: 1, character: 20}
29+
active: {line: 1, character: 20}
30+
marks: {}
31+
finalState:
32+
documentContents: |2-
33+
= 0, = 0, =0;
34+
+= 1, += 1, += 1;
35+
selections:
36+
- anchor: {line: 0, character: 0}
37+
active: {line: 0, character: 0}
38+
- anchor: {line: 0, character: 6}
39+
active: {line: 0, character: 6}
40+
- anchor: {line: 0, character: 12}
41+
active: {line: 0, character: 12}
42+
- anchor: {line: 1, character: 0}
43+
active: {line: 1, character: 0}
44+
- anchor: {line: 1, character: 7}
45+
active: {line: 1, character: 7}
46+
- anchor: {line: 1, character: 14}
47+
active: {line: 1, character: 14}

0 commit comments

Comments
 (0)