/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2014-2014 AS3Boyan
* Copyright 2014-2014 Elias Ku
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.plugins.haxe.ide.formatter;
import com.intellij.formatting.Block;
import com.intellij.formatting.Spacing;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.plugins.haxe.ide.formatter.settings.HaxeCodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.formatter.common.AbstractBlock;
import com.intellij.psi.tree.IElementType;
import static com.intellij.plugins.haxe.lang.lexer.HaxeTokenTypeSets.*;
import static com.intellij.plugins.haxe.lang.lexer.HaxeTokenTypes.*;
/**
* @author: Fedor.Korotkov
*/
public class HaxeSpacingProcessor {
private final ASTNode myNode;
private final CommonCodeStyleSettings mySettings;
private final HaxeCodeStyleSettings myHaxeCodeStyleSettings;
public HaxeSpacingProcessor(ASTNode node, CommonCodeStyleSettings settings, HaxeCodeStyleSettings haxeCodeStyleSettings) {
myNode = node;
mySettings = settings;
myHaxeCodeStyleSettings = haxeCodeStyleSettings;
}
public Spacing getSpacing(Block child1, Block child2) {
if (!(child1 instanceof AbstractBlock) || !(child2 instanceof AbstractBlock)) {
return null;
}
final IElementType elementType = myNode.getElementType();
final IElementType parentType = myNode.getTreeParent() == null ? null : myNode.getTreeParent().getElementType();
final ASTNode node1 = ((AbstractBlock)child1).getNode();
final IElementType type1 = node1.getElementType();
final ASTNode node2 = ((AbstractBlock)child2).getNode();
final IElementType type2 = node2.getElementType();
final ASTNode nodeNode1 = node1 == null ? null : node1.getFirstChildNode();
final IElementType typeType1 = nodeNode1 == null ? null : nodeNode1.getElementType();
final ASTNode nodeNode2 = node2 == null ? null : node2.getFirstChildNode();
final IElementType typeType2 = nodeNode2 == null ? null : nodeNode2.getElementType();
if (type1 == IMPORT_STATEMENT_REGULAR ||
type1 == IMPORT_STATEMENT_WITH_IN_SUPPORT ||
type1 == IMPORT_STATEMENT_WITH_WILDCARD ||
type1 == PACKAGE_STATEMENT ||
type1 == USING_STATEMENT) {
return addSingleSpaceIf(false, true);
}
if (elementType.equals(WILDCARD)) {
return addSingleSpaceIf(false);
}
if (type1 == CLASS_BODY || type1 == EXTERN_CLASS_DECLARATION_BODY || type1 == ENUM_BODY || type1 == INTERFACE_BODY) {
return Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
if (type2 == FUNCTION_DECLARATION_WITH_ATTRIBUTES) {
return Spacing.createSpacing(0, 0, 2, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
if (type2 == PLPAREN) {
if (elementType == IF_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_IF_PARENTHESES);
}
else if (elementType == WHILE_STATEMENT || elementType == DO_WHILE_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_WHILE_PARENTHESES);
}
else if (elementType == FOR_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_FOR_PARENTHESES);
}
else if (elementType == SWITCH_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_SWITCH_PARENTHESES);
}
else if (elementType == TRY_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_TRY_PARENTHESES);
}
else if (elementType == CATCH_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_CATCH_PARENTHESES);
}
else if (FUNCTION_DEFINITION.contains(elementType)) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_METHOD_PARENTHESES);
}
else if (elementType == CALL_EXPRESSION) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
}
}
if (type1 == OGREATER && type2 == OASSIGN) {
return addSingleSpaceIf(false);
}
//
//Spacing before left braces
//
if (type2 == BLOCK_STATEMENT) {
if (elementType == IF_STATEMENT && type1 != KELSE) {
return setBraceSpace(mySettings.SPACE_BEFORE_IF_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
else if (elementType == IF_STATEMENT && type1 == KELSE) {
return setBraceSpace(mySettings.SPACE_BEFORE_ELSE_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
else if (elementType == WHILE_STATEMENT || elementType == DO_WHILE_STATEMENT) {
return setBraceSpace(mySettings.SPACE_BEFORE_WHILE_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
else if (elementType == FOR_STATEMENT) {
return setBraceSpace(mySettings.SPACE_BEFORE_FOR_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
else if (elementType == SWITCH_STATEMENT) {
return setBraceSpace(mySettings.SPACE_BEFORE_SWITCH_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
else if (elementType == TRY_STATEMENT) {
return setBraceSpace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
else if (elementType == CATCH_STATEMENT) {
return setBraceSpace(mySettings.SPACE_BEFORE_CATCH_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
else if (FUNCTION_DEFINITION.contains(elementType)) {
return setBraceSpace(mySettings.SPACE_BEFORE_METHOD_LBRACE, mySettings.METHOD_BRACE_STYLE, child1.getTextRange());
}
}
if ((elementType == CLASS_DECLARATION || elementType == ENUM_DECLARATION || elementType == INTERFACE_DECLARATION) &&
type2 == PLCURLY) {
return setBraceSpace(mySettings.SPACE_BEFORE_CLASS_LBRACE, mySettings.BRACE_STYLE, child1.getTextRange());
}
if (type1 == PLPAREN || type2 == PRPAREN) {
if (elementType == IF_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_WITHIN_IF_PARENTHESES);
}
else if (elementType == WHILE_STATEMENT || elementType == DO_WHILE_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_WITHIN_WHILE_PARENTHESES);
}
else if (elementType == FOR_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_WITHIN_FOR_PARENTHESES);
}
else if (elementType == SWITCH_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_WITHIN_SWITCH_PARENTHESES);
}
else if (elementType == TRY_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_WITHIN_TRY_PARENTHESES);
}
else if (elementType == CATCH_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_WITHIN_CATCH_PARENTHESES);
}
else if (FUNCTION_DEFINITION.contains(elementType)) {
final boolean newLineNeeded = type1 == PLPAREN ?
mySettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE :
mySettings.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE;
return addSingleSpaceIf(mySettings.SPACE_WITHIN_METHOD_PARENTHESES, newLineNeeded);
}
else if (elementType == CALL_EXPRESSION) {
final boolean newLineNeeded = type1 == PLPAREN ?
mySettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE :
mySettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE;
return addSingleSpaceIf(mySettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES, newLineNeeded);
}
else if (mySettings.BINARY_OPERATION_WRAP != CommonCodeStyleSettings.DO_NOT_WRAP && elementType == PARENTHESIZED_EXPRESSION) {
final boolean newLineNeeded = type1 == PLPAREN ?
mySettings.PARENTHESES_EXPRESSION_LPAREN_WRAP :
mySettings.PARENTHESES_EXPRESSION_RPAREN_WRAP;
return addSingleSpaceIf(false, newLineNeeded);
}
}
if (elementType == TERNARY_EXPRESSION) {
if (type2 == OQUEST) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_QUEST);
}
else if (type2 == OCOLON) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_COLON);
}
else if (type1 == OQUEST) {
return addSingleSpaceIf(mySettings.SPACE_AFTER_QUEST);
}
else if (type1 == OCOLON) {
return addSingleSpaceIf(mySettings.SPACE_AFTER_COLON);
}
}
//
// Spacing around assignment operators (=, -=, etc.)
//
if (ASSIGN_OPERATORS.contains(type1) || ASSIGN_OPERATORS.contains(type2) ||
type2 == VAR_INIT) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_ASSIGNMENT_OPERATORS);
}
//
// Spacing around logical operators (&&, OR, etc.)
//
if (LOGIC_OPERATORS.contains(type1) || LOGIC_OPERATORS.contains(type2)) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_LOGICAL_OPERATORS);
}
//
// Spacing around equality operators (==, != etc.)
//
if ((type1 == COMPARE_OPERATION && EQUALITY_OPERATORS.contains(typeType1)) ||
(type2 == COMPARE_OPERATION && EQUALITY_OPERATORS.contains(typeType2))) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_EQUALITY_OPERATORS);
}
//
// Spacing around relational operators (<, <= etc.)
//
if ((type1 == COMPARE_OPERATION && RELATIONAL_OPERATORS.contains(typeType1)) ||
(type2 == COMPARE_OPERATION && RELATIONAL_OPERATORS.contains(typeType2))) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_RELATIONAL_OPERATORS);
}
//
// Spacing around additive operators ( &, |, ^, etc.)
//
if (BITWISE_OPERATORS.contains(type1) || BITWISE_OPERATORS.contains(type2)) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_BITWISE_OPERATORS);
}
//
// Spacing around additive operators ( +, -, etc.)
//
if ((ADDITIVE_OPERATORS.contains(type1) || ADDITIVE_OPERATORS.contains(type2)) &&
elementType != PREFIX_EXPRESSION) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_ADDITIVE_OPERATORS);
}
//
// Spacing around multiplicative operators ( *, /, %, etc.)
//
if ((MULTIPLICATIVE_OPERATORS.contains(type1) || MULTIPLICATIVE_OPERATORS.contains(type2))) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS);
}
//
// Spacing around unary operators ( NOT, ++, etc.)
//
if ((UNARY_OPERATORS.contains(type1) || UNARY_OPERATORS.contains(type2)) &&
elementType == PREFIX_EXPRESSION) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_UNARY_OPERATOR);
}
//
// Spacing around shift operators ( <<, >>, >>>, etc.)
//
if (SHIFT_OPERATORS.contains(type1) || SHIFT_OPERATORS.contains(type2)) {
return addSingleSpaceIf(mySettings.SPACE_AROUND_SHIFT_OPERATORS);
}
//
//Spacing before keyword (else, catch, etc)
//
if (type2 == KELSE) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_ELSE_KEYWORD, mySettings.ELSE_ON_NEW_LINE);
}
if (type2 == KWHILE) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_WHILE_KEYWORD, mySettings.WHILE_ON_NEW_LINE);
}
if (type2 == CATCH_STATEMENT) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_CATCH_KEYWORD, mySettings.CATCH_ON_NEW_LINE);
}
//
//Other
//
if (type1 == KELSE && type2 == IF_STATEMENT) {
return Spacing.createSpacing(1, 1, mySettings.SPECIAL_ELSE_IF_TREATMENT ? 0 : 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
if (type1 == OCOMMA && (elementType == PARAMETER_LIST || elementType == EXPRESSION_LIST) &&
(parentType == CALL_EXPRESSION ||
parentType == NEW_EXPRESSION ||
FUNCTION_DEFINITION.contains(parentType))) {
return addSingleSpaceIf(mySettings.SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS);
}
if (type1 == OCOMMA) {
return addSingleSpaceIf(mySettings.SPACE_AFTER_COMMA);
}
if (type2 == OCOMMA) {
return addSingleSpaceIf(mySettings.SPACE_BEFORE_COMMA);
}
if (type1 == OCOLON && elementType == TYPE_TAG) {
return addSingleSpaceIf(myHaxeCodeStyleSettings.SPACE_AFTER_TYPE_REFERENCE_COLON);
}
if (type2 == TYPE_TAG) {
return addSingleSpaceIf(myHaxeCodeStyleSettings.SPACE_BEFORE_TYPE_REFERENCE_COLON);
}
if (type1 == OARROW || type2 == OARROW) {
return addSingleSpaceIf(myHaxeCodeStyleSettings.SPACE_AROUND_ARROW);
}
if (type1 == FUNCTION_PROTOTYPE_DECLARATION_WITH_ATTRIBUTES && type2 == FUNCTION_PROTOTYPE_DECLARATION_WITH_ATTRIBUTES) {
return Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AROUND_METHOD, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
if (type1 == PLCURLY && (type2 == INTERFACE_BODY || type2 == CLASS_BODY || type2 == ENUM_BODY || type2 == ABSTRACT_CLASS_DECLARATION)) {
return Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_BEFORE_METHOD_BODY, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
if (type1 == FUNCTION_PROTOTYPE_DECLARATION_WITH_ATTRIBUTES && type2 == PRCURLY) {
return Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AROUND_METHOD, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
return Spacing.createSpacing(0, 1, 0, true, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
private Spacing addSingleSpaceIf(boolean condition) {
return addSingleSpaceIf(condition, false);
}
private Spacing addSingleSpaceIf(boolean condition, boolean linesFeed) {
final int spaces = condition ? 1 : 0;
final int lines = linesFeed ? 1 : 0;
return Spacing.createSpacing(spaces, spaces, lines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
private Spacing setBraceSpace(boolean needSpaceSetting,
@CommonCodeStyleSettings.BraceStyleConstant int braceStyleSetting,
TextRange textRange) {
final int spaces = needSpaceSetting ? 1 : 0;
if (braceStyleSetting == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED && textRange != null) {
return Spacing.createDependentLFSpacing(spaces, spaces, textRange, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
final int lineBreaks = braceStyleSetting == CommonCodeStyleSettings.END_OF_LINE ||
braceStyleSetting == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED ? 0 : 1;
return Spacing.createSpacing(spaces, spaces, lineBreaks, false, 0);
}
}
}