package com.sylvanaar.idea.Lua.lang.formatter.processors;
import com.intellij.formatting.Spacing;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.sylvanaar.idea.Lua.LuaFileType;
import com.sylvanaar.idea.Lua.lang.formatter.blocks.LuaFormattingBlock;
import com.sylvanaar.idea.Lua.lang.psi.LuaPsiElement;
import com.sylvanaar.idea.Lua.lang.psi.visitor.LuaElementVisitor;
import static com.sylvanaar.idea.Lua.lang.parser.LuaElementTypes.NEWLINE;
import static com.sylvanaar.idea.Lua.lang.parser.LuaElementTypes.SHORTCOMMENT;
public class LuaSpacingProcessor extends LuaElementVisitor {
private static final ThreadLocal<LuaSpacingProcessor> mySharedProcessorAllocator = new ThreadLocal<LuaSpacingProcessor>();
protected MyLuaSpacingVisitor myLuaElementVisitor;
protected static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.lua.formatter.processors.LuaSpacingProcessor");
private LuaSpacingProcessor(MyLuaSpacingVisitor visitor) {
// super(visitor);
myLuaElementVisitor = visitor;
}
public static Spacing getSpacing(LuaFormattingBlock child1, LuaFormattingBlock child2, CodeStyleSettings settings) {
return getSpacing(child2.getNode(), settings);
}
private static Spacing getSpacing(ASTNode node, CodeStyleSettings settings) {
LuaSpacingProcessor spacingProcessor = mySharedProcessorAllocator.get();
try {
if (spacingProcessor == null) {
spacingProcessor = new LuaSpacingProcessor(new MyLuaSpacingVisitor(node, settings));
mySharedProcessorAllocator.set(spacingProcessor);
} else {
spacingProcessor.setVisitor(new MyLuaSpacingVisitor(node, settings));
}
spacingProcessor.doInit();
return spacingProcessor.getResult();
}
catch (Exception e) {
LOG.error(e);
return null;
}
finally {
spacingProcessor.clear();
}
}
private void doInit() {
myLuaElementVisitor.doInit();
}
private void clear() {
if (myLuaElementVisitor != null) {
myLuaElementVisitor.clear();
}
}
private Spacing getResult() {
return myLuaElementVisitor.getResult();
}
public void setVisitor(MyLuaSpacingVisitor visitor) {
myLuaElementVisitor = visitor;
}
/**
* Visitor to adjust spaces via user Code Style Settings
*/
private static class MyLuaSpacingVisitor extends LuaElementVisitor {
private PsiElement myParent;
private final CodeStyleSettings mySettings;
private Spacing myResult;
private ASTNode myChild1;
private ASTNode myChild2;
public MyLuaSpacingVisitor(ASTNode node, CodeStyleSettings settings) {
mySettings = settings;
init(node);
}
private void init(final ASTNode child) {
if (child == null) return;
ASTNode treePrev = child.getTreePrev();
while (treePrev != null && SpacingUtil.isWhiteSpace(treePrev)) {
treePrev = treePrev.getTreePrev();
}
if (treePrev == null) {
init(child.getTreeParent());
} else {
myChild2 = child;
myChild1 = treePrev;
final CompositeElement parent = (CompositeElement) treePrev.getTreeParent();
myParent = SourceTreeToPsiMap.treeElementToPsi(parent);
}
}
/*
Method to start visiting
*/
private void doInit() {
if (myChild1 == null || myChild2 == null) return;
PsiElement psi1 = myChild1.getPsi();
PsiElement psi2 = myChild2.getPsi();
if (psi1 == null || psi2 == null) return;
if (psi1.getLanguage() != LuaFileType.LUA_LANGUAGE ||
psi2.getLanguage() != LuaFileType.LUA_LANGUAGE) {
return;
}
if (myChild2 != null && mySettings.KEEP_FIRST_COLUMN_COMMENT && SpacingUtil.COMMENT_BIT_SET.contains(myChild2.getElementType())) {
myResult = Spacing.createKeepingFirstColumnSpacing(0, Integer.MAX_VALUE, true, 1);
return;
}
if (myChild1 != null && myChild2 != null && myChild1.getElementType() == NEWLINE) {
final ASTNode prev = SpacingUtil.getPrevElementType(myChild1);
if (prev != null && prev.getElementType() == SHORTCOMMENT) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
return;
}
}
if (myParent instanceof LuaPsiElement) {
((LuaPsiElement) myParent).accept(this);
}
}
// }
// @Override
// public void visitAnnotation(GrAnnotation annotation) {
// if (myChild2.getElementType() == ANNOTATION_ARGUMENTS) {
// myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
//// }
//// }
//
// public void visitArgumentList(GrArgumentList list) {
// if (myChild1.getElementType() == mLBRACK || myChild2.getElementType() == mRBRACK) {
// createSpaceInCode(mySettings.SPACE_WITHIN_BRACKETS);
// }
// // todo add other cases
// }
//
// @Override
// public void visitMethodCallExpression(GrMethodCallExpression methodCallExpression) {
// if (myChild2.getElementType() == ARGUMENTS) createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
// }
//
// public void visitClosure(GrClosableBlock closure) {
// if ((myChild1.getElementType() == mLCURLY && myChild2.getElementType() != PARAMETERS_LIST && myChild2.getElementType() != mCLOSABLE_BLOCK_OP)
// || myChild2.getElementType() == mRCURLY) {
// myResult = Spacing.createDependentLFSpacing(0, Integer.MAX_VALUE, closure.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else if (myChild1.getElementType() == mCLOSABLE_BLOCK_OP) {
// GrStatement[] statements = closure.getStatements();
// if (statements.length > 0) {
// TextRange range = new TextRange(statements[0].getTextRange().getStartOffset(), statements[statements.length - 1].getTextRange().getEndOffset());
// myResult = Spacing.createDependentLFSpacing(1, Integer.MAX_VALUE, range, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// }
// }
//
// public void visitOpenBlock(GrOpenBlock block) {
// if (myChild1.getElementType() == mLCURLY && myChild2.getElementType() == mRCURLY && block.getParent() instanceof GrBlockStatement) {
// myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else
// if (myChild1.getElementType() == mLCURLY && !LuaEditorActionUtil.isMultilineStringElement(myChild2) ||
// myChild2.getElementType() == mRCURLY && !LuaEditorActionUtil.isMultilineStringElement(myChild1)) {
// myResult = Spacing.createDependentLFSpacing(0, 1, block.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// }
//
//// public void visitNewExpression(GrNewExpression newExpression) {
//// if (myChild1.getElementType() == kNEW) {
//// createSpaceInCode(true);
//// } else if (myChild2.getElementType() == ARGUMENTS) {
//// createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
//// }
//// }
//
// public void visitTypeDefinition(GrTypeDefinition typeDefinition) {
// if (myChild2.getElementType() == CLASS_BODY) {
// PsiIdentifier nameIdentifier = typeDefinition.getNameIdentifier();
// int dependanceStart = nameIdentifier == null ? myParent.getTextRange().getStartOffset() : nameIdentifier.getTextRange().getStartOffset();
// myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_CLASS_LBRACE, mySettings.CLASS_BRACE_STYLE,
// new TextRange(dependanceStart, myChild1.getTextRange().getEndOffset()), false);
// }
// }
//
// public void visitTypeDefinitionBody(GrTypeDefinitionBody typeDefinitionBody) {
// if (myChild1.getElementType() == mLCURLY && myChild2.getElementType() == mRCURLY) {
// myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
// } else if (myChild1.getElementType() == mLCURLY) {
// myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_CLASS_HEADER + 1,
// mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
// } else if (myChild2.getElementType() == mRCURLY) {
// myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
// }
// }
//
// public void visitMethod(GrMethod method) {
// if (myChild2.getElementType() == mLPAREN) {
// createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_PARENTHESES);
// } else if (myChild2.getElementType() == mRPAREN && myChild2.getElementType() == THROW_CLAUSE) {
// createSpaceInCode(true);
// } else if (myChild2.getElementType() == OPEN_BLOCK) {
// PsiElement methodName = method.getNameIdentifier();
// int dependancyStart = methodName == null ? myParent.getTextRange().getStartOffset() : methodName.getTextRange().getStartOffset();
// myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_METHOD_LBRACE, mySettings.METHOD_BRACE_STYLE,
// new TextRange(dependancyStart, myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_METHODS_IN_ONE_LINE);
// } else if (myChild1.getElementType() == MODIFIERS) {
// processModifierList(myChild1);
// } else if (COMMENT_SET.contains(myChild1.getElementType())
// && (myChild2.getElementType() == MODIFIERS || myChild2.getElementType() == REFERENCE_ELEMENT)) {
// myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
// }
//
// }
//
// public void visitDocMethodReference(GrDocMethodReference reference) {
// visitDocMember();
// }
//
//
//
//
// public void visitWhileStatement(LuaWhileStatement statement) {
// if (myChild2.getElementType() == LPAREN) {
// createSpaceInCode(mySettings.SPACE_BEFORE_WHILE_PARENTHESES);
// } else if (myChild1.getElementType() == LPAREN || myChild2.getElementType() == RPAREN) {
// createSpaceInCode(mySettings.SPACE_WITHIN_WHILE_PARENTHESES);
// } else if (myChild2.getPsi() instanceof GrBlockStatement) {
// myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_WHILE_LBRACE, mySettings.BRACE_STYLE,
// new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE);
// } else {
// createSpacingBeforeElementInsideControlStatement();
// }
// }
//
//
//
//
//
// public void visitIfStatement(GrIfStatement ifStatement) {
// if (myChild2.getElementType() == kELSE) {
// if (myChild1.getElementType() != OPEN_BLOCK && myChild1.getElementType() != BLOCK_STATEMENT) {
// myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// if (mySettings.ELSE_ON_NEW_LINE) {
// myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// createSpaceProperty(true, false, 0);
// }
// }
// } else if (myChild1.getElementType() == kELSE) {
// if (myChild2.getElementType() == IF_STATEMENT) {
// if (mySettings.SPECIAL_ELSE_IF_TREATMENT) {
// createSpaceProperty(true, false, 0);
// } else {
// myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// } else {
// if (myChild2.getElementType() == BLOCK_STATEMENT || myChild2.getElementType() == OPEN_BLOCK) {
// myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_ELSE_LBRACE, mySettings.BRACE_STYLE,
// null,
// mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE);
// } else {
// createSpacingBeforeElementInsideControlStatement();
// }
// }
// } else if (myChild2.getElementType() == BLOCK_STATEMENT || myChild2.getElementType() == OPEN_BLOCK) {
// boolean space = myChild2.getPsi() == ((GrIfStatement) myParent).getElseBranch() ? mySettings.SPACE_BEFORE_ELSE_LBRACE : mySettings.SPACE_BEFORE_IF_LBRACE;
// myResult = getSpaceBeforeLBrace(space, mySettings.BRACE_STYLE, new TextRange(myParent.getTextRange().getStartOffset(),
// myChild1.getTextRange().getEndOffset()),
// mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE);
// } else if (myChild2.getElementType() == mLPAREN) {
// createSpaceInCode(mySettings.SPACE_BEFORE_IF_PARENTHESES);
// } else if (myChild1.getElementType() == mLPAREN) {
// createSpaceInCode(mySettings.SPACE_WITHIN_IF_PARENTHESES);
// } else if (myChild2.getElementType() == mRPAREN) {
// createSpaceInCode(mySettings.SPACE_WITHIN_IF_PARENTHESES);
// } else if (((GrIfStatement) myParent).getThenBranch() == myChild2.getPsi()) {
// createSpacingBeforeElementInsideControlStatement();
// }
// }
//
// public void visitForStatement(GrForStatement forStatement) {
// if (myChild2.getElementType() == mLPAREN) {
// createSpaceInCode(mySettings.SPACE_BEFORE_FOR_PARENTHESES);
// } else if (myChild1.getElementType() == mLPAREN) {
// ASTNode rparenth = findFrom(myChild2, mRPAREN, true);
// if (rparenth == null) {
// createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES);
// } else {
// createParenSpace(mySettings.FOR_STATEMENT_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES,
// new TextRange(myChild1.getTextRange().getStartOffset(), rparenth.getTextRange().getEndOffset()));
// }
// } else if (myChild2.getElementType() == mRPAREN) {
// ASTNode lparenth = findFrom(myChild2, mLPAREN, false);
// if (lparenth == null) {
// createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES);
// } else {
// createParenSpace(mySettings.FOR_STATEMENT_RPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES,
// new TextRange(lparenth.getTextRange().getStartOffset(), myChild2.getTextRange().getEndOffset()));
// }
//
// } else if (myChild2.getElementType() == BLOCK_STATEMENT || myChild2.getElementType() == OPEN_BLOCK) {
// if (myChild2.getElementType() == BLOCK_STATEMENT) {
// myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_FOR_LBRACE, mySettings.BRACE_STYLE,
// new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE);
// } else if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE) {
// myResult = Spacing.createDependentLFSpacing(1, 1, myParent.getTextRange(), false, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// myResult = Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// }
// }
//
// private void createParenSpace(final boolean onNewLine, final boolean space) {
// createParenSpace(onNewLine, space, myParent.getTextRange());
// }
//
// private void createParenSpace(final boolean onNewLine, final boolean space, final TextRange dependance) {
// if (onNewLine) {
// final int spaces = space ? 1 : 0;
// myResult = Spacing
// .createDependentLFSpacing(spaces, spaces, dependance, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// createSpaceInCode(space);
// }
// }
//
//
// private static ASTNode findFrom(ASTNode current, final IElementType expected, boolean forward) {
// while (current != null) {
// if (current.getElementType() == expected) return current;
// current = forward ? current.getTreeNext() : current.getTreePrev();
// }
// return null;
// }
//
//
// private void processOnNewLineCondition(final boolean onNewLine) {
// if (onNewLine) {
// if (!mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE) {
// myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// myResult = Spacing.createDependentLFSpacing(0, 1, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// } else {
// createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// }
//
//
// private void createSpacingBeforeElementInsideControlStatement() {
// if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE && myChild1.getElementType() != mSL_COMMENT) {
// createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// }
//
//
// private void processModifierList(ASTNode modifierList) {
// if (modifierList.getLastChildNode().getElementType() == ANNOTATION && mySettings.METHOD_ANNOTATION_WRAP == CodeStyleSettings.WRAP_ALWAYS) {
// myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// else if (mySettings.MODIFIER_LIST_WRAP) {
// myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// else {
// createSpaceProperty(true, false, 0);
// }
// }
//
//
protected void clear() {
myResult = null;
myChild2 = myChild1 = null;
myParent = null;
}
protected Spacing getResult() {
final Spacing result = myResult;
clear();
return result;
}
//
// private void createSpaceInCode(final boolean space) {
// createSpaceProperty(space, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
//
// private void createSpaceProperty(boolean space, int keepBlankLines) {
// createSpaceProperty(space, mySettings.KEEP_LINE_BREAKS, keepBlankLines);
// }
//
// private void createSpaceProperty(boolean space, boolean keepLineBreaks, final int keepBlankLines) {
// final ASTNode prev = SpacingUtil.getPrevElementType(myChild2);
// if (prev != null && prev.getElementType() == mSL_COMMENT) {
// myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// myResult = Spacing.createSpacing(space ? 1 : 0, space ? 1 : 0, 0, keepLineBreaks, keepBlankLines);
// }
// }
//
// private Spacing getSpaceBeforeLBrace(final boolean spaceBeforeLbrace, int braceStyle, TextRange dependantRange, boolean keepOneLine) {
// if (dependantRange != null && braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED) {
// int space = spaceBeforeLbrace ? 1 : 0;
// return createNonLFSpace(space, dependantRange, false);
// } else if (braceStyle == CodeStyleSettings.END_OF_LINE || braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED) {
// int space = spaceBeforeLbrace ? 1 : 0;
// return createNonLFSpace(space, null, false);
// } else if (keepOneLine) {
// int space = spaceBeforeLbrace ? 1 : 0;
// return Spacing.createDependentLFSpacing(space, space, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// return Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// }
//
// private Spacing createNonLFSpace(int spaces, final TextRange dependantRange, final boolean keepLineBreaks) {
// final ASTNode prev = SpacingUtil.getPrevElementType(myChild2);
// if (prev != null && prev.getElementType() == mSL_COMMENT) {
// return Spacing.createSpacing(0, Integer.MAX_VALUE, 1, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else if (dependantRange != null) {
// return Spacing.createDependentLFSpacing(spaces, spaces, dependantRange, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE);
// } else {
// return Spacing.createSpacing(spaces, spaces, 0, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE);
// }
// }
//
//
}
}