/*
* Copyright 2013-2017 Grzegorz Ligas <ligasgr@gmail.com> and other contributors
* (see the CONTRIBUTORS file).
*
* 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 org.intellij.xquery.formatter;
import com.intellij.formatting.FormattingModel;
import com.intellij.formatting.FormattingModelBuilder;
import com.intellij.formatting.SpacingBuilder;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.tree.TokenSet;
import org.intellij.xquery.XQueryLanguage;
import org.intellij.xquery.formatter.settings.XQueryCodeStyleSettings;
import org.intellij.xquery.psi.XQueryTypes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.formatting.FormattingModelProvider.createFormattingModelForPsiFile;
import static org.intellij.xquery.psi.XQueryTypes.*;
/**
* User: ligasgr
* Date: 21/08/13
* Time: 19:49
*/
public class XQueryFormattingModelBuilder implements FormattingModelBuilder {
private static final TokenSet KEYWORDS = TokenSet.create(K_NAMESPACE, K_DEFAULT, K_IMPORT, K_DECLARE, K_SCHEMA,
K_AT, K_COLLATION, K_ELEMENT, K_FUNCTION, K_TEXT, K_COMMENT, K_NODE, K_PI, K_IF, K_THEN, K_ELSE,
K_TYPESWITCH, K_SWITCH, K_VALIDATE, K_CONTEXT, K_MODULE, K_INHERIT, K_NO_INHERIT, K_PRESERVE,
K_NO_PRESERVE, K_BASE_URI, K_XQUERY, K_VERSION, K_ENCODING, K_OPTION, K_STRIP, K_SOME, K_IN, K_AS, K_LET,
K_RETURN, K_AND, K_OR, K_CASE, K_FOR, K_VARIABLE, K_COPY_NAMESPACES, K_CONSTRUCTION, K_ORDER, K_EVERY,
K_BOUNDARY_SPACE, K_ORDERING, K_ORDERED, K_UNORDERED, K_EMPTY, K_GREATEST, K_LEAST, K_DECIMAL_FORMAT,
K_DECIMAL_SEPARATOR, K_GROUPING_SEPARATOR, K_INFINITY, K_MINUS_SIGN, K_NAN, K_PERCENT, K_PER_MILLE,
K_ZERO_DIGIT, K_DIGIT, K_PATTERN_SEPARATOR, K_ITEM, K_TO, K_WHERE, K_GROUP, K_BY, K_ALLOWING,
K_ASCENDING, K_DESCENDING, K_INSTANCE, K_OF, K_SATISFIES, K_MAP, K_ATTRIBUTE, K_DOCUMENT_NODE,
K_EMPTY_SEQUENCE, K_NAMESPACE_NODE, K_SCHEMA_ATTRIBUTE, K_SCHEMA_ELEMENT, K_DOCUMENT, K_STABLE, K_CHILD,
K_DESCENDANT, K_SELF, K_DESCENDANT_OR_SELF, K_FOLLOWING_SIBLING, K_FOLLOWING, K_PARENT, K_ANCESTOR,
K_PRECEDING_SIBLING, K_PRECEDING, K_ANCESTOR_OR_SELF, K_TUMBLING, K_SLIDING, K_WINDOW, K_START, K_WHEN,
K_ONLY, K_END, K_PREVIOUS, K_NEXT, K_COUNT, K_TRY, K_CATCH, K_DIV, K_IDIV, K_MOD, K_UNION, K_INTERSECT,
K_EXCEPT, K_TREAT, K_CASTABLE, K_CAST, K_IS, K_TYPE, K_LAX, K_STRICT, K_EXTERNAL, K_EXPONENT_SEPARATOR,
K_ARRAY);
@NotNull
@Override
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(XQueryLanguage.INSTANCE);
XQueryCodeStyleSettings xQuerySettings = settings.getCustomSettings(XQueryCodeStyleSettings.class);
final XQueryFormattingBlock block = new XQueryFormattingBlock(element.getNode(), null, null, commonSettings,
createSpacingBuilder(commonSettings, xQuerySettings, settings));
FormattingModel result = createFormattingModelForPsiFile(element.getContainingFile(), block, settings);
return result;
}
private static SpacingBuilder createSpacingBuilder(CommonCodeStyleSettings settings,
XQueryCodeStyleSettings xQuerySettings,
CodeStyleSettings codeStyleSettings) {
return new SpacingBuilder(codeStyleSettings, XQueryLanguage.INSTANCE)
.before(SEPARATOR).none()
.around(EQUALITY_COMP).spaceIf(settings.SPACE_AROUND_EQUALITY_OPERATORS)
.aroundInside(EQUAL, MODULE_DECL).spaceIf(xQuerySettings.SPACE_AROUND_ASSIGNMENT_IN_PROLOG)
.aroundInside(EQUAL, SCHEMA_IMPORT).spaceIf(xQuerySettings.SPACE_AROUND_ASSIGNMENT_IN_PROLOG)
.aroundInside(EQUAL, MODULE_IMPORT).spaceIf(xQuerySettings.SPACE_AROUND_ASSIGNMENT_IN_PROLOG)
.aroundInside(EQUAL, DECIMAL_FORMAT_DECL).spaceIf(xQuerySettings.SPACE_AROUND_ASSIGNMENT_IN_PROLOG)
.aroundInside(EQUAL, NAMESPACE_DECL).spaceIf(xQuerySettings.SPACE_AROUND_ASSIGNMENT_IN_PROLOG)
.aroundInside(ATTREQUAL, DIR_ATTRIBUTE).spaceIf(xQuerySettings
.SPACE_AROUND_ASSIGNMENT_IN_XML_ATTRIBUTE)
.around(RELATIONAL_COMP).spaceIf(settings.SPACE_AROUND_RELATIONAL_OPERATORS)
.afterInside(OP_PLUS, UNARY_EXPR).spaceIf(settings.SPACE_AROUND_UNARY_OPERATOR)
.afterInside(OP_MINUS, UNARY_EXPR).spaceIf(settings.SPACE_AROUND_UNARY_OPERATOR)
.around(ADDITIVE_OPERATOR).spaceIf(settings.SPACE_AROUND_ADDITIVE_OPERATORS)
.around(COLON_COLON).spaceIf(xQuerySettings.SPACE_AROUND_AXIS_OPERATOR)
.around(MULTIPLICATIVE_OPERATOR).spaceIf(settings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS)
.around(OP_ASSIGN).spaceIf(settings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
.around(EQUAL).spaceIf(settings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
.aroundInside(COLON, MAP_CONSTRUCTOR_ENTRY).spaceIf(settings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
.beforeInside(L_PAR, IF_EXPR).spaceIf(settings.SPACE_BEFORE_IF_PARENTHESES)
.beforeInside(L_PAR, SWITCH_EXPR).spaceIf(settings.SPACE_BEFORE_SWITCH_PARENTHESES)
.beforeInside(L_PAR, TYPESWITCH_EXPR).spaceIf(xQuerySettings.SPACE_BEFORE_TYPESWITCH_PARENTHESES)
.beforeInside(L_PAR, SEQUENCE_TYPE).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, GENERAL_ITEM_TYPE).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, ANY_KIND_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, DOCUMENT_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, TEXT_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, COMMENT_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, NAMESPACE_NODE_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, PI_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, ATTRIBUTE_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, SCHEMA_ATTRIBUTE_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, ELEMENT_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, MAP_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, SCHEMA_ELEMENT_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, ANY_FUNCTION_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.beforeInside(L_PAR, TYPED_FUNCTION_TEST).spaceIf(xQuerySettings.SPACE_BEFORE_TYPE_TEST_PARENTHESES)
.before(PARAM_LIST).spaceIf(xQuerySettings.SPACE_BEFORE_FUNCTION_DECLARATION_PARENTHESES)
.beforeInside(ARGUMENT_LIST, FUNCTION_CALL).spaceIf(xQuerySettings
.SPACE_BEFORE_FUNCTION_CALL_PARENTHESES)
.before(COMMA).spaceIf(settings.SPACE_BEFORE_COMMA)
.after(COMMA).spaceIf(settings.SPACE_AFTER_COMMA)
.around(KEYWORDS).spaces(1)
.around(VERSION_DECL).spaces(1)
.around(MODULE_DECL).spaces(1)
.around(DEFAULT_FUNCTION_NAMESPACE_DECL).spaces(1)
.around(DEFAULT_ELEMENT_NAMESPACE_DECL).spaces(1)
.around(BOUNDARY_SPACE_DECL).spaces(1)
.around(DEFAULT_COLLATION_DECL).spaces(1)
.around(BASE_URI_DECL).spaces(1)
.around(CONSTRUCTION_DECL).spaces(1)
.around(ORDERING_MODE_DECL).spaces(1)
.around(EMPTY_ORDER_DECL).spaces(1)
.around(COPY_NAMESPACES_DECL).spaces(1)
.around(DECIMAL_FORMAT_DECL).spaces(1)
.around(NAMESPACE_DECL).spaces(1)
.around(MODULE_IMPORT).spaces(1)
.around(SCHEMA_IMPORT).spaces(1)
.around(OPTION_DECL).spaces(1)
.around(VAR_DECL).spaces(1)
.around(FUNCTION_DECL).spaces(1)
.around(FOR_CLAUSE).spaces(1)
.around(WINDOW_CLAUSE).spaces(1)
.around(LET_CLAUSE).spaces(1)
.around(WHERE_CLAUSE).spaces(1)
.around(GROUP_BY_CLAUSE).spaces(1)
.around(ORDER_BY_CLAUSE).spaces(1)
.around(COUNT_CLAUSE).spaces(1)
.around(RETURN_CLAUSE).spaces(1)
.around(SWITCH_CASE_CLAUSE).spaces(1)
.around(SWITCH_RETURN_CLAUSE).spaces(1)
.around(SWITCH_DEFAULT_RETURN_CLAUSE).spaces(1)
.around(CASE_CLAUSE).spaces(1)
.around(TYPESWITCH_DEFAULT_RETURN_CLAUSE).spaces(1)
.around(TYPE_DECLARATION).spaces(1)
.around(TRY_CLAUSE).spaces(1)
.around(CATCH_CLAUSE).spaces(1)
.around(TO_OPERATOR).spaces(1)
.around(AND_OPERATOR).spaces(1)
.around(OR_OPERATOR).spaces(1)
.around(UNION_OPERATOR).spaces(1)
.around(CONCAT_OPERATOR).spaces(1)
.around(INTERSECT_EXCEPT_OPERATOR).spaces(1)
.around(INSTANCE_OF_OPERATOR).spaces(1)
.around(TREAT_OPERATOR).spaces(1)
.around(CASTABLE_OPERATOR).spaces(1)
.around(CAST_OPERATOR).spaces(1)
.around(NODE_COMP).spaces(1)
.around(VALUE_COMP).spaces(1)
.around(CATCH_CLAUSE_EXPRESSION).spaces(1)
.after(L_BRACKET).none()
.before(R_BRACKET).none()
.after(L_C_BRACE).none()
.before(L_C_BRACE).spaces(1)
.before(R_C_BRACE).none()
.after(R_C_BRACE).spaces(1)
.before(ARGUMENT_LIST).none()
.before(ARGUMENT).none()
.after(ARGUMENT).none()
.before(PARAM).none()
.after(PARAM).none()
.after(EXPR).none()
;
}
@Nullable
@Override
public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) {
return null;
}
}