diff --git a/resources/functionalTests/block/6do-end1/input.p b/resources/functionalTests/block/6do-end1/input.p new file mode 100644 index 00000000..a27822ab --- /dev/null +++ b/resources/functionalTests/block/6do-end1/input.p @@ -0,0 +1,5 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.blockFormatting": true}*/ + +do while true: +a = 3. end. \ No newline at end of file diff --git a/resources/functionalTests/block/6do-end1/target.p b/resources/functionalTests/block/6do-end1/target.p new file mode 100644 index 00000000..857839e1 --- /dev/null +++ b/resources/functionalTests/block/6do-end1/target.p @@ -0,0 +1,6 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.blockFormatting": true}*/ + +do while true: + a = 3. +end. \ No newline at end of file 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/resources/functionalTests/block/6do-one-liner/input.p b/resources/functionalTests/block/6do-one-liner/input.p new file mode 100644 index 00000000..fad192bd --- /dev/null +++ b/resources/functionalTests/block/6do-one-liner/input.p @@ -0,0 +1,4 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.blockFormatting": true}*/ + +do while true: define variable a as integer no-undo. end. \ No newline at end of file diff --git a/resources/functionalTests/block/6do-one-liner/target.p b/resources/functionalTests/block/6do-one-liner/target.p new file mode 100644 index 00000000..fad192bd --- /dev/null +++ b/resources/functionalTests/block/6do-one-liner/target.p @@ -0,0 +1,4 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.blockFormatting": true}*/ + +do while true: define variable a as integer no-undo. end. \ No newline at end of file diff --git a/resources/functionalTests/if/20-then-same-statement-new-do-new/input.p b/resources/functionalTests/if/20-then-same-statement-new-do-new/input.p new file mode 100644 index 00000000..9cb47f4d --- /dev/null +++ b/resources/functionalTests/if/20-then-same-statement-new-do-new/input.p @@ -0,0 +1,14 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.ifFormatting": true, +"AblFormatter.blockFormatting": true, +"AblFormatter.ifFormattingThenLocation": "Same", +"AblFormatter.ifFormattingStatementLocation": "New", +"AblFormatter.ifFormattingDoLocation": "New"}*/ + +if something <> ? and something <> 0 then + oObject:method(something). +else if a = 3 then +do: + oObject:method(something). end. +else + message "a" \ No newline at end of file diff --git a/resources/functionalTests/if/20-then-same-statement-new-do-new/target.p b/resources/functionalTests/if/20-then-same-statement-new-do-new/target.p new file mode 100644 index 00000000..de60bab4 --- /dev/null +++ b/resources/functionalTests/if/20-then-same-statement-new-do-new/target.p @@ -0,0 +1,15 @@ +/* formatterSettingsOverride */ +/* { "AblFormatter.ifFormatting": true, +"AblFormatter.blockFormatting": true, +"AblFormatter.ifFormattingThenLocation": "Same", +"AblFormatter.ifFormattingStatementLocation": "New", +"AblFormatter.ifFormattingDoLocation": "New"}*/ + +if something <> ? and something <> 0 then + oObject:method(something). +else if a = 3 then +do: + oObject:method(something). +end. +else + message "a" \ No newline at end of file diff --git a/src/v2/formatters/block/BlockFormatter.ts b/src/v2/formatters/block/BlockFormatter.ts index 8e8ca68f..d03647fc 100644 --- a/src/v2/formatters/block/BlockFormatter.ts +++ b/src/v2/formatters/block/BlockFormatter.ts @@ -80,9 +80,21 @@ export class BlockFormater extends AFormatter implements IFormatter { ) ); - const codeLines = FormatterHelper.getCurrentText(parent, fullText) - .split(fullText.eolDelimiter) - .slice(0, -1); + let codeLines = FormatterHelper.getCurrentText(parent, fullText).split( + fullText.eolDelimiter + ); + + // Do not do any changes for one-liner blocks + if (codeLines.length === 1) { + const text = FormatterHelper.getCurrentText(node, fullText); + return this.getCodeEdit(node, text, text, fullText); + } + const lastLine = codeLines[codeLines.length - 1]; + + const lastLineMatchesTypicalStructure = this.matchEndPattern(lastLine); + if (lastLineMatchesTypicalStructure) { + codeLines.pop(); + } let n = 0; let lineChangeDelta = 0; @@ -110,29 +122,61 @@ export class BlockFormater extends AFormatter implements IFormatter { } }); - const lastLine = FormatterHelper.getCurrentText(parent, fullText) - .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 (lastLineMatchesTypicalStructure) { + 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.getActualTextIndentation( + lastLine, + fullText + ); + + if (endRowDelta !== 0) { + indentationEdits.push({ + line: + parent.endPosition.row - + parent.startPosition.row, + lineChangeDelta: endRowDelta, + }); + } + } + } + codeLines.push(lastLine); + } else { + const parentOfEndNode = formattingOnStatement + ? node.parent + : parent; + if (parentOfEndNode !== null) { + const endNode = parentOfEndNode.children.find( + (node) => node.type === SyntaxNodeType.EndKeyword + ); + if (endNode !== undefined) { + const index = endNode.startPosition.column; + const firstPart = lastLine.slice(0, index); + 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, + }); + } } } } @@ -140,32 +184,33 @@ export class BlockFormater extends AFormatter implements IFormatter { return this.getCodeEditsFromIndentationEdits( parent, fullText, - indentationEdits + indentationEdits, + codeLines ); } private getCodeEditsFromIndentationEdits( node: SyntaxNode, fullText: FullText, - indentationEdits: IndentationEdits[] + indentationEdits: IndentationEdits[], + codeLines: string[] ): CodeEdit | CodeEdit[] | undefined { const text = FormatterHelper.getCurrentText(node, fullText); const newText = this.applyIndentationEdits( - text, indentationEdits, - fullText + fullText, + codeLines ); return this.getCodeEdit(node, text, newText, fullText); } private applyIndentationEdits( - code: string, edits: IndentationEdits[], - fullText: FullText + fullText: FullText, + lines: string[] ): string { // Split the code into lines - const lines = code.split(fullText.eolDelimiter); // Apply each edit edits.forEach((edit) => { @@ -221,6 +266,14 @@ export class BlockFormater extends AFormatter implements IFormatter { } return node; } + + private matchEndPattern(str: string): boolean { + /* Returns true if string matches the pattern: (any characters that do not include a dot)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[^.]*\..*$/i; + return pattern.test(str); + } } interface IndentationEdits { diff --git a/src/v2/formatters/body/BodyFormatter.ts b/src/v2/formatters/body/BodyFormatter.ts index 7a13bc23..6c8561fa 100644 --- a/src/v2/formatters/body/BodyFormatter.ts +++ b/src/v2/formatters/body/BodyFormatter.ts @@ -110,33 +110,6 @@ export class BodyFormatter extends AFormatter implements IFormatter { } }); - const lastLine = FormatterHelper.getCurrentText(parent, fullText) - .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 (endRowDelta !== 0) { - indentationEdits.push({ - line: parent.endPosition.row - parent.startPosition.row, - lineChangeDelta: endRowDelta, - }); - } - } - } - return this.getCodeEditsFromIndentationEdits( node, fullText,