From edb23ff9955e8e6bffa579e73b2ce672208405e9 Mon Sep 17 00:00:00 2001 From: Zhiming Ma Date: Fri, 26 Apr 2024 22:44:20 +0800 Subject: [PATCH] chore(agent): clean up experimental post-processing features. (#1973) * chore(agent): clean up experimental syntax features. * fix: lint --- clients/tabby-agent/src/AgentConfig.ts | 29 +- clients/tabby-agent/src/TabbyAgent.ts | 7 +- clients/tabby-agent/src/configFile.ts | 4 - .../src/postprocess/calculateReplaceRange.ts | 17 +- .../calculateReplaceRangeBySyntax.test.ts | 163 ------- .../calculateReplaceRangeBySyntax.ts | 64 --- .../limit_scope/experimental_block_01.toml | 26 -- .../limit_scope/experimental_block_02.toml | 21 - ...ental_syntax_rust_01.toml => rust_01.toml} | 7 +- ...ental_syntax_rust_02.toml => rust_02.toml} | 6 +- .../golden/limit_scope/to_block_03.toml | 6 +- .../golden/limit_scope/to_line_01.toml | 6 +- ..._typescript_01.toml => typescript_01.toml} | 6 +- .../experimental_syntax_rust_01.toml | 30 -- ..._javascript_01.toml => javascript_01.toml} | 8 +- ..._mismatched_01.toml => mismatched_01.toml} | 8 +- ...l_syntax_rust_01_ref.toml => rust_01.toml} | 8 +- ..._typescript_01.toml => typescript_01.toml} | 8 +- .../tabby-agent/src/postprocess/limitScope.ts | 17 +- .../limitScopeByIndentation.test.ts | 118 +---- .../postprocess/limitScopeByIndentation.ts | 16 +- .../postprocess/limitScopeBySyntax.test.ts | 410 ------------------ .../src/postprocess/limitScopeBySyntax.ts | 93 ---- clients/tabby-agent/src/syntax/typeList.ts | 113 ----- 24 files changed, 55 insertions(+), 1136 deletions(-) delete mode 100644 clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.test.ts delete mode 100644 clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.ts delete mode 100644 clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_01.toml delete mode 100644 clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_02.toml rename clients/tabby-agent/src/postprocess/golden/limit_scope/{experimental_syntax_rust_01.toml => rust_01.toml} (78%) rename clients/tabby-agent/src/postprocess/golden/limit_scope/{experimental_syntax_rust_02.toml => rust_02.toml} (76%) rename clients/tabby-agent/src/postprocess/golden/limit_scope/{experimental_syntax_typescript_01.toml => typescript_01.toml} (75%) delete mode 100644 clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_rust_01.toml rename clients/tabby-agent/src/postprocess/golden/replace_range/{experimental_syntax_javascript_01.toml => javascript_01.toml} (69%) rename clients/tabby-agent/src/postprocess/golden/replace_range/{experimental_syntax_mismatched_01.toml => mismatched_01.toml} (70%) rename clients/tabby-agent/src/postprocess/golden/replace_range/{experimental_syntax_rust_01_ref.toml => rust_01.toml} (78%) rename clients/tabby-agent/src/postprocess/golden/replace_range/{experimental_syntax_typescript_01.toml => typescript_01.toml} (60%) delete mode 100644 clients/tabby-agent/src/postprocess/limitScopeBySyntax.test.ts delete mode 100644 clients/tabby-agent/src/postprocess/limitScopeBySyntax.ts delete mode 100644 clients/tabby-agent/src/syntax/typeList.ts diff --git a/clients/tabby-agent/src/AgentConfig.ts b/clients/tabby-agent/src/AgentConfig.ts index b2b76c72c2a1..789f873efcde 100644 --- a/clients/tabby-agent/src/AgentConfig.ts +++ b/clients/tabby-agent/src/AgentConfig.ts @@ -7,7 +7,6 @@ export type AgentConfig = { }; completion: { prompt: { - experimentalStripAutoClosingCharacters: boolean; maxPrefixLines: number; maxSuffixLines: number; fillDeclarations: { @@ -52,20 +51,8 @@ export type AgentConfig = { }; }; postprocess: { - limitScope: { - // Prefer to use syntax parser than indentation - experimentalSyntax: boolean; - indentation: { - // When completion is continuing the current line, limit the scope to: - // false(default): the line scope, meaning use the next indent level as the limit. - // true: the block scope, meaning use the current indent level as the limit. - experimentalKeepBlockScopeWhenCompletingLine: boolean; - }; - }; - calculateReplaceRange: { - // Prefer to use syntax parser than bracket stack - experimentalSyntax: boolean; - }; + limitScope: any; + calculateReplaceRange: any; }; logs: { level: "debug" | "error" | "silent"; @@ -98,7 +85,6 @@ export const defaultAgentConfig: AgentConfig = { }, completion: { prompt: { - experimentalStripAutoClosingCharacters: false, maxPrefixLines: 20, maxSuffixLines: 20, fillDeclarations: { @@ -130,15 +116,8 @@ export const defaultAgentConfig: AgentConfig = { }, }, postprocess: { - limitScope: { - experimentalSyntax: false, - indentation: { - experimentalKeepBlockScopeWhenCompletingLine: false, - }, - }, - calculateReplaceRange: { - experimentalSyntax: false, - }, + limitScope: {}, + calculateReplaceRange: {}, }, logs: { level: "silent", diff --git a/clients/tabby-agent/src/TabbyAgent.ts b/clients/tabby-agent/src/TabbyAgent.ts index b53ec45b43ac..fa098a696695 100644 --- a/clients/tabby-agent/src/TabbyAgent.ts +++ b/clients/tabby-agent/src/TabbyAgent.ts @@ -340,12 +340,7 @@ export class TabbyAgent extends EventEmitter implements Agent { const maxSuffixLines = this.config.completion.prompt.maxSuffixLines; const { prefixLines, suffixLines } = context; const prefix = prefixLines.slice(Math.max(prefixLines.length - maxPrefixLines, 0)).join(""); - let suffix; - if (this.config.completion.prompt.experimentalStripAutoClosingCharacters && context.mode !== "fill-in-line") { - suffix = "\n" + suffixLines.slice(1, maxSuffixLines).join(""); - } else { - suffix = suffixLines.slice(0, maxSuffixLines).join(""); - } + const suffix = suffixLines.slice(0, maxSuffixLines).join(""); if (isBlank(prefix)) { return null; } diff --git a/clients/tabby-agent/src/configFile.ts b/clients/tabby-agent/src/configFile.ts index 4069f687c98f..a9109c1666d6 100644 --- a/clients/tabby-agent/src/configFile.ts +++ b/clients/tabby-agent/src/configFile.ts @@ -50,7 +50,6 @@ const typeCheckSchema: Record = { "server.requestTimeout": "number", completion: "object", "completion.prompt": "object", - "completion.prompt.experimentalStripAutoClosingCharacters": "boolean", "completion.prompt.maxPrefixLines": "number", "completion.prompt.maxSuffixLines": "number", "completion.prompt.fillDeclarations": "object", @@ -74,9 +73,6 @@ const typeCheckSchema: Record = { "completion.debounce": "object", "completion.debounce.mode": "string", "completion.debounce.interval": "number", - postprocess: "object", - "postprocess.limitScopeByIndentation": "object", - "postprocess.limitScopeByIndentation.experimentalKeepBlockScopeWhenCompletingLine": "boolean", logs: "object", "logs.level": "string", tls: "object", diff --git a/clients/tabby-agent/src/postprocess/calculateReplaceRange.ts b/clients/tabby-agent/src/postprocess/calculateReplaceRange.ts index 181f641b2cd3..57cf5cea73e0 100644 --- a/clients/tabby-agent/src/postprocess/calculateReplaceRange.ts +++ b/clients/tabby-agent/src/postprocess/calculateReplaceRange.ts @@ -1,24 +1,11 @@ import { AgentConfig } from "../AgentConfig"; -import { isBrowser } from "../env"; -import { PostprocessChoiceFilter, logger } from "./base"; +import { PostprocessChoiceFilter } from "./base"; import { calculateReplaceRangeByBracketStack } from "./calculateReplaceRangeByBracketStack"; -import { calculateReplaceRangeBySyntax } from "./calculateReplaceRangeBySyntax"; export function calculateReplaceRange( - config: AgentConfig["postprocess"]["calculateReplaceRange"], + _config: AgentConfig["postprocess"]["calculateReplaceRange"], ): PostprocessChoiceFilter { return async (choice, context) => { - const preferSyntaxParser = - !isBrowser && // syntax parser is not supported in browser yet - config.experimentalSyntax; - - if (preferSyntaxParser) { - try { - return await calculateReplaceRangeBySyntax(choice, context); - } catch (error) { - logger.debug({ error }, "Failed to calculate replace range by syntax parser"); - } - } return calculateReplaceRangeByBracketStack(choice, context); }; } diff --git a/clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.test.ts b/clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.test.ts deleted file mode 100644 index 85c74fb7cb39..000000000000 --- a/clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.test.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { expect } from "chai"; -import { documentContext, inline } from "./testUtils"; -import { calculateReplaceRangeBySyntax } from "./calculateReplaceRangeBySyntax"; - -describe("postprocess", () => { - describe("calculateReplaceRangeBySyntax", () => { - it("should handle auto closing quotes", async () => { - const context = { - ...documentContext` - const hello = "║" - `, - language: "typescript", - }; - const choice = { - index: 0, - text: inline` - ├hello";┤ - `, - replaceRange: { - start: context.position, - end: context.position, - }, - }; - const expected = { - index: 0, - text: inline` - ├hello";┤ - `, - replaceRange: { - start: context.position, - end: context.position + 1, - }, - }; - expect(await calculateReplaceRangeBySyntax(choice, context)).to.deep.equal(expected); - }); - - it("should handle auto closing quotes", async () => { - const context = { - ...documentContext` - let htmlMarkup = \`║\` - `, - language: "typescript", - }; - const choice = { - index: 0, - text: inline` - ├

\${message}

\`;┤ - `, - replaceRange: { - start: context.position, - end: context.position, - }, - }; - const expected = { - index: 0, - text: inline` - ├

\${message}

\`;┤ - `, - replaceRange: { - start: context.position, - end: context.position + 1, - }, - }; - expect(await calculateReplaceRangeBySyntax(choice, context)).to.deep.equal(expected); - }); - - it("should handle multiple auto closing brackets", async () => { - const context = { - ...documentContext` - process.on('data', (data) => {║}) - `, - language: "typescript", - }; - const choice = { - index: 0, - text: inline` - ├ - console.log(data); - });┤ - `, - replaceRange: { - start: context.position, - end: context.position, - }, - }; - const expected = { - index: 0, - text: inline` - ├ - console.log(data); - });┤ - `, - replaceRange: { - start: context.position, - end: context.position + 2, - }, - }; - expect(await calculateReplaceRangeBySyntax(choice, context)).to.deep.equal(expected); - }); - - it("should handle multiple auto closing brackets", async () => { - const context = { - ...documentContext` - let mat: number[][][] = [[[║]]] - `, - language: "typescript", - }; - const choice = { - index: 0, - text: inline` - ├1, 2], [3, 4]], [[5, 6], [7, 8]]];┤ - `, - replaceRange: { - start: context.position, - end: context.position, - }, - }; - const expected = { - index: 0, - text: inline` - ├1, 2], [3, 4]], [[5, 6], [7, 8]]];┤ - `, - replaceRange: { - start: context.position, - end: context.position + 3, - }, - }; - expect(await calculateReplaceRangeBySyntax(choice, context)).to.deep.equal(expected); - }); - - it("should handle the bad case of calculateReplaceRangeByBracketStack", async () => { - const context = { - ...documentContext` - function clamp(n: number, max: number, min: number): number { - return Math.max(Math.min(║); - } - `, - language: "typescript", - }; - const choice = { - index: 0, - text: inline` - ├n, max), min┤ - `, - replaceRange: { - start: context.position, - end: context.position, - }, - }; - const expected = { - index: 0, - text: inline` - ├n, max), min┤ - `, - replaceRange: { - start: context.position, - end: context.position, - }, - }; - expect(await calculateReplaceRangeBySyntax(choice, context)).to.deep.equal(expected); - }); - }); -}); diff --git a/clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.ts b/clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.ts deleted file mode 100644 index 06932e56181c..000000000000 --- a/clients/tabby-agent/src/postprocess/calculateReplaceRangeBySyntax.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { getParser, languagesConfigs } from "../syntax/parser"; -import { CompletionContext, CompletionResponseChoice } from "../CompletionContext"; -import { isBlank, splitLines } from "../utils"; -import { logger } from "./base"; - -export const supportedLanguages = Object.keys(languagesConfigs); - -/** - * @throws {Error} if language is not supported - * @throws {Error} if syntax error when parsing completion - */ -export async function calculateReplaceRangeBySyntax( - choice: CompletionResponseChoice, - context: CompletionContext, -): Promise { - const { position, prefix, suffix, prefixLines, currentLinePrefix, currentLineSuffix, language } = context; - const suffixText = currentLineSuffix.trimEnd(); - if (isBlank(suffixText)) { - return choice; - } - - if (!supportedLanguages.includes(language)) { - throw new Error(`Language ${language} is not supported`); - } - const languageConfig = languagesConfigs[language]!; - const parser = await getParser(languageConfig); - - const completionText = choice.text.slice(position - choice.replaceRange.start); - const completionLines = splitLines(completionText); - let replaceLength = 0; - let tree = parser.parse(prefix + completionText + suffix); - let node = tree.rootNode.namedDescendantForIndex( - prefix.length + completionText.length, - prefix.length + completionText.length + suffixText.length - replaceLength, - ); - while (node.hasError() && replaceLength < suffixText.length) { - replaceLength++; - const row = prefixLines.length - 1 + completionLines.length - 1; - let column = completionLines[completionLines.length - 1]?.length ?? 0; - if (completionLines.length == 1) { - column += currentLinePrefix.length; - } - tree.edit({ - startIndex: prefix.length + completionText.length, - oldEndIndex: prefix.length + completionText.length + 1, - newEndIndex: prefix.length + completionText.length, - startPosition: { row, column }, - oldEndPosition: { row, column: column + 1 }, - newEndPosition: { row, column }, - }); - tree = parser.parse(prefix + completionText + suffix.slice(replaceLength), tree); - node = tree.rootNode.namedDescendantForIndex( - prefix.length + completionText.length, - prefix.length + completionText.length + suffixText.length - replaceLength, - ); - } - if (node.hasError()) { - throw new Error("Syntax error when parsing completion"); - } - - choice.replaceRange.end = position + replaceLength; - logger.trace({ context, completion: choice.text, range: choice.replaceRange }, "Adjust replace range by syntax"); - return choice; -} diff --git a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_01.toml b/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_01.toml deleted file mode 100644 index c7d9c7ed2f55..000000000000 --- a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_01.toml +++ /dev/null @@ -1,26 +0,0 @@ -description = 'Limit scope experimental: limit to block when completing a line: case 01' - -[config.limitScope.indentation] -experimentalKeepBlockScopeWhenCompletingLine = true - -[context] -filepath = 'foo.ts' -language = 'typescript' -# indentation = ' ' # not specified -text = ''' -export class Foo { - private _foo: number; - - constructor() { - this._foo = 1; - } - - update(value): Foo { - this._foo =├ value; - return this;┤ - } -} -''' - -[expected] -unchanged = true diff --git a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_02.toml b/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_02.toml deleted file mode 100644 index 1fb08b4485f7..000000000000 --- a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_block_02.toml +++ /dev/null @@ -1,21 +0,0 @@ -description = 'Limit scope experimental: limit to block when completing a line: case 02' - -[config.limitScope.indentation] -experimentalKeepBlockScopeWhenCompletingLine = true - -[context] -filepath = 'checks.js' -language = 'javascript' -# indentation = ' ' # not specified -text = ''' -function check(obj) { - // if obj.a is defined, then return t├rue - if (obj.a) { - return true; - }┤ - return false; -} -''' - -[expected] -unchanged = true \ No newline at end of file diff --git a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_rust_01.toml b/clients/tabby-agent/src/postprocess/golden/limit_scope/rust_01.toml similarity index 78% rename from clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_rust_01.toml rename to clients/tabby-agent/src/postprocess/golden/limit_scope/rust_01.toml index e3f7689eea3e..ea602754cdf3 100644 --- a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_rust_01.toml +++ b/clients/tabby-agent/src/postprocess/golden/limit_scope/rust_01.toml @@ -1,7 +1,7 @@ -description = 'Limit scope experimental: syntax rust: case 01' +description = 'Limit scope: rust 01' -[config.limitScope] -experimentalSyntax = true +[config] +# use default config [context] filepath = 'stop.rs' @@ -24,3 +24,4 @@ pub struct StopCondition { max_decoding_time: Duration,┤ } ''' +notEqual = true \ No newline at end of file diff --git a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_rust_02.toml b/clients/tabby-agent/src/postprocess/golden/limit_scope/rust_02.toml similarity index 76% rename from clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_rust_02.toml rename to clients/tabby-agent/src/postprocess/golden/limit_scope/rust_02.toml index 440e2c8fc286..fc22f435f523 100644 --- a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_rust_02.toml +++ b/clients/tabby-agent/src/postprocess/golden/limit_scope/rust_02.toml @@ -1,7 +1,7 @@ -description = 'Limit scope experimental: syntax rust: case 02' +description = 'Limit scope: rust 02' -[config.limitScope] -experimentalSyntax = true +[config] +# use default config [context] filepath = 'stop.rs' diff --git a/clients/tabby-agent/src/postprocess/golden/limit_scope/to_block_03.toml b/clients/tabby-agent/src/postprocess/golden/limit_scope/to_block_03.toml index b72928f54667..e2115cfe2a5c 100644 --- a/clients/tabby-agent/src/postprocess/golden/limit_scope/to_block_03.toml +++ b/clients/tabby-agent/src/postprocess/golden/limit_scope/to_block_03.toml @@ -1,9 +1,7 @@ description = 'Limit scope: limit to block scope: case 03' -[config.limitScope] -experimentalSyntax = false -[config.limitScope.indentation] -experimentalKeepBlockScopeWhenCompletingLine = false +[config] +# use default config [context] filepath = 'checks.js' diff --git a/clients/tabby-agent/src/postprocess/golden/limit_scope/to_line_01.toml b/clients/tabby-agent/src/postprocess/golden/limit_scope/to_line_01.toml index 427c696738c6..c4c4434848b7 100644 --- a/clients/tabby-agent/src/postprocess/golden/limit_scope/to_line_01.toml +++ b/clients/tabby-agent/src/postprocess/golden/limit_scope/to_line_01.toml @@ -1,9 +1,7 @@ description = 'Limit scope: limit to single line when completing a line: case 01' -[config.limitScope] -experimentalSyntax = false -[config.limitScope.indentation] -experimentalKeepBlockScopeWhenCompletingLine = false +[config] +# use default config [context] filepath = 'foo.ts' diff --git a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_typescript_01.toml b/clients/tabby-agent/src/postprocess/golden/limit_scope/typescript_01.toml similarity index 75% rename from clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_typescript_01.toml rename to clients/tabby-agent/src/postprocess/golden/limit_scope/typescript_01.toml index 98482c67ef0e..c7be5a500c2e 100644 --- a/clients/tabby-agent/src/postprocess/golden/limit_scope/experimental_syntax_typescript_01.toml +++ b/clients/tabby-agent/src/postprocess/golden/limit_scope/typescript_01.toml @@ -1,7 +1,7 @@ -description = 'Limit scope experimental: syntax typescript: case 01' +description = 'Limit scope: typescript 01' -[config.limitScope] -experimentalSyntax = true +[config] +# use default config [context] filepath = 'foo.ts' diff --git a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_rust_01.toml b/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_rust_01.toml deleted file mode 100644 index 3987255aac70..000000000000 --- a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_rust_01.toml +++ /dev/null @@ -1,30 +0,0 @@ -description = 'Replace range experimental: syntax rust: bad case 01' - -[config.limitScope] -experimentalSyntax = true -[config.calculateReplaceRange] -experimentalSyntax = true - -[context] -filepath = 'myTest.rs' -language = 'rust' -# indentation = ' ' # not specified -text = ''' -pub fun myTest(&self, text: String) { - let mut body = HashMap::new(); - body.insert("├text".to_string(), text);┤") - let mut headers = HashMap::new(); - headers.insert("Content-Type".to_string(), "application/json".to_string()); -} -''' - -[expected] -text = ''' -pub fun myTest(&self, text: String) { - let mut body = HashMap::new(); - body.insert("├text".to_string(), text);┤")╣ - let mut headers = HashMap::new(); - headers.insert("Content-Type".to_string(), "application/json".to_string()); -} -''' -notEqual = true diff --git a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_javascript_01.toml b/clients/tabby-agent/src/postprocess/golden/replace_range/javascript_01.toml similarity index 69% rename from clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_javascript_01.toml rename to clients/tabby-agent/src/postprocess/golden/replace_range/javascript_01.toml index c681b8f652fa..1853be872365 100644 --- a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_javascript_01.toml +++ b/clients/tabby-agent/src/postprocess/golden/replace_range/javascript_01.toml @@ -1,9 +1,7 @@ -description = 'Replace range experimental: syntax javascript: case 01' +description = 'Replace range: javascript 01' -[config.limitScope] -experimentalSyntax = true -[config.calculateReplaceRange] -experimentalSyntax = true +[config] +# use default config [context] filepath = 'listener.js' diff --git a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_mismatched_01.toml b/clients/tabby-agent/src/postprocess/golden/replace_range/mismatched_01.toml similarity index 70% rename from clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_mismatched_01.toml rename to clients/tabby-agent/src/postprocess/golden/replace_range/mismatched_01.toml index be5b6c26e76c..587536e17986 100644 --- a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_mismatched_01.toml +++ b/clients/tabby-agent/src/postprocess/golden/replace_range/mismatched_01.toml @@ -1,9 +1,7 @@ -description = 'Replace range experimental: syntax mismatched: case 01' +description = 'Replace range: mismatched case 01' -[config.limitScope] -experimentalSyntax = true -[config.calculateReplaceRange] -experimentalSyntax = true +[config] +# use default config [context] filepath = 'fibonacci.ts' diff --git a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_rust_01_ref.toml b/clients/tabby-agent/src/postprocess/golden/replace_range/rust_01.toml similarity index 78% rename from clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_rust_01_ref.toml rename to clients/tabby-agent/src/postprocess/golden/replace_range/rust_01.toml index 7c649604dbbf..8b4c8d5cde79 100644 --- a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_rust_01_ref.toml +++ b/clients/tabby-agent/src/postprocess/golden/replace_range/rust_01.toml @@ -1,9 +1,7 @@ -description = 'Replace range experimental: syntax rust: case 01 (ref)' +description = 'Replace range: rust 01' -[config.limitScope] -experimentalSyntax = true -[config.calculateReplaceRange] -experimentalSyntax = false +[config] +# use default config [context] filepath = 'myTest.rs' diff --git a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_typescript_01.toml b/clients/tabby-agent/src/postprocess/golden/replace_range/typescript_01.toml similarity index 60% rename from clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_typescript_01.toml rename to clients/tabby-agent/src/postprocess/golden/replace_range/typescript_01.toml index dd0abc95eb10..f3573131ae19 100644 --- a/clients/tabby-agent/src/postprocess/golden/replace_range/experimental_syntax_typescript_01.toml +++ b/clients/tabby-agent/src/postprocess/golden/replace_range/typescript_01.toml @@ -1,9 +1,7 @@ -description = 'Replace range experimental: syntax typescript: case 01' +description = 'Replace range: typescript 01' -[config.limitScope] -experimentalSyntax = true -[config.calculateReplaceRange] -experimentalSyntax = true +[config] +# use default config [context] filepath = 'print.ts' diff --git a/clients/tabby-agent/src/postprocess/limitScope.ts b/clients/tabby-agent/src/postprocess/limitScope.ts index 8a5b6b8774b0..8b16ed40e920 100644 --- a/clients/tabby-agent/src/postprocess/limitScope.ts +++ b/clients/tabby-agent/src/postprocess/limitScope.ts @@ -1,23 +1,10 @@ import { CompletionContext } from "../CompletionContext"; import { AgentConfig } from "../AgentConfig"; -import { isBrowser } from "../env"; -import { PostprocessFilter, logger } from "./base"; +import { PostprocessFilter } from "./base"; import { limitScopeByIndentation } from "./limitScopeByIndentation"; -import { limitScopeBySyntax } from "./limitScopeBySyntax"; export function limitScope(config: AgentConfig["postprocess"]["limitScope"]): PostprocessFilter { return async (input: string, context: CompletionContext) => { - const preferSyntaxParser = - !isBrowser && // syntax parser is not supported in browser yet - config.experimentalSyntax; - - if (preferSyntaxParser) { - try { - return await limitScopeBySyntax()(input, context); - } catch (error) { - logger.debug({ error }, "Failed to limit scope by syntax parser"); - } - } - return limitScopeByIndentation(config["indentation"])(input, context); + return limitScopeByIndentation(config)(input, context); }; } diff --git a/clients/tabby-agent/src/postprocess/limitScopeByIndentation.test.ts b/clients/tabby-agent/src/postprocess/limitScopeByIndentation.test.ts index 3a955b825e70..ae9d1a8efb25 100644 --- a/clients/tabby-agent/src/postprocess/limitScopeByIndentation.test.ts +++ b/clients/tabby-agent/src/postprocess/limitScopeByIndentation.test.ts @@ -1,13 +1,10 @@ import { expect } from "chai"; import { documentContext, inline } from "./testUtils"; -import { limitScopeByIndentation } from "./limitScopeByIndentation"; +import { limitScopeByIndentation as createLimitScopeByIndentationFilter } from "./limitScopeByIndentation"; describe("postprocess", () => { - describe("limitScopeByIndentation: default config", () => { - const limitScopeByIndentationDefault = limitScopeByIndentation({ - experimentalKeepBlockScopeWhenCompletingLine: false, - }); - + describe("limitScopeByIndentation", () => { + const limitScopeByIndentation = createLimitScopeByIndentationFilter({}); it("should limit scope at sentence end, when completion is continuing uncompleted sentence in the prefix.", () => { const context = { ...documentContext` @@ -22,7 +19,7 @@ describe("postprocess", () => { const expected = inline` ├ 1;┤ `; - expect(limitScopeByIndentationDefault(completion, context)).to.eq(expected); + expect(limitScopeByIndentation(completion, context)).to.eq(expected); }); it("should limit scope at sentence end, when completion is continuing uncompleted sentence in the prefix.", () => { @@ -50,7 +47,7 @@ describe("postprocess", () => { const expected = inline` ├("Parsing", { json });┤ `; - expect(limitScopeByIndentationDefault(completion, context)).to.eq(expected); + expect(limitScopeByIndentation(completion, context)).to.eq(expected); }); it("should limit scope at next indent level, including closing line, when completion is starting a new indent level in next line.", () => { @@ -83,7 +80,7 @@ describe("postprocess", () => { return max; }┤ `; - expect(limitScopeByIndentationDefault(completion, context)).to.eq(expected); + expect(limitScopeByIndentation(completion, context)).to.eq(expected); }); it("should limit scope at next indent level, including closing line, when completion is continuing uncompleted sentence in the prefix, and starting a new indent level in next line.", () => { @@ -114,7 +111,7 @@ describe("postprocess", () => { }┤ ┴┴ `; - expect(limitScopeByIndentationDefault(completion, context)).to.eq(expected); + expect(limitScopeByIndentation(completion, context)).to.eq(expected); }); it("should limit scope at current indent level, including closing line, when completion starts new sentences at same indent level.", () => { @@ -136,7 +133,7 @@ describe("postprocess", () => { return max; }┤ `; - expect(limitScopeByIndentationDefault(completion, context)).to.eq(completion); + expect(limitScopeByIndentation(completion, context)).to.eq(completion); }); it("should allow only one level closing bracket", () => { @@ -160,7 +157,7 @@ describe("postprocess", () => { }┤ ┴┴ `; - expect(limitScopeByIndentationDefault(completion, context)).to.eq(expected); + expect(limitScopeByIndentation(completion, context)).to.eq(expected); }); it("should allow level closing bracket at current line, it looks same as starts new sentences", () => { @@ -175,7 +172,7 @@ describe("postprocess", () => { const completion = inline` ├}┤ `; - expect(limitScopeByIndentationDefault(completion, context)).to.be.eq(completion); + expect(limitScopeByIndentation(completion, context)).to.be.eq(completion); }); it("should not allow level closing bracket, when the suffix lines have same indent level", () => { @@ -194,7 +191,7 @@ describe("postprocess", () => { `; const expected = inline` ├┤`; - expect(limitScopeByIndentationDefault(completion, context)).to.be.eq(expected); + expect(limitScopeByIndentation(completion, context)).to.be.eq(expected); }); it("should use indent level of previous line, when current line is empty.", () => { @@ -222,14 +219,12 @@ describe("postprocess", () => { }┤ ┴┴ `; - expect(limitScopeByIndentationDefault(completion, context)).to.eq(expected); + expect(limitScopeByIndentation(completion, context)).to.eq(expected); }); }); describe("limitScopeByIndentation: bad cases", () => { - const limitScopeByIndentationDefault = limitScopeByIndentation({ - experimentalKeepBlockScopeWhenCompletingLine: false, - }); + const limitScopeByIndentation = createLimitScopeByIndentationFilter({}); it("cannot handle the case of indent that does'nt have a close line, e.g. chaining call", () => { const context = { ...documentContext` @@ -259,7 +254,7 @@ describe("postprocess", () => { return output; }┤ `; - expect(limitScopeByIndentationDefault(completion, context)).not.to.eq(expected); + expect(limitScopeByIndentation(completion, context)).not.to.eq(expected); }); it("cannot handle the case of indent that does'nt have a close line, e.g. python def function", () => { @@ -285,90 +280,7 @@ describe("postprocess", () => { max = arr[i] return max┤ `; - expect(limitScopeByIndentationDefault(completion, context)).not.to.eq(expected); - }); - }); - - describe("limitScopeByIndentation: with experimentalKeepBlockScopeWhenCompletingLine on", () => { - const limitScopeByIndentationKeepBlock = limitScopeByIndentation({ - experimentalKeepBlockScopeWhenCompletingLine: true, - }); - - it("should limit scope at block end, when completion is continuing uncompleted sentence in the prefix.", () => { - const context = { - ...documentContext` - let a =║ - `, - language: "javascript", - }; - const completion = inline` - ├ 1; - let b = 2;┤ - `; - expect(limitScopeByIndentationKeepBlock(completion, context)).to.eq(completion); - }); - - it("should limit scope at block end, when completion is continuing uncompleted sentence in the prefix.", () => { - const context = { - ...documentContext` - function safeParse(json) { - try { - console.log║ - } - } - `, - language: "javascript", - }; - const completion = inline` - ├("Parsing", { json }); - return JSON.parse(json); - } catch (e) { - return null; - } - }┤ - `; - const expected = inline` - ├("Parsing", { json }); - return JSON.parse(json); - } catch (e) { - return null; - }┤ - ┴┴ - `; - expect(limitScopeByIndentationKeepBlock(completion, context)).to.eq(expected); - }); - - it("should limit scope at same indent level, including closing line, when completion is continuing uncompleted sentence in the prefix, and starting a new indent level in next line.", () => { - const context = { - ...documentContext` - function findMax(arr) { - let max = arr[0]; - for║ - } - `, - language: "javascript", - }; - const completion = inline` - ├ (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - } - return max; - } - console.log(findMax([1, 2, 3, 4, 5]));┤ - `; - const expected = inline` - ├ (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - } - return max; - }┤ - ┴┴ - `; - expect(limitScopeByIndentationKeepBlock(completion, context)).to.eq(expected); + expect(limitScopeByIndentation(completion, context)).not.to.eq(expected); }); }); }); diff --git a/clients/tabby-agent/src/postprocess/limitScopeByIndentation.ts b/clients/tabby-agent/src/postprocess/limitScopeByIndentation.ts index 213b22e84960..a94dd02e06fd 100644 --- a/clients/tabby-agent/src/postprocess/limitScopeByIndentation.ts +++ b/clients/tabby-agent/src/postprocess/limitScopeByIndentation.ts @@ -7,7 +7,7 @@ function parseIndentationContext( inputLines: string[], inputLinesForDetection: string[], context: CompletionContext, - config: AgentConfig["postprocess"]["limitScope"]["indentation"], + _config: AgentConfig["postprocess"]["limitScope"], ): { indentLevelLimit: number; allowClosingLine: boolean } { const result = { indentLevelLimit: 0, @@ -49,13 +49,9 @@ function parseIndentationContext( if (!isCurrentLineInCompletionBlank && !isCurrentLineInPrefixBlank) { // if two reference lines are contacted at current line, it is continuing uncompleted sentence - if (config.experimentalKeepBlockScopeWhenCompletingLine) { - result.indentLevelLimit = referenceLineInPrefixIndent; - } else { - result.indentLevelLimit = referenceLineInPrefixIndent + 1; // + 1 for comparison, no matter how many spaces indent - // allow closing line only if first line is opening a new indent block - result.allowClosingLine &&= isBlockOpeningLine(inputLinesForDetection, 0); - } + result.indentLevelLimit = referenceLineInPrefixIndent + 1; // + 1 for comparison, no matter how many spaces indent + // allow closing line only if first line is opening a new indent block + result.allowClosingLine &&= isBlockOpeningLine(inputLinesForDetection, 0); } else if (referenceLineInCompletionIndent > referenceLineInPrefixIndent) { // if reference line in completion has more indent than reference line in prefix, it is opening a new indent block result.indentLevelLimit = referenceLineInPrefixIndent + 1; @@ -81,9 +77,7 @@ function parseIndentationContext( return result; } -export function limitScopeByIndentation( - config: AgentConfig["postprocess"]["limitScope"]["indentation"], -): PostprocessFilter { +export function limitScopeByIndentation(config: AgentConfig["postprocess"]["limitScope"]): PostprocessFilter { return (input: string, context: CompletionContext) => { const { prefixLines, suffixLines, currentLinePrefix } = context; const inputLines = splitLines(input); diff --git a/clients/tabby-agent/src/postprocess/limitScopeBySyntax.test.ts b/clients/tabby-agent/src/postprocess/limitScopeBySyntax.test.ts deleted file mode 100644 index ee6d6f67d0b7..000000000000 --- a/clients/tabby-agent/src/postprocess/limitScopeBySyntax.test.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { expect } from "chai"; -import { documentContext, inline } from "./testUtils"; -import { limitScopeBySyntax } from "./limitScopeBySyntax"; - -describe("postprocess", () => { - describe("limitScopeBySyntax javascript", () => { - it("should limit scope at function_declaration.", async () => { - const context = { - ...documentContext` - function findMax(arr) {║} - `, - language: "javascript", - }; - const completion = inline` - ├ - let max = arr[0]; - for (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - } - return max; - } - console.log(findMax([1, 2, 3, 4, 5]));┤ - `; - const expected = inline` - ├ - let max = arr[0]; - for (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - } - return max; - }┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - - it("should limit scope at function_declaration", async () => { - const context = { - ...documentContext` - function findMax(arr) { - let max = arr[0];║ - } - `, - language: "javascript", - }; - const completion = inline` - ├ - for (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - } - return max; - }┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(completion); - }); - - it("should limit scope at function_declaration", async () => { - const context = { - ...documentContext` - function findMax(arr) { - let max = arr[0]; - for (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - }║ - } - `, - language: "javascript", - }; - const completion = inline` - ├ - return max; - }┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(completion); - }); - - it("should limit scope at for_statement.", async () => { - const context = { - ...documentContext` - function findMax(arr) { - let max = arr[0]; - for║ - } - `, - language: "javascript", - }; - const completion = inline` - ├ (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - } - return max; - } - console.log(findMax([1, 2, 3, 4, 5]));┤ - `; - const expected = inline` - ├ (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } - }┤ - ┴┴ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - - it("should limit scope at current node if no parent scope found.", async () => { - const context = { - ...documentContext` - let a =║ - `, - language: "javascript", - }; - const completion = inline` - ├ 1; - let b = 2;┤ - `; - const expected = inline` - ├ 1;┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - - it("should handle the bad case of limitScopeByIndentation", async () => { - const context = { - ...documentContext` - function sortWords(input) { - const output = input.trim() - .split("\n") - .map((line) => line.split(" ")) - ║ - } - `, - language: "javascript", - }; - const completion = inline` - ├.flat() - .sort() - .join(" "); - console.log(output); - return output; - } - sortWords("world hello");┤ - `; - const expected = inline` - ├.flat() - .sort() - .join(" "); - console.log(output); - return output; - }┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - }); - - describe("limitScopeBySyntax python", () => { - it("should limit scope at function_definition.", async () => { - const context = { - ...documentContext` - def find_min(arr):║ - `, - language: "python", - }; - const completion = inline` - ├ - min = arr[0] - for i in range(1, len(arr)): - if arr[i] < min: - min = arr[i] - return min - print(find_min([1, 2, 3, 4, 5]))┤ - `; - const expected = inline` - ├ - min = arr[0] - for i in range(1, len(arr)): - if arr[i] < min: - min = arr[i] - return min┤ - ┴┴ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - - it("should limit scope at function_definition.", async () => { - const context = { - ...documentContext` - def find_min(arr): - min = arr[0]║ - `, - language: "python", - }; - const completion = inline` - ├ - for i in range(1, len(arr)): - if arr[i] < min: - min = arr[i] - return min - print(find_min([1, 2, 3, 4, 5]))┤ - `; - const expected = inline` - ├ - for i in range(1, len(arr)): - if arr[i] < min: - min = arr[i] - return min┤ - ┴┴ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - - it("should limit scope at function_definition.", async () => { - const context = { - ...documentContext` - def find_min(arr): - min = arr[0] - for i in range(1, len(arr)): - if arr[i] < min: - min = arr[i]║ - `, - language: "python", - }; - const completion = inline` - ├ - return min┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(completion); - }); - - it("should limit scope at for_statement.", async () => { - const context = { - ...documentContext` - def find_min(arr): - max = arr[0] - for║ - `, - language: "python", - }; - const completion = inline` - ├ i in range(1, len(arr)): - if arr[i] < min: - min = arr[i] - return min - ┤ - `; - const expected = inline` - ├ i in range(1, len(arr)): - if arr[i] < min: - min = arr[i]┤ - ┴┴┴┴ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - - it("should handle the bad case of limitScopeByIndentation", async () => { - const context = { - ...documentContext` - def findMax(arr): - ║ - `, - language: "python", - }; - const completion = inline` - ├max = arr[0] - for i in range(1, len(arr)): - if arr[i] > max: - max = arr[i] - return max - findMax([1, 2, 3, 4, 5])┤ - `; - const expected = inline` - ├max = arr[0] - for i in range(1, len(arr)): - if arr[i] > max: - max = arr[i] - return max┤ - ┴┴ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - }); - - describe("limitScopeBySyntax go", () => { - it("should limit scope at function_declaration.", async () => { - const context = { - ...documentContext` - func findMin(arr []int) int {║} - `, - language: "go", - }; - const completion = inline` - ├ - min := math.MaxInt64 - for _, v := range arr { - if v < min { - min = v - } - } - return min - } - - func main() { - arr := []int{5, 2, 9, 8, 1, 3} - fmt.Println(findMin(arr)) // Output: 1 - }┤ - `; - const expected = inline` - ├ - min := math.MaxInt64 - for _, v := range arr { - if v < min { - min = v - } - } - return min - }┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - - it("should limit scope at for_statement.", async () => { - const context = { - ...documentContext` - func findMin(arr []int) int { - min := math.MaxInt64 - for║ - `, - language: "go", - }; - const completion = inline` - ├ _, v := range arr { - if v < min { - min = v - } - } - return min - }┤ - `; - const expected = inline` - ├ _, v := range arr { - if v < min { - min = v - } - }┤ - ┴┴ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - }); - - describe("limitScopeBySyntax rust", () => { - it("should limit scope at function_item.", async () => { - const context = { - ...documentContext` - fn find_min(arr: &[i32]) -> i32 {║} - `, - language: "rust", - }; - const completion = inline` - ├ - *arr.iter().min().unwrap() - } - fn main() { - let arr = vec![5, 2, 9, 8, 1, 3]; - println!("{}", find_min(&arr)); // Output: 1 - }┤ - `; - const expected = inline` - ├ - *arr.iter().min().unwrap() - }┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - }); - - describe("limitScopeBySyntax ruby", () => { - it("should limit scope at for.", async () => { - const context = { - ...documentContext` - def fibonacci(n)║ - `, - language: "ruby", - }; - const completion = inline` - ├ - return n if n <= 1 - fibonacci(n - 1) + fibonacci(n - 2) - end - puts fibonacci(10)┤ - `; - const expected = inline` - ├ - return n if n <= 1 - fibonacci(n - 1) + fibonacci(n - 2) - end┤ - `; - expect(await limitScopeBySyntax()(completion, context)).to.eq(expected); - }); - }); -}); diff --git a/clients/tabby-agent/src/postprocess/limitScopeBySyntax.ts b/clients/tabby-agent/src/postprocess/limitScopeBySyntax.ts deleted file mode 100644 index 0fc2e46afde7..000000000000 --- a/clients/tabby-agent/src/postprocess/limitScopeBySyntax.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type TreeSitterParser from "web-tree-sitter"; -import { getParser, languagesConfigs } from "../syntax/parser"; -import { typeList } from "../syntax/typeList"; -import { CompletionContext } from "../CompletionContext"; -import { PostprocessFilter, logger } from "./base"; - -export const supportedLanguages = Object.keys(languagesConfigs); - -function findLineBegin(text: string, position: number): number { - let lastNonBlankCharPos = position - 1; - while (lastNonBlankCharPos >= 0 && text[lastNonBlankCharPos]?.match(/\s/)) { - lastNonBlankCharPos--; - } - if (lastNonBlankCharPos < 0) { - return 0; - } - const lineBegin = text.lastIndexOf("\n", lastNonBlankCharPos); - if (lineBegin < 0) { - return 0; - } - const line = text.slice(lineBegin + 1, position); - const indentation = line.search(/\S/); - return lineBegin + 1 + indentation; -} - -function findLineEnd(text: string, position: number): number { - let firstNonBlankCharPos = position; - while (firstNonBlankCharPos < text.length && text[firstNonBlankCharPos]?.match(/\s/)) { - firstNonBlankCharPos++; - } - if (firstNonBlankCharPos >= text.length) { - return text.length; - } - const lineEnd = text.indexOf("\n", firstNonBlankCharPos); - if (lineEnd < 0) { - return text.length; - } - return lineEnd; -} - -function findScope(node: TreeSitterParser.SyntaxNode, typeList: string[][]): TreeSitterParser.SyntaxNode { - for (const types of typeList) { - let scope: TreeSitterParser.SyntaxNode | null = node; - while (scope) { - if (types.includes(scope.type)) { - return scope; - } - scope = scope.parent; - } - } - return node; -} - -export function limitScopeBySyntax(): PostprocessFilter { - return async (input: string, context: CompletionContext) => { - const { position, text, language, prefix, suffix } = context; - if (!supportedLanguages.includes(language)) { - throw new Error(`Language ${language} is not supported`); - } - const languageConfig = languagesConfigs[language]!; - const parser = await getParser(languageConfig); - - const updatedText = prefix + input + suffix; - const updatedTree = parser.parse(updatedText); - const lineBegin = findLineBegin(updatedText, position); - const lineEnd = findLineEnd(updatedText, position); - const scope = findScope( - updatedTree.rootNode.namedDescendantForIndex(lineBegin, lineEnd), - typeList[languageConfig] ?? [], - ); - - if (scope.type == "ERROR") { - throw new Error("Cannot determine syntax scope."); - } - - if (scope.endIndex < position + input.length) { - logger.debug( - { - languageConfig, - text, - updatedText, - position, - lineBegin, - lineEnd, - scope: { type: scope.type, start: scope.startIndex, end: scope.endIndex }, - }, - "Remove content out of syntax scope", - ); - return input.slice(0, scope.endIndex - position); - } - return input; - }; -} diff --git a/clients/tabby-agent/src/syntax/typeList.ts b/clients/tabby-agent/src/syntax/typeList.ts deleted file mode 100644 index fbc1b8d6fabe..000000000000 --- a/clients/tabby-agent/src/syntax/typeList.ts +++ /dev/null @@ -1,113 +0,0 @@ -// https://github.com/tree-sitter/tree-sitter-typescript/blob/master/src/node-types.json -export const typeList: Record = { - tsx: [ - [ - "jsx_element", - "jsx_self_closing_element", - - "for_statement", - "for_in_statement", - "if_statement", - "while_statement", - "do_statement", - "switch_statement", - "try_statement", - "with_statement", - "labeled_statement", - - "class_declaration", - "abstract_class_declaration", - "interface_declaration", - "enum_declaration", - "type_alias_declaration", - "function_declaration", - "generator_function_declaration", - "ambient_declaration", - - "method_definition", - - "import_statement", - "export_statement", - "module", - ], - ["expression_statement", "lexical_declaration"], - ], - - // https://github.com/tree-sitter/tree-sitter-python/blob/master/src/node-types.json - python: [ - [ - "for_statement", - "if_statement", - "while_statement", - "match_statement", - "try_statement", - "with_statement", - - "function_definition", - "decorated_definition", - "class_definition", - - "import_statement", - "import_from_statement", - ], - ], - - // https://github.com/tree-sitter/tree-sitter-go/blob/master/src/node-types.json - go: [ - [ - "for_statement", - "if_statement", - "expression_switch_statement", - "type_switch_statement", - "select_statement", - "labeled_statement", - - "function_declaration", - "method_declaration", - "type_declaration", - - "import_declaration", - "package_clause", - ], - ], - - // https://github.com/tree-sitter/tree-sitter-rust/blob/master/src/node-types.json - rust: [ - [ - "for_expression", - "if_expression", - "while_expression", - "loop_expression", - "match_expression", - "try_expression", - - "function_item", - "type_item", - "enum_item", - "struct_item", - "union_item", - "trait_item", - "impl_item", - - "use_declaration", - ], - ], - - // https://github.com/tree-sitter/tree-sitter-ruby/blob/master/src/node-types.json - ruby: [ - [ - "for", - "if", - "unless", - "while", - "until", - "case", - - "class", - "singleton_class", - "method", - "singleton_method", - "module", - ], - ], -};