@abaplint/core
Version:
abaplint - Core API
240 lines • 11.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Indent = void 0;
const Statements = require("../abap/2_statements/statements");
const Expressions = require("../abap/2_statements/expressions");
const _statement_1 = require("../abap/2_statements/statements/_statement");
const virtual_position_1 = require("../virtual_position");
const structures_1 = require("../abap/3_structures/structures");
// todo, will break if there is multiple statements per line?
class Indent {
constructor(options) {
this.globalClasses = new Set();
this.options = options || {};
}
execute(original, modified) {
const statements = original.getStatements();
const expected = this.getExpectedIndents(original);
const lines = modified.split("\n");
for (const statement of statements) {
if (statement.getFirstToken().getStart() instanceof virtual_position_1.VirtualPosition) {
continue; // macro contents
}
const exp = expected.shift();
if (exp === undefined || exp < 0) {
continue;
}
const row = statement.getFirstToken().getStart().getRow() - 1;
lines[row] = lines[row].trim();
for (let i = 1; i < exp; i++) {
lines[row] = " " + lines[row];
}
}
return lines.join("\n");
}
// returns list of expected indentation for each line/statement?
getExpectedIndents(file) {
var _a;
const ret = [];
const init = 1;
const stack = new Stack();
let indent = init;
let parentIsEvent = false;
const isDynpro = ((_a = file.getStructure()) === null || _a === void 0 ? void 0 : _a.get()) instanceof structures_1.DynproLogic;
let previousStatement = undefined;
for (const statement of file.getStatements()) {
if (statement.getFirstToken().getStart() instanceof virtual_position_1.VirtualPosition) {
continue; // skip macro contents
}
const type = statement.get();
if (type instanceof Statements.EndIf
|| type instanceof Statements.EndWhile
|| type instanceof Statements.EndModule
|| type instanceof Statements.EndSelect
|| type instanceof Statements.EndMethod
|| type instanceof Statements.EndChain
|| type instanceof Statements.EndAt
|| type instanceof Statements.Else
|| type instanceof Statements.EndExec
|| type instanceof Statements.EndOfDefinition
|| type instanceof Statements.EndLoop
|| type instanceof Statements.EndTestInjection
|| type instanceof Statements.EndTestSeam
|| type instanceof Statements.EndForm
|| type instanceof Statements.EndCatch
|| (this.options.selectionScreenBlockIndentation === true
&& type instanceof Statements.SelectionScreen
&& (statement.concatTokens().toUpperCase().includes("END OF SCREEN") ||
statement.concatTokens().toUpperCase().includes("END OF BLOCK") ||
statement.concatTokens().toUpperCase().includes("END OF LINE")))
|| type instanceof Statements.ElseIf
|| type instanceof Statements.EndFunction
|| type instanceof Statements.EndInterface
|| type instanceof Statements.EndDo) {
indent = indent - 2;
}
else if (type instanceof Statements.StartOfSelection
|| type instanceof Statements.AtSelectionScreen
|| type instanceof Statements.AtLineSelection
|| type instanceof Statements.AtPF
|| type instanceof Statements.Initialization
|| type instanceof Statements.AtUserCommand
|| type instanceof Statements.ProcessAfterInput
|| type instanceof Statements.ProcessBeforeOutput
|| type instanceof Statements.ProcessOnValueRequest
|| type instanceof Statements.TopOfPage
|| type instanceof Statements.Get
|| type instanceof Statements.EndOfSelection
|| type instanceof Statements.LoadOfProgram) {
indent = init;
parentIsEvent = true;
}
else if (type instanceof Statements.Form
|| (type instanceof Statements.Include && parentIsEvent)
|| (type instanceof Statements.Module && isDynpro === false)
|| type instanceof Statements.ClassImplementation
|| type instanceof Statements.ClassDefinition) {
indent = init;
parentIsEvent = false;
}
else if (type instanceof Statements.Cleanup
|| type instanceof Statements.Catch) {
indent = stack.peek() - 2;
}
else if (type instanceof Statements.Public
|| type instanceof Statements.Protected
|| type instanceof Statements.Private
|| type instanceof Statements.WhenType
|| type instanceof Statements.WhenOthers
|| type instanceof Statements.When) {
indent = stack.peek();
}
else if (type instanceof Statements.EndTry) {
indent = stack.pop() - (this.options.alignTryCatch ? 2 : 4);
}
else if (type instanceof Statements.EndClass
|| type instanceof Statements.EndCase) {
indent = stack.pop() - 2;
indent = Math.max(indent, init); // maybe move this out of switch before ret.push(indent)
}
else if (type instanceof _statement_1.Comment
|| type instanceof Statements.IncludeType
|| type instanceof _statement_1.Empty
|| type instanceof _statement_1.MacroContent) {
ret.push(-1);
previousStatement = statement;
continue;
}
if (previousStatement
&& !(previousStatement.get() instanceof _statement_1.Comment)
&& previousStatement.getLastToken().getEnd().getRow() === statement.getFirstToken().getStart().getRow()) {
// any indentation allowed if there are multiple statements on the same line
ret.push(-1);
previousStatement = statement;
continue;
}
ret.push(indent);
if (type instanceof Statements.If
|| type instanceof Statements.While
|| (type instanceof Statements.Module && isDynpro === false)
|| type instanceof Statements.SelectLoop
|| type instanceof Statements.FunctionModule
|| type instanceof Statements.Interface
|| type instanceof Statements.Do
|| type instanceof Statements.At
|| type instanceof Statements.AtFirst
|| type instanceof Statements.AtLast
|| type instanceof Statements.ExecSQL
|| type instanceof Statements.Catch
|| type instanceof Statements.ProcessAfterInput
|| type instanceof Statements.ProcessBeforeOutput
|| type instanceof Statements.ProcessOnValueRequest
|| type instanceof Statements.Define
|| type instanceof Statements.When
|| type instanceof Statements.WhenType
|| type instanceof Statements.WhenOthers
|| type instanceof Statements.Cleanup
|| type instanceof Statements.Loop
|| type instanceof Statements.LoopAtScreen
|| type instanceof Statements.CatchSystemExceptions
|| type instanceof Statements.Form
|| type instanceof Statements.Else
|| type instanceof Statements.ElseIf
|| type instanceof Statements.MethodImplementation
|| type instanceof Statements.Chain
|| type instanceof Statements.TestInjection
|| type instanceof Statements.TestSeam
|| (this.options.selectionScreenBlockIndentation === true
&& type instanceof Statements.SelectionScreen
&& (statement.concatTokens().toUpperCase().includes("BEGIN OF SCREEN") ||
statement.concatTokens().toUpperCase().includes("BEGIN OF TABBED BLOCK") ||
statement.concatTokens().toUpperCase().includes("BEGIN OF BLOCK") ||
statement.concatTokens().toUpperCase().includes("BEGIN OF LINE")))
|| type instanceof Statements.StartOfSelection
|| type instanceof Statements.Get
|| type instanceof Statements.AtSelectionScreen
|| type instanceof Statements.AtLineSelection
|| type instanceof Statements.LoadOfProgram
|| type instanceof Statements.Initialization
|| type instanceof Statements.AtUserCommand
|| type instanceof Statements.TopOfPage
|| type instanceof Statements.EndOfSelection
|| type instanceof Statements.Public
|| type instanceof Statements.Protected
|| type instanceof Statements.Private) {
indent = indent + 2;
}
else if (type instanceof Statements.Try) {
indent = indent + (this.options.alignTryCatch ? 2 : 4);
stack.push(indent);
}
else if (type instanceof Statements.ClassDefinition
|| type instanceof Statements.Case
|| type instanceof Statements.CaseType
|| type instanceof Statements.ClassImplementation) {
indent = indent + (this.skipIndentForGlobalClass(statement) ? 0 : 2);
stack.push(indent);
}
previousStatement = statement;
}
return ret;
}
skipIndentForGlobalClass(statement) {
if (!this.options.globalClassSkipFirst) {
return false;
}
const type = statement.get();
if (type instanceof Statements.ClassDefinition && statement.findFirstExpression(Expressions.ClassGlobal)) {
const className = statement.findFirstExpression(Expressions.ClassName);
if (className) {
this.globalClasses.add(className.getFirstToken().getStr().toUpperCase());
}
return true;
}
else if (type instanceof Statements.ClassImplementation) {
const className = statement.findFirstExpression(Expressions.ClassName);
if (className && this.globalClasses.has(className.getFirstToken().getStr().toUpperCase())) {
return true;
}
}
return false;
}
}
exports.Indent = Indent;
class Stack {
constructor() {
this.items = [];
}
push(item) {
this.items.push(item);
}
peek() {
return this.items[this.items.length - 1];
}
pop() {
const peek = this.peek();
this.items = this.items.slice(0, this.items.length - 1);
return peek;
}
}
//# sourceMappingURL=indent.js.map