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