diff --git a/packages/app-web-docs/src/docs/contributing/tree-sitter-query-syntax.md b/packages/app-web-docs/src/docs/contributing/tree-sitter-query-syntax.md
index dd18da0102..06e5f64824 100644
--- a/packages/app-web-docs/src/docs/contributing/tree-sitter-query-syntax.md
+++ b/packages/app-web-docs/src/docs/contributing/tree-sitter-query-syntax.md
@@ -19,6 +19,24 @@ In addition to the above aspects, you can also use the following inline operator
- `@foo.start` and `@foo.end` to construct the scope using a range between two nodes (inclusive).
- `@foo.startOf` and `@foo.endOf` to refer to the start and end positions of a node. For example, you could use `@foo.start.endOf` to indicate that the scope should start at the end of the node.
+## Iteration capture aliases
+
+Use these aliases when several scopes share an iteration range:
+
+- `@statementNameValue.iteration` expands to `@statement.iteration`,
+ `@name.iteration`, and `@value.iteration`.
+- `@statementNameValueType.iteration` expands to the same captures plus
+ `@type.iteration`, for languages and contexts that need type iteration.
+
+Both aliases support `.domain`, `.start.endOf`, `.end.startOf`, and `.end.endOf`. For example, a Java block can share iteration boundaries without repeating the pattern for each scope:
+
+```scm
+(_
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
+)
+```
+
## Query predicate operators
We also support a number of query predicate operators for modifying the scope. See [`queryPredicateOperators.ts`](../../../../../packages/lib-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts) for a list of available operators.
diff --git a/packages/app-web-docs/src/docs/user/languages/fixtures/shellscript.json b/packages/app-web-docs/src/docs/user/languages/fixtures/shellscript.json
index 315d3fec84..1e0a43e589 100644
--- a/packages/app-web-docs/src/docs/user/languages/fixtures/shellscript.json
+++ b/packages/app-web-docs/src/docs/user/languages/fixtures/shellscript.json
@@ -915,6 +915,46 @@
}
]
},
+ {
+ "name": "scopes/shellscript/name/name.iteration.block2",
+ "languageId": "shellscript",
+ "facet": "name.iteration.block",
+ "code": "if true; then\n :\nelif false; then\n :\nelse\n :\nfi",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-6:2"
+ }
+ ],
+ "domain": "0:0-6:2"
+ },
+ {
+ "targets": [
+ {
+ "content": "0:13-2:0"
+ }
+ ],
+ "domain": "0:13-2:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "2:16-4:0"
+ }
+ ],
+ "domain": "2:16-4:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "4:4-6:0"
+ }
+ ],
+ "domain": "4:4-6:0"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/name/name.iteration.block3",
"languageId": "shellscript",
@@ -939,6 +979,30 @@
}
]
},
+ {
+ "name": "scopes/shellscript/name/name.iteration.block4",
+ "languageId": "shellscript",
+ "facet": "name.iteration.block",
+ "code": "case $foo in\n 0) bar=0 ;;\nesac",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-2:4"
+ }
+ ],
+ "domain": "0:0-2:4"
+ },
+ {
+ "targets": [
+ {
+ "content": "1:6-1:13"
+ }
+ ],
+ "domain": "1:6-1:13"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/name/name.iteration.document",
"languageId": "shellscript",
@@ -1441,6 +1505,46 @@
}
]
},
+ {
+ "name": "scopes/shellscript/statement/statement.iteration.block2",
+ "languageId": "shellscript",
+ "facet": "statement.iteration.block",
+ "code": "if true; then\n :\nelif false; then\n :\nelse\n :\nfi",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-6:2"
+ }
+ ],
+ "domain": "0:0-6:2"
+ },
+ {
+ "targets": [
+ {
+ "content": "0:13-2:0"
+ }
+ ],
+ "domain": "0:13-2:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "2:16-4:0"
+ }
+ ],
+ "domain": "2:16-4:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "4:4-6:0"
+ }
+ ],
+ "domain": "4:4-6:0"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/statement/statement.iteration.block3",
"languageId": "shellscript",
@@ -1465,6 +1569,30 @@
}
]
},
+ {
+ "name": "scopes/shellscript/statement/statement.iteration.block4",
+ "languageId": "shellscript",
+ "facet": "statement.iteration.block",
+ "code": "case $foo in\n 0) bar=0 ;;\nesac",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-2:4"
+ }
+ ],
+ "domain": "0:0-2:4"
+ },
+ {
+ "targets": [
+ {
+ "content": "1:6-1:13"
+ }
+ ],
+ "domain": "1:6-1:13"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/statement/statement.iteration.document",
"languageId": "shellscript",
@@ -1864,6 +1992,46 @@
}
]
},
+ {
+ "name": "scopes/shellscript/value/value.iteration.block2",
+ "languageId": "shellscript",
+ "facet": "value.iteration.block",
+ "code": "if true; then\n :\nelif false; then\n :\nelse\n :\nfi",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-6:2"
+ }
+ ],
+ "domain": "0:0-6:2"
+ },
+ {
+ "targets": [
+ {
+ "content": "0:13-2:0"
+ }
+ ],
+ "domain": "0:13-2:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "2:16-4:0"
+ }
+ ],
+ "domain": "2:16-4:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "4:4-6:0"
+ }
+ ],
+ "domain": "4:4-6:0"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/value/value.iteration.block3",
"languageId": "shellscript",
@@ -1888,6 +2056,30 @@
}
]
},
+ {
+ "name": "scopes/shellscript/value/value.iteration.block4",
+ "languageId": "shellscript",
+ "facet": "value.iteration.block",
+ "code": "case $foo in\n 0) bar=0 ;;\nesac",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-2:4"
+ }
+ ],
+ "domain": "0:0-2:4"
+ },
+ {
+ "targets": [
+ {
+ "content": "1:6-1:13"
+ }
+ ],
+ "domain": "1:6-1:13"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/value/value.iteration.document",
"languageId": "shellscript",
diff --git a/packages/app-web-docs/src/docs/user/languages/shellscript.mdx b/packages/app-web-docs/src/docs/user/languages/shellscript.mdx
index aafa6a23df..314a525ac1 100644
--- a/packages/app-web-docs/src/docs/user/languages/shellscript.mdx
+++ b/packages/app-web-docs/src/docs/user/languages/shellscript.mdx
@@ -313,8 +313,12 @@ Below are visualizations of all our scope tests for this language. These were cr
+
+
+
+
#### 9. Name (iteration document)
Iteration scope for names: the entire document including leading and trailing empty lines.
@@ -469,8 +473,12 @@ Below are visualizations of all our scope tests for this language. These were cr
+
+
+
+
#### 19. Statement (iteration document)
Iteration scope for statements: the entire document including leading and trailing empty lines.
@@ -537,8 +545,12 @@ Below are visualizations of all our scope tests for this language. These were cr
+
+
+
+
#### 10. Value (iteration document)
Iteration scope for values: the entire document including leading and trailing empty lines.
diff --git a/packages/app-web-docs/src/docs/user/scopes/fixtures/name.json b/packages/app-web-docs/src/docs/user/scopes/fixtures/name.json
index e2d0b04bd6..f5e0e35291 100644
--- a/packages/app-web-docs/src/docs/user/scopes/fixtures/name.json
+++ b/packages/app-web-docs/src/docs/user/scopes/fixtures/name.json
@@ -12083,6 +12083,46 @@
}
]
},
+ {
+ "name": "scopes/shellscript/name/name.iteration.block2",
+ "languageId": "shellscript",
+ "facet": "name.iteration.block",
+ "code": "if true; then\n :\nelif false; then\n :\nelse\n :\nfi",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-6:2"
+ }
+ ],
+ "domain": "0:0-6:2"
+ },
+ {
+ "targets": [
+ {
+ "content": "0:13-2:0"
+ }
+ ],
+ "domain": "0:13-2:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "2:16-4:0"
+ }
+ ],
+ "domain": "2:16-4:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "4:4-6:0"
+ }
+ ],
+ "domain": "4:4-6:0"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/name/name.iteration.block3",
"languageId": "shellscript",
@@ -12107,6 +12147,30 @@
}
]
},
+ {
+ "name": "scopes/shellscript/name/name.iteration.block4",
+ "languageId": "shellscript",
+ "facet": "name.iteration.block",
+ "code": "case $foo in\n 0) bar=0 ;;\nesac",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-2:4"
+ }
+ ],
+ "domain": "0:0-2:4"
+ },
+ {
+ "targets": [
+ {
+ "content": "1:6-1:13"
+ }
+ ],
+ "domain": "1:6-1:13"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/name/name.iteration.document",
"languageId": "shellscript",
diff --git a/packages/app-web-docs/src/docs/user/scopes/fixtures/statement.json b/packages/app-web-docs/src/docs/user/scopes/fixtures/statement.json
index fc80eec426..fb93209a8c 100644
--- a/packages/app-web-docs/src/docs/user/scopes/fixtures/statement.json
+++ b/packages/app-web-docs/src/docs/user/scopes/fixtures/statement.json
@@ -10926,6 +10926,46 @@
}
]
},
+ {
+ "name": "scopes/shellscript/statement/statement.iteration.block2",
+ "languageId": "shellscript",
+ "facet": "statement.iteration.block",
+ "code": "if true; then\n :\nelif false; then\n :\nelse\n :\nfi",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-6:2"
+ }
+ ],
+ "domain": "0:0-6:2"
+ },
+ {
+ "targets": [
+ {
+ "content": "0:13-2:0"
+ }
+ ],
+ "domain": "0:13-2:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "2:16-4:0"
+ }
+ ],
+ "domain": "2:16-4:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "4:4-6:0"
+ }
+ ],
+ "domain": "4:4-6:0"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/statement/statement.iteration.block3",
"languageId": "shellscript",
@@ -10950,6 +10990,30 @@
}
]
},
+ {
+ "name": "scopes/shellscript/statement/statement.iteration.block4",
+ "languageId": "shellscript",
+ "facet": "statement.iteration.block",
+ "code": "case $foo in\n 0) bar=0 ;;\nesac",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-2:4"
+ }
+ ],
+ "domain": "0:0-2:4"
+ },
+ {
+ "targets": [
+ {
+ "content": "1:6-1:13"
+ }
+ ],
+ "domain": "1:6-1:13"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/statement/statement.iteration.document",
"languageId": "shellscript",
diff --git a/packages/app-web-docs/src/docs/user/scopes/fixtures/value.json b/packages/app-web-docs/src/docs/user/scopes/fixtures/value.json
index c868b52dbc..49eecbc5c5 100644
--- a/packages/app-web-docs/src/docs/user/scopes/fixtures/value.json
+++ b/packages/app-web-docs/src/docs/user/scopes/fixtures/value.json
@@ -8636,6 +8636,46 @@
}
]
},
+ {
+ "name": "scopes/shellscript/value/value.iteration.block2",
+ "languageId": "shellscript",
+ "facet": "value.iteration.block",
+ "code": "if true; then\n :\nelif false; then\n :\nelse\n :\nfi",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-6:2"
+ }
+ ],
+ "domain": "0:0-6:2"
+ },
+ {
+ "targets": [
+ {
+ "content": "0:13-2:0"
+ }
+ ],
+ "domain": "0:13-2:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "2:16-4:0"
+ }
+ ],
+ "domain": "2:16-4:0"
+ },
+ {
+ "targets": [
+ {
+ "content": "4:4-6:0"
+ }
+ ],
+ "domain": "4:4-6:0"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/value/value.iteration.block3",
"languageId": "shellscript",
@@ -8660,6 +8700,30 @@
}
]
},
+ {
+ "name": "scopes/shellscript/value/value.iteration.block4",
+ "languageId": "shellscript",
+ "facet": "value.iteration.block",
+ "code": "case $foo in\n 0) bar=0 ;;\nesac",
+ "scopes": [
+ {
+ "targets": [
+ {
+ "content": "0:0-2:4"
+ }
+ ],
+ "domain": "0:0-2:4"
+ },
+ {
+ "targets": [
+ {
+ "content": "1:6-1:13"
+ }
+ ],
+ "domain": "1:6-1:13"
+ }
+ ]
+ },
{
"name": "scopes/shellscript/value/value.iteration.document",
"languageId": "shellscript",
diff --git a/packages/app-web-docs/src/docs/user/scopes/name.mdx b/packages/app-web-docs/src/docs/user/scopes/name.mdx
index 1763ce0176..54049c3157 100644
--- a/packages/app-web-docs/src/docs/user/scopes/name.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/name.mdx
@@ -1593,8 +1593,12 @@ Default: `name`
+
+
+
+
##### Talon
diff --git a/packages/app-web-docs/src/docs/user/scopes/statement.mdx b/packages/app-web-docs/src/docs/user/scopes/statement.mdx
index 5ebbd68846..acb28847df 100644
--- a/packages/app-web-docs/src/docs/user/scopes/statement.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/statement.mdx
@@ -1997,8 +1997,12 @@ Default: `state`
+
+
+
+
##### Talon
diff --git a/packages/app-web-docs/src/docs/user/scopes/value.mdx b/packages/app-web-docs/src/docs/user/scopes/value.mdx
index e5d2ff3778..73db810d63 100644
--- a/packages/app-web-docs/src/docs/user/scopes/value.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/value.mdx
@@ -1275,8 +1275,12 @@ Default: `value`
+
+
+
+
##### Talon
diff --git a/packages/lib-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts b/packages/lib-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts
index fc30fcfd6f..821ec670f0 100644
--- a/packages/lib-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts
+++ b/packages/lib-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts
@@ -6,6 +6,7 @@ import type {
TextDocument,
TreeSitter,
} from "@cursorless/lib-common";
+import { expandCaptureName, expandCaptures } from "./captureAliases";
import type { ScopeCaptureName } from "./captureNames";
import {
getNormalizedCaptureIndex,
@@ -36,6 +37,8 @@ import { treeSitterQueryCache } from "./TreeSitterQueryCache";
*/
export class TreeSitterQuery {
private shouldCheckCaptures: boolean;
+ private normalizedCaptureNames = new Set();
+ private captureAliases = new Map();
private constructor(
private ide: IDE,
@@ -54,6 +57,16 @@ export class TreeSitterQuery {
private patternPredicates: PatternPredicate[][],
) {
this.shouldCheckCaptures = ide.runMode !== "production";
+
+ for (const name of query.captureNames) {
+ const expandedNames = expandCaptureName(name);
+ if (expandedNames.length > 1) {
+ this.captureAliases.set(name, expandedNames);
+ }
+ for (const expandedName of expandedNames) {
+ this.normalizedCaptureNames.add(getNormalizedCaptureName(expandedName));
+ }
+ }
}
static create(
@@ -68,9 +81,7 @@ export class TreeSitterQuery {
}
hasCapture(name: string): boolean {
- return this.query.captureNames.some(
- (n) => getNormalizedCaptureName(n) === name,
- );
+ return this.normalizedCaptureNames.has(name);
}
matches(
@@ -123,16 +134,13 @@ export class TreeSitterQuery {
end: Position | undefined,
captureNameFilter: Set | undefined,
): QueryMatch[] {
+ const aliases = this.filterCaptureAliases(captureNameFilter);
+ const matchesFilter = this.createCaptureFilter(captureNameFilter, aliases);
const matches = this.getTreeMatches(document, start, end);
const results: QueryMatch[] = [];
for (const match of matches) {
- if (
- captureNameFilter != null &&
- !match.captures.some((capture) =>
- captureNameFilter.has(getNormalizedCaptureIndex(capture.name)),
- )
- ) {
+ if (matchesFilter != null && !match.captures.some(matchesFilter)) {
continue;
}
@@ -147,8 +155,13 @@ export class TreeSitterQuery {
match,
patternPredicates,
captureNameFilter,
+ aliases,
)
- : this.createQueryCapturesWithoutPredicates(match, captureNameFilter);
+ : this.createQueryCapturesWithoutPredicates(
+ match,
+ captureNameFilter,
+ aliases,
+ );
if (captures.length > 0) {
results.push({ captures });
@@ -158,6 +171,39 @@ export class TreeSitterQuery {
return results;
}
+ private filterCaptureAliases(captureNameFilter: Set | undefined) {
+ if (captureNameFilter == null || this.captureAliases.size === 0) {
+ return this.captureAliases;
+ }
+
+ const aliases = new Map();
+ for (const [alias, names] of this.captureAliases) {
+ aliases.set(
+ alias,
+ names.filter((name) =>
+ captureNameFilter.has(getNormalizedCaptureIndex(name)),
+ ),
+ );
+ }
+ return aliases;
+ }
+
+ private createCaptureFilter(
+ captureNameFilter: Set | undefined,
+ aliases: ReadonlyMap,
+ ) {
+ if (captureNameFilter == null) {
+ return undefined;
+ }
+ if (aliases.size === 0) {
+ return (capture: treeSitter.QueryCapture) =>
+ captureNameFilter.has(getNormalizedCaptureIndex(capture.name));
+ }
+ return (capture: treeSitter.QueryCapture) =>
+ captureNameFilter.has(getNormalizedCaptureIndex(capture.name)) ||
+ (aliases.get(capture.name)?.length ?? 0) > 0;
+ }
+
private getTreeMatches(
document: TextDocument,
start: Position | undefined,
@@ -175,6 +221,7 @@ export class TreeSitterQuery {
match: treeSitter.QueryMatch,
predicates: PatternPredicate[],
captureNameFilter: Set | undefined,
+ aliases: ReadonlyMap,
): QueryCapture[] {
const captures: MutableQueryCapture[] = [];
@@ -207,7 +254,10 @@ export class TreeSitterQuery {
// with names `@foo`, `@foo.start`, and `@foo.end` to have the same
// name, for which we'd return a capture with name `foo`.
- for (const capture of captures) {
+ const expandedCaptures =
+ aliases.size === 0 ? captures : expandCaptures(captures, aliases);
+
+ for (const capture of expandedCaptures) {
if (
captureNameFilter != null &&
!captureNameFilter.has(getNormalizedCaptureIndex(capture.name))
@@ -248,6 +298,7 @@ export class TreeSitterQuery {
private createQueryCapturesWithoutPredicates(
match: treeSitter.QueryMatch,
captureNameFilter: Set | undefined,
+ aliases: ReadonlyMap,
): QueryCapture[] {
const result: QueryCapture[] = [];
const map = new Map<
@@ -258,7 +309,12 @@ export class TreeSitterQuery {
}
>();
- for (const capture of match.captures) {
+ const expandedCaptures =
+ aliases.size === 0
+ ? match.captures
+ : expandCaptures(match.captures, aliases);
+
+ for (const capture of expandedCaptures) {
if (
captureNameFilter != null &&
!captureNameFilter.has(getNormalizedCaptureIndex(capture.name))
diff --git a/packages/lib-engine/src/languages/TreeSitterQuery/captureAliases.test.ts b/packages/lib-engine/src/languages/TreeSitterQuery/captureAliases.test.ts
new file mode 100644
index 0000000000..b983df92cf
--- /dev/null
+++ b/packages/lib-engine/src/languages/TreeSitterQuery/captureAliases.test.ts
@@ -0,0 +1,196 @@
+import assert from "node:assert/strict";
+import {
+ asyncSafety,
+ FakeIDE,
+ InMemoryTextEditor,
+ Position,
+} from "@cursorless/lib-common";
+import { TestTreeSitter } from "../../testUtil/TestTreeSitter";
+import { expandCaptureName } from "./captureAliases";
+import { TreeSitterQuery } from "./TreeSitterQuery";
+import { treeSitterQueryCache } from "./TreeSitterQueryCache";
+
+for (const alias of [
+ "statementNameValue.iteration",
+ "statementNameValueType.iteration",
+]) {
+ suite(`${alias} capture alias`, () => {
+ const ide = new FakeIDE();
+ const treeSitter = new TestTreeSitter();
+ const names = [
+ "statement.iteration",
+ "name.iteration",
+ "value.iteration",
+ ...(alias === "statementNameValueType.iteration"
+ ? ["type.iteration"]
+ : []),
+ ];
+
+ suiteSetup(
+ asyncSafety(async () => {
+ await treeSitter.loadLanguage("shellscript");
+ }),
+ );
+
+ setup(() => treeSitterQueryCache.clear());
+
+ test("preserves suffixes and leaves unrelated names unchanged", () => {
+ for (const suffix of [
+ "",
+ ".start.endOf",
+ ".end.startOf",
+ ".end.endOf",
+ ".domain",
+ ]) {
+ assert.deepEqual(
+ expandCaptureName(`${alias}${suffix}`),
+ names.map((name) => `${name}${suffix}`),
+ );
+ }
+ assert.deepEqual(expandCaptureName("interior"), ["interior"]);
+ assert.deepEqual(expandCaptureName(`${alias}Other`), [`${alias}Other`]);
+ });
+
+ for (const withPredicates of [false, true]) {
+ test(`expands and filters boundary captures with predicates: ${withPredicates}`, () => {
+ const { query, document } = createQuery(`
+ ((compound_statement
+ "{" @${alias}.start.endOf
+ "}" @${alias}.end.startOf
+ ) ${withPredicates ? `(#type? @${alias}.start.endOf "{")` : ""})
+ `);
+ for (const name of names) {
+ assert.equal(query.hasCapture(name), true);
+ }
+ assert.equal(query.hasCapture(alias), false);
+ assert.equal(query.hasCapture("interior"), false);
+ assert.equal(
+ query.hasCapture("type.iteration"),
+ names.includes("type.iteration"),
+ );
+
+ const matches = query.matches(
+ document,
+ new Position(0, 0),
+ new Position(0, 15),
+ );
+ assert.equal(matches.length, 1);
+ assert.deepEqual(
+ matches[0].captures.map((c) => c.name),
+ names,
+ );
+ for (const capture of matches[0].captures) {
+ assert.equal(document.getText(capture.range), " bar=0; ");
+ }
+
+ for (const scope of [
+ "statement",
+ "name",
+ "value",
+ ...(alias === "statementNameValueType.iteration"
+ ? ["type" as const]
+ : []),
+ ] as const) {
+ const filtered = query.matchesForScopeTypes(document, [scope]);
+ assert.equal(filtered.length, 1);
+ assert.equal(filtered[0].captures.length, 1);
+ assert.equal(filtered[0].captures[0].name, `${scope}.iteration`);
+ assert.equal(
+ document.getText(filtered[0].captures[0].range),
+ " bar=0; ",
+ );
+ }
+ assert.deepEqual(query.matchesForScopeTypes(document, ["comment"]), []);
+ });
+ }
+
+ test("supports an inclusive end boundary on the containing node", () => {
+ const { query, document } = createQuery(`
+ (compound_statement
+ "{" @${alias}.start.endOf
+ ) @${alias}.end.endOf
+ `);
+ const matches = query.matchesForScopeTypes(document, [
+ "statement",
+ "name",
+ "value",
+ "type",
+ ]);
+ assert.equal(matches.length, 1);
+ assert.deepEqual(
+ matches[0].captures.map((capture) => capture.name),
+ names,
+ );
+ for (const capture of matches[0].captures) {
+ assert.equal(document.getText(capture.range), " bar=0; }");
+ }
+ });
+
+ test("shares capture slots with ordinary captures", () => {
+ const { query, document } = createQuery(`
+ (compound_statement
+ "{" @${alias}.start.endOf @branch.start @branch.removal.start
+ "}" @${alias}.end.startOf @branch.end @branch.removal.end)
+ `);
+ const matches = query.matches(
+ document,
+ new Position(0, 0),
+ new Position(0, 15),
+ );
+ assert.equal(matches.length, 1);
+ assert.deepEqual(
+ matches[0].captures.map((capture) => capture.name),
+ [...names, "branch", "branch.removal"],
+ );
+ const branches = query.matchesForScopeTypes(document, ["branch"]);
+ assert.equal(branches[0].captures.length, 2);
+ for (const capture of branches[0].captures) {
+ assert.equal(document.getText(capture.range), "{ bar=0; }");
+ }
+ });
+
+ test("propagates predicate range and metadata changes to every alias target", () => {
+ const { query, document } = createQuery(`
+ ((compound_statement) @${alias}
+ (#shrink-to-match! @${alias} "[{](?[^}]*)[}]")
+ (#insertion-delimiter! @${alias} ", ")
+ (#allow-multiple! @${alias}))
+ `);
+ const matches = query.matchesForScopeTypes(document, [
+ "statement",
+ "name",
+ "value",
+ "type",
+ ]);
+ assert.equal(matches.length, 1);
+ assert.equal(matches[0].captures.length, names.length);
+ for (const capture of matches[0].captures) {
+ assert.equal(document.getText(capture.range), " bar=0; ");
+ assert.equal(capture.insertionDelimiter, ", ");
+ assert.equal(capture.allowMultiple, true);
+ }
+ });
+
+ test("rejecting a predicate discards every expanded capture", () => {
+ const { query, document } = createQuery(`
+ ((compound_statement) @${alias}
+ (#not-type? @${alias} compound_statement))
+ `);
+ assert.deepEqual(query.matchesForScopeTypes(document, ["statement"]), []);
+ });
+
+ function createQuery(source: string) {
+ const editor = new InMemoryTextEditor({
+ ide,
+ languageId: "shellscript",
+ content: "foo() { bar=0; }",
+ });
+ const rawQuery = treeSitter.createQuery("shellscript", source);
+ assert.ok(rawQuery);
+ return {
+ document: editor.document,
+ query: TreeSitterQuery.create(ide, "shellscript", treeSitter, rawQuery),
+ };
+ }
+ });
+}
diff --git a/packages/lib-engine/src/languages/TreeSitterQuery/captureAliases.ts b/packages/lib-engine/src/languages/TreeSitterQuery/captureAliases.ts
new file mode 100644
index 0000000000..4ff9a3613b
--- /dev/null
+++ b/packages/lib-engine/src/languages/TreeSitterQuery/captureAliases.ts
@@ -0,0 +1,82 @@
+const statementNameValue = [
+ "statement.iteration",
+ "name.iteration",
+ "value.iteration",
+];
+const statementNameValueType = [...statementNameValue, "type.iteration"];
+const statementNameValueDomain = statementNameValue.map(
+ (name) => `${name}.domain`,
+);
+const statementNameValueTypeDomain = statementNameValueType.map(
+ (name) => `${name}.domain`,
+);
+const statementNameValueStart = statementNameValue.map(
+ (name) => `${name}.start.endOf`,
+);
+const statementNameValueEnd = statementNameValue.map(
+ (name) => `${name}.end.startOf`,
+);
+const statementNameValueTypeStartExclusive = statementNameValueType.map(
+ (name) => `${name}.start.endOf`,
+);
+const statementNameValueTypeEndExclusive = statementNameValueType.map(
+ (name) => `${name}.end.startOf`,
+);
+const statementNameValueEndInclusive = statementNameValue.map(
+ (name) => `${name}.end.endOf`,
+);
+const statementNameValueTypeEndInclusive = statementNameValueType.map(
+ (name) => `${name}.end.endOf`,
+);
+
+/** Expand shared captures after Tree-sitter has matched the query. */
+export function expandCaptureName(name: string): string[] {
+ switch (name) {
+ case "statementNameValue.iteration":
+ return statementNameValue;
+ case "statementNameValueType.iteration":
+ return statementNameValueType;
+ case "statementNameValue.iteration.domain":
+ return statementNameValueDomain;
+ case "statementNameValueType.iteration.domain":
+ return statementNameValueTypeDomain;
+ case "statementNameValue.iteration.start.endOf":
+ return statementNameValueStart;
+ case "statementNameValue.iteration.end.startOf":
+ return statementNameValueEnd;
+ case "statementNameValueType.iteration.start.endOf":
+ return statementNameValueTypeStartExclusive;
+ case "statementNameValueType.iteration.end.startOf":
+ return statementNameValueTypeEndExclusive;
+ case "statementNameValue.iteration.end.endOf":
+ return statementNameValueEndInclusive;
+ case "statementNameValueType.iteration.end.endOf":
+ return statementNameValueTypeEndInclusive;
+ default:
+ return [name];
+ }
+}
+
+/** Preserve predicate changes while giving each expanded capture its own name. */
+export function expandCaptures(
+ captures: readonly T[],
+ aliases: ReadonlyMap,
+): readonly T[] {
+ let result: T[] | undefined;
+
+ for (let i = 0; i < captures.length; i++) {
+ const capture = captures[i];
+ const names = aliases.get(capture.name);
+
+ if (names == null) {
+ result?.push(capture);
+ } else {
+ result ??= captures.slice(0, i);
+ for (const name of names) {
+ result.push({ ...capture, name });
+ }
+ }
+ }
+
+ return result ?? captures;
+}
diff --git a/packages/lib-engine/src/languages/TreeSitterQuery/captureNames.ts b/packages/lib-engine/src/languages/TreeSitterQuery/captureNames.ts
index 12f0b203ce..1ff3b488c3 100644
--- a/packages/lib-engine/src/languages/TreeSitterQuery/captureNames.ts
+++ b/packages/lib-engine/src/languages/TreeSitterQuery/captureNames.ts
@@ -2,6 +2,7 @@ import {
pseudoScopeTypeTypes,
simpleScopeTypeTypes,
} from "@cursorless/lib-common";
+import { expandCaptureName } from "./captureAliases";
const scopeCaptureNames = simpleScopeTypeTypes.filter(
(s) => !pseudoScopeTypeTypes.has(s),
@@ -97,7 +98,9 @@ function getScopeName(captureName: string): string {
}
export function isCaptureAllowed(captureName: string): boolean {
- return allowedCaptures.has(captureName);
+ return expandCaptureName(captureName).some((name) =>
+ allowedCaptures.has(name),
+ );
}
// Capture names missing normalized name can be things like '@_dummy'
diff --git a/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts b/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts
index a967beaae1..95437ed96a 100644
--- a/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts
+++ b/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts
@@ -3,6 +3,43 @@ import { FakeIDE } from "@cursorless/lib-common";
import { validateQueryCaptures } from "./validateQueryCaptures";
const testCases: { name: string; isOk: boolean; content: string }[] = [
+ {
+ name: "Statement/name/value iteration alias",
+ isOk: true,
+ content: "(compound_statement) @statementNameValue.iteration",
+ },
+ {
+ name: "Statement/name/value iteration boundaries",
+ isOk: true,
+ content:
+ '(compound_statement "{" @statementNameValue.iteration.start.endOf "}" @statementNameValue.iteration.end.startOf)',
+ },
+ {
+ name: "Statement/name/value iteration domain",
+ isOk: true,
+ content: "(compound_statement) @statementNameValue.iteration.domain",
+ },
+ {
+ name: "Unknown iteration relationship",
+ isOk: false,
+ content: "(compound_statement) @statementNameValue.iteration.unknown",
+ },
+ {
+ name: "Statement/name/value/type iteration boundaries",
+ isOk: true,
+ content:
+ '(compound_statement "{" @statementNameValueType.iteration.start.endOf "}" @statementNameValueType.iteration.end.startOf)',
+ },
+ {
+ name: "Unknown type iteration relationship",
+ isOk: false,
+ content: "(compound_statement) @statementNameValueType.iteration.unknown",
+ },
+ {
+ name: "Alias without iteration",
+ isOk: false,
+ content: "(compound_statement) @statementNameValue",
+ },
{
name: "Scope captures",
isOk: true,
@@ -17,7 +54,17 @@ const testCases: { name: string; isOk: boolean; content: string }[] = [
name: "Position captures",
isOk: true,
content:
- "(if_statement) @statement.startOf @statement.leading.startOf @statement.trailing.endOf",
+ "(if_statement) @statement.leading.startOf @statement.trailing.endOf",
+ },
+ {
+ name: "Bare startOf capture",
+ isOk: false,
+ content: "(if_statement) @statement.startOf",
+ },
+ {
+ name: "Bare endOf capture",
+ isOk: false,
+ content: "(if_statement) @statement.endOf",
},
{
name: "Range captures",
@@ -60,6 +107,41 @@ const testCases: { name: string; isOk: boolean; content: string }[] = [
isOk: false,
content: "(if_statement) @unknown",
},
+ {
+ name: "Unknown capture before valid capture",
+ isOk: false,
+ content: "(if_statement) @unknown @statement",
+ },
+ {
+ name: "Unknown capture between valid captures",
+ isOk: false,
+ content: "(if_statement) @statement @unknown @interior",
+ },
+ {
+ name: "Unknown capture before comment",
+ isOk: false,
+ content: "(if_statement) @unknown ;; @statement",
+ },
+ {
+ name: "Indented and inline comments",
+ isOk: true,
+ content: " ;; @unknown\n(if_statement) @statement ; @unknown",
+ },
+ {
+ name: "Captures inside strings",
+ isOk: true,
+ content: '(#eq? @statement "text @unknown ; @other")',
+ },
+ {
+ name: "Escaped quotes inside strings",
+ isOk: true,
+ content: String.raw`(#eq? @statement "text \" @unknown")`,
+ },
+ {
+ name: "Unknown capture after string",
+ isOk: false,
+ content: '("@ignored" @unknown @statement)',
+ },
{
name: "Unknown relationship",
isOk: false,
diff --git a/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts b/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts
index ff0833d488..3c4d04bca9 100644
--- a/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts
+++ b/packages/lib-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts
@@ -2,10 +2,9 @@ import { showError } from "@cursorless/lib-common";
import type { IDE } from "@cursorless/lib-common";
import { isCaptureAllowed } from "./captureNames";
-// Not a comment. ie line is not starting with `;;`
-// Not a string.
-// Capture starts with `@` and is followed by words and/or dots
-const capturePattern = /^(?!;;).*(? 1 &&
!captureName.includes(".") &&
diff --git a/resources/fixtures/scopes/shellscript/name/name.iteration.block2.scope b/resources/fixtures/scopes/shellscript/name/name.iteration.block2.scope
new file mode 100644
index 0000000000..ceccbb0d8f
--- /dev/null
+++ b/resources/fixtures/scopes/shellscript/name/name.iteration.block2.scope
@@ -0,0 +1,47 @@
+if true; then
+ :
+elif false; then
+ :
+else
+ :
+fi
+---
+
+[#1 Content] =
+[#1 Domain] = 0:0-6:2
+ >-------------
+0| if true; then
+1| :
+2| elif false; then
+3| :
+4| else
+5| :
+6| fi
+ --<
+
+
+[#2 Content] =
+[#2 Domain] = 0:13-2:0
+ >
+0| if true; then
+1| :
+2| elif false; then
+ <
+
+
+[#3 Content] =
+[#3 Domain] = 2:16-4:0
+ >
+2| elif false; then
+3| :
+4| else
+ <
+
+
+[#4 Content] =
+[#4 Domain] = 4:4-6:0
+ >
+4| else
+5| :
+6| fi
+ <
diff --git a/resources/fixtures/scopes/shellscript/name/name.iteration.block4.scope b/resources/fixtures/scopes/shellscript/name/name.iteration.block4.scope
new file mode 100644
index 0000000000..90d9aad120
--- /dev/null
+++ b/resources/fixtures/scopes/shellscript/name/name.iteration.block4.scope
@@ -0,0 +1,18 @@
+case $foo in
+ 0) bar=0 ;;
+esac
+---
+
+[#1 Content] =
+[#1 Domain] = 0:0-2:4
+ >------------
+0| case $foo in
+1| 0) bar=0 ;;
+2| esac
+ ----<
+
+
+[#2 Content] =
+[#2 Domain] = 1:6-1:13
+ >-------<
+1| 0) bar=0 ;;
diff --git a/resources/fixtures/scopes/shellscript/statement/statement.iteration.block2.scope b/resources/fixtures/scopes/shellscript/statement/statement.iteration.block2.scope
new file mode 100644
index 0000000000..ceccbb0d8f
--- /dev/null
+++ b/resources/fixtures/scopes/shellscript/statement/statement.iteration.block2.scope
@@ -0,0 +1,47 @@
+if true; then
+ :
+elif false; then
+ :
+else
+ :
+fi
+---
+
+[#1 Content] =
+[#1 Domain] = 0:0-6:2
+ >-------------
+0| if true; then
+1| :
+2| elif false; then
+3| :
+4| else
+5| :
+6| fi
+ --<
+
+
+[#2 Content] =
+[#2 Domain] = 0:13-2:0
+ >
+0| if true; then
+1| :
+2| elif false; then
+ <
+
+
+[#3 Content] =
+[#3 Domain] = 2:16-4:0
+ >
+2| elif false; then
+3| :
+4| else
+ <
+
+
+[#4 Content] =
+[#4 Domain] = 4:4-6:0
+ >
+4| else
+5| :
+6| fi
+ <
diff --git a/resources/fixtures/scopes/shellscript/statement/statement.iteration.block4.scope b/resources/fixtures/scopes/shellscript/statement/statement.iteration.block4.scope
new file mode 100644
index 0000000000..90d9aad120
--- /dev/null
+++ b/resources/fixtures/scopes/shellscript/statement/statement.iteration.block4.scope
@@ -0,0 +1,18 @@
+case $foo in
+ 0) bar=0 ;;
+esac
+---
+
+[#1 Content] =
+[#1 Domain] = 0:0-2:4
+ >------------
+0| case $foo in
+1| 0) bar=0 ;;
+2| esac
+ ----<
+
+
+[#2 Content] =
+[#2 Domain] = 1:6-1:13
+ >-------<
+1| 0) bar=0 ;;
diff --git a/resources/fixtures/scopes/shellscript/value/value.iteration.block2.scope b/resources/fixtures/scopes/shellscript/value/value.iteration.block2.scope
new file mode 100644
index 0000000000..ceccbb0d8f
--- /dev/null
+++ b/resources/fixtures/scopes/shellscript/value/value.iteration.block2.scope
@@ -0,0 +1,47 @@
+if true; then
+ :
+elif false; then
+ :
+else
+ :
+fi
+---
+
+[#1 Content] =
+[#1 Domain] = 0:0-6:2
+ >-------------
+0| if true; then
+1| :
+2| elif false; then
+3| :
+4| else
+5| :
+6| fi
+ --<
+
+
+[#2 Content] =
+[#2 Domain] = 0:13-2:0
+ >
+0| if true; then
+1| :
+2| elif false; then
+ <
+
+
+[#3 Content] =
+[#3 Domain] = 2:16-4:0
+ >
+2| elif false; then
+3| :
+4| else
+ <
+
+
+[#4 Content] =
+[#4 Domain] = 4:4-6:0
+ >
+4| else
+5| :
+6| fi
+ <
diff --git a/resources/fixtures/scopes/shellscript/value/value.iteration.block4.scope b/resources/fixtures/scopes/shellscript/value/value.iteration.block4.scope
new file mode 100644
index 0000000000..90d9aad120
--- /dev/null
+++ b/resources/fixtures/scopes/shellscript/value/value.iteration.block4.scope
@@ -0,0 +1,18 @@
+case $foo in
+ 0) bar=0 ;;
+esac
+---
+
+[#1 Content] =
+[#1 Domain] = 0:0-2:4
+ >------------
+0| case $foo in
+1| 0) bar=0 ;;
+2| esac
+ ----<
+
+
+[#2 Content] =
+[#2 Domain] = 1:6-1:13
+ >-------<
+1| 0) bar=0 ;;
diff --git a/resources/queries/c.scm b/resources/queries/c.scm
index f510cdc37a..3331ad60b1 100644
--- a/resources/queries/c.scm
+++ b/resources/queries/c.scm
@@ -37,13 +37,8 @@
)
(
- (translation_unit) @statement.iteration @class.iteration @namedFunction.iteration
- (#document-range! @statement.iteration @class.iteration @namedFunction.iteration)
-)
-
-(
- (translation_unit) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (translation_unit) @statementNameValueType.iteration @class.iteration @namedFunction.iteration
+ (#document-range! @statementNameValueType.iteration @class.iteration @namedFunction.iteration)
)
;;!! { }
@@ -60,24 +55,14 @@
;;!! union Foo { };
;;! ^
(field_declaration_list
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
-)
-
-(field_declaration_list
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
)
;; Body of statements
(compound_statement
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
-)
-
-(compound_statement
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
)
(
diff --git a/resources/queries/csharp.scm b/resources/queries/csharp.scm
index edcadfe7da..9cf6bfcb5f 100644
--- a/resources/queries/csharp.scm
+++ b/resources/queries/csharp.scm
@@ -53,25 +53,15 @@
] @statement
(
- (compilation_unit) @statement.iteration @class.iteration @namedFunction.iteration
- (#document-range! @statement.iteration @class.iteration @namedFunction.iteration)
-)
-
-(
- (compilation_unit) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (compilation_unit) @statementNameValueType.iteration @class.iteration @namedFunction.iteration
+ (#document-range! @statementNameValueType.iteration @class.iteration @namedFunction.iteration)
)
;;!! { }
;;! ^
(block
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
-)
-
-(block
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
)
;;!! { }
@@ -164,15 +154,8 @@
(class_declaration
body: (_
- "{" @class.iteration.start.endOf @name.iteration.start.endOf @statement.iteration.start.endOf
- "}" @class.iteration.end.startOf @name.iteration.end.startOf @statement.iteration.end.startOf
- )
-)
-
-(class_declaration
- body: (_
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
+ "{" @class.iteration.start.endOf @statementNameValueType.iteration.start.endOf @namedFunction.iteration.start.endOf
+ "}" @class.iteration.end.startOf @statementNameValueType.iteration.end.startOf @namedFunction.iteration.end.startOf
)
)
@@ -250,13 +233,6 @@
)
] @namedFunction @name.domain
-(class_declaration
- body: (_
- "{" @namedFunction.iteration.start.endOf @name.iteration.start.endOf
- "}" @namedFunction.iteration.end.startOf @name.iteration.end.startOf
- )
-)
-
;;!! void foo() {}
[
(invocation_expression)
diff --git a/resources/queries/css.scm b/resources/queries/css.scm
index 0f8879f176..8acb5be7b2 100644
--- a/resources/queries/css.scm
+++ b/resources/queries/css.scm
@@ -101,12 +101,8 @@
;; Entire file
(
- (stylesheet) @name.iteration @collectionKey.iteration @value.iteration
- (#document-range! @name.iteration @collectionKey.iteration @value.iteration)
-)
-(
- (stylesheet) @statement.iteration
- (#document-range! @statement.iteration)
+ (stylesheet) @statementNameValue.iteration @collectionKey.iteration
+ (#document-range! @statementNameValue.iteration @collectionKey.iteration)
)
;; { }
diff --git a/resources/queries/dart.scm b/resources/queries/dart.scm
index edb48aa4e8..1e4d9b5491 100644
--- a/resources/queries/dart.scm
+++ b/resources/queries/dart.scm
@@ -23,13 +23,8 @@
)
(
- (program) @class.iteration @statement.iteration @namedFunction.iteration
- (#document-range! @class.iteration @statement.iteration @namedFunction.iteration)
-)
-
-(
- (program) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (program) @class.iteration @statementNameValueType.iteration @namedFunction.iteration
+ (#document-range! @class.iteration @statementNameValueType.iteration @namedFunction.iteration)
)
;;!! { }
@@ -44,13 +39,8 @@
;;!! { }
;;! ^
(block
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
-)
-
-(block
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
)
;;!! int foo = 0;
@@ -266,13 +256,8 @@
;;!! class Foo { }
;;! ^
(class_body
- "{" @namedFunction.iteration.start.endOf @statement.iteration.start.endOf
- "}" @namedFunction.iteration.end.startOf @statement.iteration.end.startOf
-)
-
-(class_body
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
+ "{" @namedFunction.iteration.start.endOf @statementNameValueType.iteration.start.endOf
+ "}" @namedFunction.iteration.end.startOf @statementNameValueType.iteration.end.startOf
)
;;!! var foo = 0;
diff --git a/resources/queries/go.scm b/resources/queries/go.scm
index b1b1c2f95f..f48137f794 100644
--- a/resources/queries/go.scm
+++ b/resources/queries/go.scm
@@ -52,21 +52,13 @@
)
(
- (source_file) @statement.iteration @class.iteration @namedFunction.iteration
- (#document-range! @statement.iteration @class.iteration @namedFunction.iteration)
-)
-(
- (source_file) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (source_file) @statementNameValueType.iteration @class.iteration @namedFunction.iteration
+ (#document-range! @statementNameValueType.iteration @class.iteration @namedFunction.iteration)
)
(block
- "{" @class.iteration.start.endOf @statement.iteration.start.endOf
- "}" @class.iteration.end.startOf @statement.iteration.end.startOf
-)
-(block
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
+ "{" @class.iteration.start.endOf @statementNameValueType.iteration.start.endOf
+ "}" @class.iteration.end.startOf @statementNameValueType.iteration.end.startOf
)
;;!! { }
diff --git a/resources/queries/java.scm b/resources/queries/java.scm
index 29d829abc3..339c8032f6 100644
--- a/resources/queries/java.scm
+++ b/resources/queries/java.scm
@@ -90,13 +90,8 @@
) @type @_.domain
(
- (program) @class.iteration @statement.iteration
- (#document-range! @class.iteration @statement.iteration)
-)
-
-(
- (program) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (program) @class.iteration @statementNameValueType.iteration
+ (#document-range! @class.iteration @statementNameValueType.iteration)
)
;;!! class MyClass { }
@@ -110,16 +105,8 @@
;;! ^
(
(_
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
- ) @_dummy
- (#type? @_dummy block class_body interface_body constructor_body)
-)
-
-(
- (_
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
) @_dummy
(#type? @_dummy block class_body interface_body constructor_body)
)
diff --git a/resources/queries/javascript.core.scm b/resources/queries/javascript.core.scm
index 6eb95cf6d7..de670b7665 100644
--- a/resources/queries/javascript.core.scm
+++ b/resources/queries/javascript.core.scm
@@ -48,13 +48,8 @@
)
(
- (program) @statement.iteration @class.iteration
- (#document-range! @statement.iteration @class.iteration)
-)
-
-(
- (program) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (program) @statementNameValueType.iteration @class.iteration
+ (#document-range! @statementNameValueType.iteration @class.iteration)
)
;;!! { }
@@ -519,16 +514,8 @@
;;! ^
(
(_
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
- ) @_dummy
- (#type? @_dummy statement_block class_body interface_body)
-)
-
-(
- (_
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
) @_dummy
(#type? @_dummy statement_block class_body interface_body)
)
diff --git a/resources/queries/kotlin.scm b/resources/queries/kotlin.scm
index a979d2e59f..3a75a183b0 100644
--- a/resources/queries/kotlin.scm
+++ b/resources/queries/kotlin.scm
@@ -36,27 +36,16 @@
;; Entire document, including leading and trailing whitespace
(
- (source_file) @class.iteration @statement.iteration @namedFunction.iteration
- (#document-range! @class.iteration @statement.iteration @namedFunction.iteration)
-)
-(
- (source_file) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (source_file) @class.iteration @statementNameValueType.iteration @namedFunction.iteration
+ (#document-range! @class.iteration @statementNameValueType.iteration @namedFunction.iteration)
)
;;!! { }
;;! ^
(
(_
- "{" @statement.iteration.start.endOf @namedFunction.iteration.start.endOf
- "}" @statement.iteration.end.startOf @namedFunction.iteration.end.startOf
- ) @_dummy
- (#not-type? @_dummy lambda_literal)
-)
-(
- (_
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf @namedFunction.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf @namedFunction.iteration.end.startOf
) @_dummy
(#not-type? @_dummy lambda_literal)
)
diff --git a/resources/queries/lua.scm b/resources/queries/lua.scm
index 80b022f9e5..e486701a4b 100644
--- a/resources/queries/lua.scm
+++ b/resources/queries/lua.scm
@@ -31,18 +31,13 @@
;; Document iteration scopes
(
- (chunk) @statement.iteration @namedFunction.iteration
- (#document-range! @statement.iteration @namedFunction.iteration)
-)
-(
- (chunk) @name.iteration @value.iteration
- (#document-range! @name.iteration @value.iteration)
+ (chunk) @statementNameValue.iteration @namedFunction.iteration
+ (#document-range! @statementNameValue.iteration @namedFunction.iteration)
)
;; Block iteration scopes
-(block) @statement.iteration @namedFunction.iteration
-(block) @name.iteration @value.iteration
+(block) @statementNameValue.iteration @namedFunction.iteration
;; Conditionals
diff --git a/resources/queries/php.scm b/resources/queries/php.scm
index 86f6321f86..4cbe5607b1 100644
--- a/resources/queries/php.scm
+++ b/resources/queries/php.scm
@@ -40,13 +40,8 @@
] @statement
(
- (program) @class.iteration @statement.iteration @namedFunction.iteration
- (#document-range! @class.iteration @statement.iteration @namedFunction.iteration)
-)
-
-(
- (program) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (program) @class.iteration @statementNameValueType.iteration @namedFunction.iteration
+ (#document-range! @class.iteration @statementNameValueType.iteration @namedFunction.iteration)
)
;;!! { }
@@ -61,8 +56,8 @@
;;!! { }
;;! ^
(compound_statement
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @statement.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @statement.iteration.end.startOf
+ "{" @statementNameValue.iteration.start.endOf
+ "}" @statementNameValue.iteration.end.startOf
)
[
@@ -167,12 +162,8 @@
;;!! class Foo { }
;;!! interface Foo { }
(declaration_list
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
-)
-(declaration_list
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
)
;;!! interface Foo {}
diff --git a/resources/queries/properties.scm b/resources/queries/properties.scm
index 5e61ac1513..f0162d75c7 100644
--- a/resources/queries/properties.scm
+++ b/resources/queries/properties.scm
@@ -1,5 +1,4 @@
-(file) @statement.iteration @comment.iteration
-(file) @collectionKey.iteration @name.iteration @value.iteration
+(file) @statementNameValue.iteration @comment.iteration @collectionKey.iteration
(comment) @comment @textFragment
diff --git a/resources/queries/python.scm b/resources/queries/python.scm
index 4a44d1d3e6..8cbd7ae835 100644
--- a/resources/queries/python.scm
+++ b/resources/queries/python.scm
@@ -309,8 +309,7 @@
;;! *****
;;!! c = 2
;;! *****>
-(block) @name.iteration @value.iteration @type.iteration
-(block) @statement.iteration
+(block) @statementNameValueType.iteration
;;!! {"a": 1, "b": 2, "c": 3}
;;! **********************
diff --git a/resources/queries/r.scm b/resources/queries/r.scm
index 29df41d408..170158a36d 100644
--- a/resources/queries/r.scm
+++ b/resources/queries/r.scm
@@ -29,21 +29,14 @@
] @statement
)
-(program) @statement.iteration @namedFunction.iteration
-(program) @name.iteration @value.iteration
+(program) @statementNameValue.iteration @namedFunction.iteration
;;!! { }
;;! ^
(_
.
- "{" @interior.start.endOf
- "}" @interior.end.startOf
- .
-)
-(_
- .
- "{" @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
- "}" @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
+ "{" @interior.start.endOf @statementNameValue.iteration.start.endOf
+ "}" @interior.end.startOf @statementNameValue.iteration.end.startOf
.
)
diff --git a/resources/queries/ruby.scm b/resources/queries/ruby.scm
index bae7dd2073..1636ff852e 100644
--- a/resources/queries/ruby.scm
+++ b/resources/queries/ruby.scm
@@ -103,13 +103,8 @@
)
(
- (program) @class.iteration @statement.iteration @namedFunction.iteration
- (#document-range! @class.iteration @statement.iteration @namedFunction.iteration)
-)
-
-(
- (program) @name.iteration @value.iteration
- (#document-range! @name.iteration @value.iteration)
+ (program) @class.iteration @statementNameValue.iteration @namedFunction.iteration
+ (#document-range! @class.iteration @statementNameValue.iteration @namedFunction.iteration)
)
;;!! { }
@@ -120,34 +115,18 @@
)
(_
- _ @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
+ _ @statementNameValue.iteration.start.endOf @interior.start.endOf
.
body: (_)
.
- "end" @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
+ "end" @statementNameValue.iteration.end.startOf @interior.end.startOf
)
(_
- _ @interior.start.endOf
- .
- body: (_)
- .
- "end" @interior.end.startOf
-)
-
-(_
- _ @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
+ _ @statementNameValue.iteration.start.endOf @interior.start.endOf
.
body: (_
- "end" @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
- )
-)
-
-(_
- _ @interior.start.endOf
- .
- body: (_
- "end" @interior.end.startOf
+ "end" @statementNameValue.iteration.end.startOf @interior.end.startOf
)
)
@@ -204,16 +183,10 @@
;;!! if true end
;;! ^
(if
- condition: (_) @interior.start.endOf
- consequence: (_)
- .
- _ @interior.end.startOf
-)
-(if
- condition: (_) @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
+ condition: (_) @interior.start.endOf @statementNameValue.iteration.start.endOf
consequence: (_)
.
- _ @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
+ _ @interior.end.startOf @statementNameValue.iteration.end.startOf
)
;;!! if true elsif false end
@@ -246,32 +219,21 @@
;;!! elsif true else end
;;! ^
(elsif
- condition: (_) @interior.start.endOf
- alternative: (_) @interior.end.startOf
-)
-(elsif
- condition: (_) @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
- alternative: (_) @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
+ condition: (_) @interior.start.endOf @statementNameValue.iteration.start.endOf
+ alternative: (_) @interior.end.startOf @statementNameValue.iteration.end.startOf
)
;;!! elsif true end
;;! ^
(elsif
- condition: (_) @interior.start.endOf
+ condition: (_) @interior.start.endOf @statementNameValue.iteration.start.endOf
!alternative
-) @interior.end.endOf
-(elsif
- condition: (_) @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
- !alternative
-) @statement.iteration.end.endOf @name.iteration.end.endOf @value.iteration.end.endOf
+) @interior.end.endOf @statementNameValue.iteration.end.endOf
;;!! else end
(else
- "else" @interior.start.endOf
-) @branch @interior.end.endOf
-(else
- "else" @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
-) @statement.iteration.end.endOf @name.iteration.end.endOf @value.iteration.end.endOf
+ "else" @interior.start.endOf @statementNameValue.iteration.start.endOf
+) @branch @interior.end.endOf @statementNameValue.iteration.end.endOf
;;!! begin rescue end
;;!! begin end
diff --git a/resources/queries/rust.scm b/resources/queries/rust.scm
index ec9434c9b8..0df928e9af 100644
--- a/resources/queries/rust.scm
+++ b/resources/queries/rust.scm
@@ -33,26 +33,16 @@
)
(
- (source_file) @statement.iteration @class.iteration @namedFunction.iteration
- (#document-range! @statement.iteration @class.iteration @namedFunction.iteration)
-)
-(
- (source_file) @name.iteration @type.iteration @value.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (source_file) @statementNameValueType.iteration @class.iteration @namedFunction.iteration
+ (#document-range! @statementNameValueType.iteration @class.iteration @namedFunction.iteration)
)
;;!! { }
;;! ^
(_
.
- "{" @interior.start.endOf @statement.iteration.start.endOf
- "}" @interior.end.startOf @statement.iteration.end.startOf
- .
-)
-(_
- .
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
+ "{" @interior.start.endOf @statementNameValueType.iteration.start.endOf
+ "}" @interior.end.startOf @statementNameValueType.iteration.end.startOf
.
)
diff --git a/resources/queries/scala.scm b/resources/queries/scala.scm
index 347bb66c8d..30cfa374ea 100644
--- a/resources/queries/scala.scm
+++ b/resources/queries/scala.scm
@@ -37,13 +37,8 @@
] @type
(
- (compilation_unit) @class.iteration @statement.iteration @namedFunction.iteration
- (#document-range! @class.iteration @statement.iteration @namedFunction.iteration)
-)
-
-(
- (compilation_unit) @name.iteration @value.iteration @type.iteration
- (#document-range! @name.iteration @value.iteration @type.iteration)
+ (compilation_unit) @class.iteration @statementNameValueType.iteration @namedFunction.iteration
+ (#document-range! @class.iteration @statementNameValueType.iteration @namedFunction.iteration)
)
;;!! { }
@@ -124,12 +119,8 @@
;;!! { }
;;! ^
(_
- "{" @name.iteration.start.endOf @value.iteration.start.endOf @type.iteration.start.endOf
- "}" @name.iteration.end.startOf @value.iteration.end.startOf @type.iteration.end.startOf
-)
-(_
- "{" @statement.iteration.start.endOf
- "}" @statement.iteration.end.startOf
+ "{" @statementNameValueType.iteration.start.endOf
+ "}" @statementNameValueType.iteration.end.startOf
)
;;!! foo()
diff --git a/resources/queries/shellscript.scm b/resources/queries/shellscript.scm
index 32d7dc9103..cf60da6b3a 100644
--- a/resources/queries/shellscript.scm
+++ b/resources/queries/shellscript.scm
@@ -48,12 +48,8 @@
]
(
- (program) @statement.iteration @namedFunction.iteration
- (#document-range! @statement.iteration @namedFunction.iteration)
-)
-(
- (program) @name.iteration @value.iteration
- (#document-range! @name.iteration @value.iteration)
+ (program) @statementNameValue.iteration @namedFunction.iteration
+ (#document-range! @statementNameValue.iteration @namedFunction.iteration)
)
;;!! [[ $foo =~ ^\w+$ ]]
@@ -117,8 +113,8 @@
;;!! if true; then :; fi
(
(if_statement
- "then" @interior.start.endOf
- "fi" @interior.end.startOf
+ "then" @interior.start.endOf @statementNameValue.iteration.start.endOf
+ "fi" @interior.end.startOf @statementNameValue.iteration.end.startOf
) @branch
(#not-child-type? @branch elif_clause else_clause)
)
@@ -127,13 +123,13 @@
(
(if_statement
"if" @branch.start @branch.removal.start
- "then" @interior.start.endOf
+ "then" @interior.start.endOf @statementNameValue.iteration.start.endOf
(_) @branch.end @branch.removal.end
.
[
(elif_clause)
(else_clause)
- ] @branch.removal.end.startOf @interior.end.startOf
+ ] @branch.removal.end.startOf @interior.end.startOf @statementNameValue.iteration.end.startOf
)
(#not-type? @branch.end elif_clause else_clause)
(#shrink-to-match! @branch.removal.end.startOf "^(?:el(?=if\\b))?(?.*)")
@@ -144,19 +140,19 @@
(
(elif_clause
(_) @condition
- "then" @interior.start.endOf
+ "then" @interior.start.endOf @statementNameValue.iteration.start.endOf
) @branch @branch.removal.start @condition.domain
.
- _ @branch.removal.end.startOf @interior.end.startOf
+ _ @branch.removal.end.startOf @interior.end.startOf @statementNameValue.iteration.end.startOf
(#trim-end! @branch)
)
;;!! else :; fi
(
(else_clause
- "else" @interior.start.endOf
+ "else" @interior.start.endOf @statementNameValue.iteration.start.endOf
) @branch @branch.removal.start
- "fi" @branch.removal.end.startOf @interior.end.startOf
+ "fi" @branch.removal.end.startOf @interior.end.startOf @statementNameValue.iteration.end.startOf
(#trim-end! @branch)
)
@@ -184,15 +180,10 @@
;;! ^
(case_item
value: (_) @condition
- ")" @interior.start.endOf
- ";;" @interior.end.startOf
+ ")" @interior.start.endOf @statementNameValue.iteration.start.endOf
+ ";;" @interior.end.startOf @statementNameValue.iteration.end.startOf
) @branch @condition.domain
-(case_item
- ")" @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
- ";;" @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
-)
-
;;!! return 0
;;! ^
(
@@ -208,25 +199,15 @@
;;!! do :; done
;;! ^^^^
(do_group
- "do" @interior.start.endOf
- "done" @interior.end.startOf
-)
-
-(do_group
- "do" @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
- "done" @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
+ "do" @interior.start.endOf @statementNameValue.iteration.start.endOf
+ "done" @interior.end.startOf @statementNameValue.iteration.end.startOf
)
;;!! foo() { }
;;! ^
(compound_statement
- "{" @interior.start.endOf
- "}" @interior.end.startOf
-)
-
-(compound_statement
- "{" @statement.iteration.start.endOf @name.iteration.start.endOf @value.iteration.start.endOf
- "}" @statement.iteration.end.startOf @name.iteration.end.startOf @value.iteration.end.startOf
+ "{" @interior.start.endOf @statementNameValue.iteration.start.endOf
+ "}" @interior.end.startOf @statementNameValue.iteration.end.startOf
)
;;!! # foo
diff --git a/resources/queries/talon-list.scm b/resources/queries/talon-list.scm
index a9a872cdf2..5be60ffea0 100644
--- a/resources/queries/talon-list.scm
+++ b/resources/queries/talon-list.scm
@@ -39,11 +39,6 @@
) @string
(
- (source_file) @statement.iteration
- (#document-range! @statement.iteration)
-)
-
-(
- (source_file) @name.iteration @collectionKey.iteration @value.iteration
- (#document-range! @name.iteration @collectionKey.iteration @value.iteration)
+ (source_file) @statementNameValue.iteration @collectionKey.iteration
+ (#document-range! @statementNameValue.iteration @collectionKey.iteration)
)
diff --git a/resources/queries/talon.scm b/resources/queries/talon.scm
index 53698253f2..a401454779 100644
--- a/resources/queries/talon.scm
+++ b/resources/queries/talon.scm
@@ -29,8 +29,6 @@
(for_statement)
] @statement
-(block) @statement.iteration
-
;;!! not mode: command
;;! ^^^^
;;! ^^^^^^^
@@ -87,16 +85,11 @@
;;!! settings():
;;!! speech.debug = 1
;;! ^^^^^^^^^^^^^^^^
-(block) @name.iteration @collectionKey.iteration @value.iteration
-
-(
- (source_file) @command.iteration @statement.iteration
- (#document-range! @command.iteration @statement.iteration)
-)
+(block) @statementNameValue.iteration @collectionKey.iteration
(
- (source_file) @name.iteration @collectionKey.iteration @value.iteration
- (#document-range! @name.iteration @collectionKey.iteration @value.iteration)
+ (source_file) @command.iteration @statementNameValue.iteration @collectionKey.iteration
+ (#document-range! @command.iteration @statementNameValue.iteration @collectionKey.iteration)
)
;;!! tag: user.foo