Skip to content

Commit

Permalink
Refactor indenter (#243)
Browse files Browse the repository at this point in the history
* use static extension for whitespace policy add/remove
* don't change whitespace around comments in line ends
* refactored indenter
  • Loading branch information
AlexHaxe authored Oct 13, 2018
1 parent ec93fbd commit c012c94
Show file tree
Hide file tree
Showing 17 changed files with 380 additions and 141 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
- Fixed handling of metadata parameter, fixes [#241](https://github.com/HaxeCheckstyle/haxe-formatter/issues/241) ([#242](https://github.com/HaxeCheckstyle/haxe-formatter/issues/242))
- Changed default rules for function signature, see [#232](https://github.com/HaxeCheckstyle/haxe-formatter/issues/232) ([#233](https://github.com/HaxeCheckstyle/haxe-formatter/issues/233))
- Refactored marker classes to use a common base class [#239](https://github.com/HaxeCheckstyle/haxe-formatter/issues/239)
- Refactored whitespace policy add/remove handling [#243](https://github.com/HaxeCheckstyle/haxe-formatter/issues/243)
- Refactored indentation logic [#243](https://github.com/HaxeCheckstyle/haxe-formatter/issues/243)
- Removed whitespace change around comments during line end marking [#243](https://github.com/HaxeCheckstyle/haxe-formatter/issues/243)

## version 1.1.0 (2018-09-04)

Expand Down
5 changes: 3 additions & 2 deletions src/formatter/codedata/TokenList.hx
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,9 @@ class TokenList {

function logAction(callerPos:PosInfos, token:TokenTree, what:String, ?pos:PosInfos) {
var func:String = '${callerPos.fileName}:${callerPos.lineNumber}:${callerPos.methodName}';
var operation:String = '[${pos.methodName} ($what)]';
var tokPos:String = ' on `${token}` (${token.pos})';
var operation:String = '${pos.methodName.rpad(" ", 25)} $what';
var tok:String = '`${token}`';
var tokPos:String = '${tok.rpad(" ", 30)} (${token.pos})';

var text:String = func.rpad(" ", 75) + operation.rpad(" ", 70) + tokPos;
var file:FileOutput = File.append("hxformat.log", false);
Expand Down
1 change: 1 addition & 0 deletions src/formatter/import.hx
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ import formatter.codedata.TokenInfo;

using StringTools;
using tokentree.TokenTreeAccessHelper;
using formatter.config.WhitespacePolicy;
192 changes: 103 additions & 89 deletions src/formatter/marker/Indenter.hx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class Indenter {
default:
}
#if debugIndent
log(token, "------");
logIndentStart();
log(token, "start");
#end
token = findEffectiveParent(token);
#if debugIndent
Expand All @@ -66,6 +67,7 @@ class Indenter {
if (token.tok == null) {
return token.getFirstChild();
}

switch (token.tok) {
case BrOpen:
var parent:TokenTree = token.parent;
Expand Down Expand Up @@ -106,15 +108,6 @@ class Indenter {
default:
}
case BrClose, BkClose:
var current:TokenInfo = parsedCode.tokenList.getTokenAt(token.index);
var next:TokenInfo = parsedCode.tokenList.getNextToken(token);
if ((current.whitespaceAfter != Newline) && (current.whitespaceAfter != SpaceOrNewline) && (next != null)) {
switch (next.token.tok) {
case BrClose, BkClose, PClose:
return findEffectiveParent(next.token);
default:
}
}
return findEffectiveParent(token.parent);
case PClose:
return findEffectiveParent(token.parent);
Expand Down Expand Up @@ -169,65 +162,59 @@ class Indenter {
return token;
}

function setupCalcFromCandidates(token:TokenTree, prevToken:TokenTree, indentingTokensCandidates:Array<TokenTree>):Array<TokenTree> {
var indentingTokens:Array<TokenTree> = [];
if (!isIndentingToken(token)) {
if (!parsedCode.tokenList.isSameLine(prevToken, token)) {
indentingTokens.push(prevToken);
}
return indentingTokens;
}
if (prevToken.is(POpen) && token.is(BrOpen)) {
var info:TokenInfo = parsedCode.tokenList.getTokenAt(token.index);
if ((info.whitespaceAfter != Newline) && (info.whitespaceAfter != SpaceOrNewline)) {
indentingTokens.push(prevToken);
function countLineBreaks(indentingTokensCandidates:Array<TokenTree>):Int {
var count:Int = 0;
var prevToken:TokenTree = null;
var currentToken:TokenTree = null;
var mustIndent:Bool;
var lastIndentingToken:TokenTree = null;
for (token in indentingTokensCandidates) {
prevToken = currentToken;
if (prevToken == null) {
prevToken = token;
}
return indentingTokens;
}
if (!parsedCode.tokenList.isSameLine(prevToken, token)) {
indentingTokens.push(prevToken);
return indentingTokens;
}
indentingTokensCandidates.unshift(prevToken);
prevToken = token;
return indentingTokens;
}

function calcFromCandidates(token:TokenTree):Int {
var indentingTokensCandidates:Array<TokenTree> = findIndentingCandidates(token);
#if debugIndent
log(token, "candidates: " + indentingTokensCandidates);
#end
if (indentingTokensCandidates.length <= 0) {
return 0;
}
var prevToken:TokenTree = indentingTokensCandidates.shift();
var indentingTokens:Array<TokenTree> = setupCalcFromCandidates(token, prevToken, indentingTokensCandidates);

while (indentingTokensCandidates.length > 0) {
var currentToken:TokenTree = indentingTokensCandidates.shift();
currentToken = token;
#if debugIndent
log(token, '"$prevToken" -> "$currentToken"');
#end
mustIndent = false;
switch (prevToken.tok) {
case Kwd(KwdElse):
if (currentToken.is(Kwd(KwdIf))) {
prevToken = currentToken;
continue;
}
case Kwd(KwdCatch):
if (currentToken.is(Kwd(KwdTry))) {
prevToken = currentToken;
continue;
}
case Kwd(KwdFunction):
if (currentToken.is(POpen)) {
prevToken = currentToken;
mustIndent = true;
continue;
}
case Dot:
switch (currentToken.tok) {
case POpen, BrOpen:
mustIndent = true;
case Dot:
prevToken = currentToken;
continue;
if ((prevToken.pos.min == currentToken.pos.min) && parsedCode.tokenList.isNewLineBefore(currentToken)) {
// first dot & has a newline
} else {
continue;
}
case Binop(OpAssign):
case Kwd(KwdReturn), Kwd(KwdUntyped), Kwd(KwdNew):
if (!parsedCode.tokenList.isNewLineBefore(prevToken)) {
continue;
}
default:
if (parsedCode.tokenList.isNewLineBefore(prevToken)) {
#if debugIndent
log(token, 'adds "$prevToken"');
#end
count++;
continue;
}
}
case BrOpen:
switch (currentToken.tok) {
Expand All @@ -236,64 +223,87 @@ class Indenter {
switch (type) {
case OBJECTDECL:
default:
prevToken = currentToken;
continue;
}
case POpen:
var child:TokenTree = currentToken.getFirstChild();
if (child.index != prevToken.index) {
return calcFromCandidates(child) + indentingTokens.length;
if (!parsedCode.tokenList.isNewLineBefore(prevToken)) {
continue;
}
prevToken = currentToken;
continue;
case Binop(OpAssign):
if (currentToken.access().parent().parent().is(Kwd(KwdTypedef)).exists()) {
prevToken = currentToken;
continue;
}
default:
}
case DblDot:
switch (currentToken.tok) {
case Kwd(KwdCase), Kwd(KwdDefault):
prevToken = currentToken;
continue;
if ((lastIndentingToken != null) && (lastIndentingToken.pos.min == prevToken.pos.min)) {
continue;
}
mustIndent = true;
default:
}
default:
}
if (!mustIndent(currentToken, prevToken)) {
prevToken = currentToken;
if (!mustIndent && parsedCode.tokenList.isSameLineBetween(currentToken, prevToken, false)) {
continue;
}
indentingTokens.push(currentToken);
prevToken = currentToken;
if (!isIndentingToken(currentToken)) {
continue;
}
#if debugIndent
log(token, 'adds "$currentToken"');
#end
lastIndentingToken = currentToken;
count++;
}
#if debugIndent
log(token, "final: " + indentingTokens);
#end
return indentingTokens.length;
return count;
}

function mustIndent(currentToken:TokenTree, prevToken:TokenTree):Bool {
switch (currentToken.tok) {
case DblDot:
return true;
default:
function calcFromCandidates(token:TokenTree):Int {
var indentingTokensCandidates:Array<TokenTree> = findIndentingCandidates(token);
#if debugIndent
log(token, "candidates: " + indentingTokensCandidates);
#end
if (indentingTokensCandidates.length <= 0) {
return 0;
}
return !parsedCode.tokenList.isSameLine(prevToken, currentToken);
var count:Int = countLineBreaks(indentingTokensCandidates);
#if debugIndent
log(token, "final indent: " + count);
#end
return count;
}

function findIndentingCandidates(token:TokenTree):Array<TokenTree> {
var indentingTokensCandidates:Array<TokenTree> = [];
var lastIndentingToken:TokenTree = null;
switch (token.tok) {
case Dot:
lastIndentingToken = token;
default:
}
indentingTokensCandidates.push(token);
var parent:TokenTree = token;
while ((parent.parent != null) && (parent.parent.tok != null)) {
parent = parent.parent;
if (parent.pos.min > token.pos.min) {
continue;
}
if (isIndentingToken(parent)) {
if (lastIndentingToken != null) {
if (lastIndentingToken.is(Dot) && parent.is(Dot)) {
continue;
}
}
indentingTokensCandidates.push(parent);
lastIndentingToken = parent;
} else {
if (parsedCode.tokenList.isNewLineBefore(parent)) {
indentingTokensCandidates.push(parent);
lastIndentingToken = parent;
}
}
}
return indentingTokensCandidates;
Expand Down Expand Up @@ -328,42 +338,46 @@ class Indenter {
if (config.conditionalPolicy == AlignedIncrease) {
return true;
}
case Kwd(KwdIf):
return true;
case Kwd(KwdElse):
return true;
case Kwd(KwdFor):
case Kwd(KwdIf), Kwd(KwdElse):
return true;
case Kwd(KwdDo):
case Kwd(KwdFor), Kwd(KwdDo):
return true;
case Kwd(KwdWhile):
var parent:TokenTree = token.parent;
if ((parent != null) && (parent.is(Kwd(KwdDo)))) {
return false;
}
return true;
case Kwd(KwdTry):
return true;
case Kwd(KwdCatch):
case Kwd(KwdTry), Kwd(KwdCatch), Kwd(KwdThrow):
return true;
case Kwd(KwdFunction):
return true;
case Kwd(KwdReturn):
return true;
case Kwd(KwdUntyped):
case Kwd(KwdReturn), Kwd(KwdUntyped):
return true;
case Kwd(KwdNew):
switch (token.parent.tok) {
case Kwd(KwdFunction):
return false;
default:
return true;
}
case Kwd(KwdSwitch), Kwd(KwdCase), Kwd(KwdDefault):
return true;
case Kwd(KwdThrow):
return true;
default:
}
return false;
}

#if debugIndent
function logIndentStart() {
var file:FileOutput = File.append("hxformat.log", false);
file.writeString("\n".lpad("-", 202));
file.close();
}

function log(token:TokenTree, what:String, ?pos:PosInfos) {
var text:String = '`${token}` - $what - ${pos.fileName}:${pos.lineNumber}';
var tokenText:String = '`$token` (${token.pos.min})';
var text:String = '${tokenText.rpad(" ", 50)} ${what.rpad(" ", 90)}';
var file:FileOutput = File.append("hxformat.log", false);
file.writeString(text + "\n");
file.close();
Expand Down
6 changes: 0 additions & 6 deletions src/formatter/marker/MarkLineEnds.hx
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,6 @@ class MarkLineEnds extends MarkerBase {
lineEndAfter(token);
continue;
}
var info:TokenInfo = getTokenInfo(token);
if (info == null) {
whitespace(token, Around);
} else {
whitespace(token, Around);
}
default:
}
}
Expand Down
Loading

0 comments on commit c012c94

Please sign in to comment.