From e6f0dd3a9ea7f26a17205a60126f38aef3ce5ac4 Mon Sep 17 00:00:00 2001 From: gmickus Date: Wed, 11 Sep 2024 10:08:53 +0300 Subject: [PATCH 1/2] Add comments --- src/v2/formatters/block/BlockFormatter.ts | 63 ++++--- src/v2/formatters/body/BodyFormatter.ts | 204 ++++++++++++++++++++++ 2 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 src/v2/formatters/body/BodyFormatter.ts diff --git a/src/v2/formatters/block/BlockFormatter.ts b/src/v2/formatters/block/BlockFormatter.ts index 87fb72b8..89fdd49c 100644 --- a/src/v2/formatters/block/BlockFormatter.ts +++ b/src/v2/formatters/block/BlockFormatter.ts @@ -1,6 +1,9 @@ import { SyntaxNode } from "web-tree-sitter"; import { IFormatter } from "../../formatterFramework/IFormatter"; -import { bodyBlockKeywords, SyntaxNodeType } from "../../../model/SyntaxNodeType"; +import { + bodyBlockKeywords, + SyntaxNodeType, +} from "../../../model/SyntaxNodeType"; import { CodeEdit } from "../../model/CodeEdit"; import { FullText } from "../../model/FullText"; import { FormatterHelper } from "../../formatterFramework/FormatterHelper"; @@ -96,6 +99,7 @@ export class BlockFormater extends AFormatter implements IFormatter { line: index, lineChangeDelta: lineChangeDelta, }); + console.log("change line: " + index); } }); @@ -103,25 +107,36 @@ export class BlockFormater extends AFormatter implements IFormatter { .split(fullText.eolDelimiter) .slice(-1)[0]; - const parentOfEndNode = formattingOnStatement ? node.parent : parent; - if (parentOfEndNode !== null) { - const endNode = parentOfEndNode.children.find( - (node) => node.type === SyntaxNodeType.EndKeyword - ); - - if (endNode !== undefined) { - const endRowDelta = - parentIndentation - - FormatterHelper.getActualTextIndentation( - lastLine, - fullText - ); + if (this.matchEndPattern(lastLine)) { + const parentOfEndNode = formattingOnStatement + ? node.parent + : parent; + if (parentOfEndNode !== null) { + const endNode = parentOfEndNode.children.find( + (node) => node.type === SyntaxNodeType.EndKeyword + ); - if (endRowDelta !== 0) { - indentationEdits.push({ - line: parent.endPosition.row - parent.startPosition.row, - lineChangeDelta: endRowDelta, - }); + if (endNode !== undefined) { + const endRowDelta = + parentIndentation - + FormatterHelper.getActualStatementIndentation( + endNode, + fullText + ); + + if (endRowDelta !== 0) { + indentationEdits.push({ + line: + parent.endPosition.row - + parent.startPosition.row, + lineChangeDelta: endRowDelta, + }); + console.log( + "change lineEnd: " + + (parent.endPosition.row - + parent.startPosition.row) + ); + } } } } @@ -197,7 +212,7 @@ export class BlockFormater extends AFormatter implements IFormatter { node.parent?.type === SyntaxNodeType.CaseOtherwiseBranch) ) { return node.parent; - }else if ( + } else if ( node.type === SyntaxNodeType.DoBlock && (node.parent?.type === SyntaxNodeType.ElseIfStatement || node.parent?.type === SyntaxNodeType.ElseStatement) @@ -210,6 +225,14 @@ export class BlockFormater extends AFormatter implements IFormatter { } return node; } + + private matchEndPattern(str: string): boolean { + /* Returns true if string matches the pattern: (any characters)end(any characters that do not include a dot).(any characters) + In essence, it returns true on the case when on a line there is nothing but an end statement. + */ + const pattern = /^.*end[^.]*\..*$/; + return pattern.test(str); + } } interface IndentationEdits { diff --git a/src/v2/formatters/body/BodyFormatter.ts b/src/v2/formatters/body/BodyFormatter.ts new file mode 100644 index 00000000..d76f0747 --- /dev/null +++ b/src/v2/formatters/body/BodyFormatter.ts @@ -0,0 +1,204 @@ +import { SyntaxNode } from "web-tree-sitter"; +import { RegisterFormatter } from "../../formatterFramework/formatterDecorator"; +import { IFormatter } from "../../formatterFramework/IFormatter"; +import { CodeEdit } from "../../model/CodeEdit"; +import { FullText } from "../../model/FullText"; +import { AFormatter } from "../AFormatter"; +import { BodySettings } from "./BodySettings"; +import { IConfigurationManager } from "../../../utils/IConfigurationManager"; +import { + bodyBlockKeywords, + SyntaxNodeType, +} from "../../../model/SyntaxNodeType"; +import { FormatterHelper } from "../../formatterFramework/FormatterHelper"; + +@RegisterFormatter +export class BodyFormatter extends AFormatter implements IFormatter { + public static readonly formatterLabel = "bodyFormatting"; + private readonly settings: BodySettings; + + public constructor(configurationManager: IConfigurationManager) { + super(configurationManager); + this.settings = new BodySettings(configurationManager); + } + + public match(node: Readonly): boolean { + if (!bodyBlockKeywords.hasFancy(node.type, "")) { + return false; + } + + let parent = node.parent; + if (parent === null || parent.type !== SyntaxNodeType.ForStatement) { + return false; + } + + return true; + } + public parse( + node: Readonly, + fullText: Readonly + ): CodeEdit | CodeEdit[] | undefined { + let indentationEdits: IndentationEdits[] = []; + + let parent = node.parent; + + if (parent === null) { + return undefined; + } + + let formattingOnStatement = false; + if (parent.type === SyntaxNodeType.DoBlock) { + const grandParent = parent.parent; + if ( + grandParent !== null && + grandParent.type === SyntaxNodeType.OnStatement + ) { + parent = grandParent; + formattingOnStatement = true; + } + } + + const parentIndentation = FormatterHelper.getActualStatementIndentation( + this.getParentIndentationSourceNode(parent), + fullText + ); + + const indentationStep = this.settings.tabSize(); + const blockStatementsStartRows = node.children + .filter((child) => { + if (child.type === ":") { + return false; + } + return true; + }) + .map( + (child) => + child.startPosition.row + + FormatterHelper.getActualTextRow( + FormatterHelper.getCurrentText(child, fullText), + fullText + ) + ); + + const codeLines = FormatterHelper.getBodyText(node, fullText).split( + fullText.eolDelimiter + ); + + console.log("codeLines: " + codeLines); + + let n = 0; + let lineChangeDelta = 0; + codeLines.forEach((codeLine, index) => { + const lineNumber = node.startPosition.row + index; + + // adjust delta + if (blockStatementsStartRows[n] === lineNumber) { + lineChangeDelta = + parentIndentation + + indentationStep - + FormatterHelper.getActualTextIndentation( + codeLine, + fullText + ); + + n++; + } + + if (lineChangeDelta !== 0) { + indentationEdits.push({ + line: index, + lineChangeDelta: lineChangeDelta, + }); + } + }); + + return this.getCodeEditsFromIndentationEdits( + node, + fullText, + indentationEdits + ); + } + + private getCodeEditsFromIndentationEdits( + node: SyntaxNode, + fullText: FullText, + indentationEdits: IndentationEdits[] + ): CodeEdit | CodeEdit[] | undefined { + const text = FormatterHelper.getCurrentText(node, fullText); + const newText = this.applyIndentationEdits( + text, + indentationEdits, + fullText + ); + + return this.getCodeEdit(node, text, newText, fullText); + } + + private applyIndentationEdits( + code: string, + edits: IndentationEdits[], + fullText: FullText + ): string { + // Split the code into lines + const lines = code.split(fullText.eolDelimiter); + + // Apply each edit + edits.forEach((edit) => { + const { line, lineChangeDelta } = edit; + + // Ensure the line number is within the range + if (line >= 0 && line < lines.length) { + const currentLine = lines[line]; + // Count current leading spaces + const currentLeadingSpaces = + RegExp(/^\s*/).exec(currentLine)?.[0].length || 0; + // Calculate new indentation + + const newLeadingSpaces = Math.max( + 0, + currentLeadingSpaces + lineChangeDelta + ); + + // Update the line with the new indentation + + lines[line] = + " ".repeat(newLeadingSpaces) + currentLine.trimStart(); + } + }); + + // Join the lines back into a single string + return lines.join(fullText.eolDelimiter); + } + + //refactor + private getParentIndentationSourceNode(node: SyntaxNode): SyntaxNode { + if ( + node.type === SyntaxNodeType.DoBlock && + node.parent?.type === SyntaxNodeType.IfStatement + ) { + return node.parent; + } else if ( + node.type === SyntaxNodeType.DoBlock && + (node.parent?.type === SyntaxNodeType.CaseWhenBranch || + node.parent?.type === SyntaxNodeType.CaseOtherwiseBranch) + ) { + return node.parent; + } else if ( + node.type === SyntaxNodeType.DoBlock && + (node.parent?.type === SyntaxNodeType.ElseIfStatement || + node.parent?.type === SyntaxNodeType.ElseStatement) + ) { + if (node.parent.parent === null) { + return node.parent; + } + + return node.parent.parent; + } + return node; + } +} + +interface IndentationEdits { + line: number; + lineChangeDelta: number; +} From c1616fb74c6805db7256a7e0e9d8f2443fd24439 Mon Sep 17 00:00:00 2001 From: gmickus Date: Wed, 11 Sep 2024 13:36:08 +0300 Subject: [PATCH 2/2] Improve formatting of END --- .../block/{6do-end => 6do-end1}/input.p | 0 .../block/{6do-end => 6do-end1}/target.p | 0 resources/functionalTests/block/6do-end2/input.p | 7 +++++++ resources/functionalTests/block/6do-end2/target.p | 8 ++++++++ src/v2/formatters/block/BlockFormatter.ts | 13 +++++++++++++ 5 files changed, 28 insertions(+) rename resources/functionalTests/block/{6do-end => 6do-end1}/input.p (100%) rename resources/functionalTests/block/{6do-end => 6do-end1}/target.p (100%) create mode 100644 resources/functionalTests/block/6do-end2/input.p create mode 100644 resources/functionalTests/block/6do-end2/target.p diff --git a/resources/functionalTests/block/6do-end/input.p b/resources/functionalTests/block/6do-end1/input.p similarity index 100% rename from resources/functionalTests/block/6do-end/input.p rename to resources/functionalTests/block/6do-end1/input.p diff --git a/resources/functionalTests/block/6do-end/target.p b/resources/functionalTests/block/6do-end1/target.p similarity index 100% rename from resources/functionalTests/block/6do-end/target.p rename to resources/functionalTests/block/6do-end1/target.p diff --git a/resources/functionalTests/block/6do-end2/input.p b/resources/functionalTests/block/6do-end2/input.p new file mode 100644 index 00000000..185c485a --- /dev/null +++ b/resources/functionalTests/block/6do-end2/input.p @@ -0,0 +1,7 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.blockFormatting": true}*/ + +do transaction: + do while true: + a = 3. end. + end. \ No newline at end of file diff --git a/resources/functionalTests/block/6do-end2/target.p b/resources/functionalTests/block/6do-end2/target.p new file mode 100644 index 00000000..8ec170b5 --- /dev/null +++ b/resources/functionalTests/block/6do-end2/target.p @@ -0,0 +1,8 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.blockFormatting": true}*/ + +do transaction: + do while true: + a = 3. + end. +end. \ No newline at end of file diff --git a/src/v2/formatters/block/BlockFormatter.ts b/src/v2/formatters/block/BlockFormatter.ts index bafdb468..d03647fc 100644 --- a/src/v2/formatters/block/BlockFormatter.ts +++ b/src/v2/formatters/block/BlockFormatter.ts @@ -164,6 +164,19 @@ export class BlockFormater extends AFormatter implements IFormatter { const secondPart = lastLine.slice(index); codeLines[codeLines.length - 1] = firstPart; codeLines.push(secondPart); + const endRowDelta = + parentIndentation - + FormatterHelper.getActualTextIndentation( + secondPart, + fullText + ); + + if (endRowDelta !== 0) { + indentationEdits.push({ + line: codeLines.length - 1, + lineChangeDelta: endRowDelta, + }); + } } } }