/* * Copyright 2000-2009 JetBrains s.r.o. * * 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.sylvanaar.idea.Lua.lang.formatter.blocks; import com.intellij.formatting.Alignment; import com.intellij.formatting.Block; import com.intellij.formatting.Indent; import com.intellij.formatting.Wrap; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; 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.templateLanguages.OuterLanguageElement; import com.sylvanaar.idea.Lua.LuaFileType; import com.sylvanaar.idea.Lua.lang.formatter.processors.LuaIndentProcessor; import com.sylvanaar.idea.Lua.lang.parser.LuaElementTypes; import com.sylvanaar.idea.Lua.lang.psi.LuaPsiFileBase; import com.sylvanaar.idea.Lua.lang.psi.expressions.LuaBinaryExpression; import java.util.ArrayList; import java.util.List; /** * Utility class to generate myBlock hierarchy * * @author ilyas */ public class LuaBlockGenerator implements LuaElementTypes { public static final Logger LOG = Logger.getInstance("Lua.LuaBlockGenerator"); // private static final TokenSet NESTED = TokenSet.create(REFERENCE_EXPRESSION, // PATH_INDEX_PROPERTY, // PATH_METHOD_CALL, // PATH_PROPERTY_REFERENCE); static int level = 0; public static List<Block> generateSubBlocks(ASTNode node, Alignment myAlignment, Wrap myWrap, CodeStyleSettings mySettings, LuaFormattingBlock formattingBlock) { // //For binary expressions PsiElement blockPsi = formattingBlock.getNode().getPsi(); if (blockPsi instanceof LuaBinaryExpression && !(blockPsi.getParent() instanceof LuaBinaryExpression)) { return generateForBinaryExpr(node, myWrap, mySettings); } // LOG.info(">> parent: " + blockPsi + ": " + node); // For other cases final ArrayList<Block> subBlocks = new ArrayList<Block>(); ASTNode[] children = getLuaChildren(node); ASTNode prevChildNode = null; for (ASTNode childNode : children) { if (canBeCorrectBlock(childNode)) { final Indent indent = LuaIndentProcessor.getChildIndent(formattingBlock, prevChildNode, childNode); // LOG.info("" + level + " child: " + childNode + "indent " + indent); level++; subBlocks.add( new LuaFormattingBlock(childNode, blockPsi instanceof LuaFormattingBlock ? null : myAlignment, indent, myWrap, mySettings)); --level; prevChildNode = childNode; } } // LOG.info("<< parent: " + blockPsi+ ": " + node); return subBlocks; } /** * @param node Tree node * @return true, if the current node can be myBlock node, else otherwise */ private static boolean canBeCorrectBlock(final ASTNode node) { return (node.getText().trim().length() > 0); } private static ASTNode[] getLuaChildren(final ASTNode node) { PsiElement psi = node.getPsi(); if (psi instanceof OuterLanguageElement) { TextRange range = node.getTextRange(); ArrayList<ASTNode> childList = new ArrayList<ASTNode>(); PsiFile LuaFile = psi.getContainingFile().getViewProvider().getPsi(LuaFileType.LUA_LANGUAGE); if (LuaFile instanceof LuaPsiFileBase) { addChildNodes(LuaFile, childList, range); } return childList.toArray(new ASTNode[childList.size()]); } return node.getChildren(null); } private static void addChildNodes(PsiElement elem, ArrayList<ASTNode> childNodes, TextRange range) { ASTNode node = elem.getNode(); if (range.contains(elem.getTextRange()) && node != null) { childNodes.add(node); } else { for (PsiElement child : elem.getChildren()) { addChildNodes(child, childNodes, range); } } } /** * Generates blocks for binary expressions * * @param node * @return */ private static List<Block> generateForBinaryExpr(final ASTNode node, Wrap myWrap, CodeStyleSettings mySettings) { final ArrayList<Block> subBlocks = new ArrayList<Block>(); Alignment alignment = mySettings.ALIGN_MULTILINE_BINARY_OPERATION ? Alignment.createAlignment() : null; LuaBinaryExpression myExpr = (LuaBinaryExpression) node.getPsi(); ASTNode[] children = node.getChildren(null); if (myExpr.getLeftExpression() instanceof LuaBinaryExpression) { addBinaryChildrenRecursively(myExpr.getLeftExpression(), subBlocks, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings); } for (ASTNode childNode : children) { if (canBeCorrectBlock(childNode) && !(childNode.getPsi() instanceof LuaBinaryExpression)) { subBlocks.add(new LuaFormattingBlock(childNode, alignment, Indent.getContinuationWithoutFirstIndent(), myWrap, mySettings)); } } if (myExpr.getRightExpression() instanceof LuaBinaryExpression) { addBinaryChildrenRecursively(myExpr.getRightExpression(), subBlocks, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings); } return subBlocks; } /** * Adds all children of specified element to given list * * @param elem * @param list * @param indent * @param alignment */ private static void addBinaryChildrenRecursively(PsiElement elem, List<Block> list, Indent indent, Alignment alignment, Wrap myWrap, CodeStyleSettings mySettings) { if (elem == null) return; ASTNode[] children = elem.getNode().getChildren(null); // For binary expressions if ((elem instanceof LuaBinaryExpression)) { LuaBinaryExpression myExpr = ((LuaBinaryExpression) elem); if (myExpr.getLeftExpression() instanceof LuaBinaryExpression) { addBinaryChildrenRecursively(myExpr.getLeftExpression(), list, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings); } for (ASTNode childNode : children) { if (canBeCorrectBlock(childNode) && !(childNode.getPsi() instanceof LuaBinaryExpression)) { list.add(new LuaFormattingBlock(childNode, alignment, indent, myWrap, mySettings)); } } if (myExpr.getRightExpression() instanceof LuaBinaryExpression) { addBinaryChildrenRecursively(myExpr.getRightExpression(), list, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings); } } } /** * Generates blocks for nested expressions like a.b.c etc. * * @param node * @return */ private static List<Block> generateForNestedExpr(final ASTNode node, Alignment myAlignment, Wrap myWrap, CodeStyleSettings mySettings) { final ArrayList<Block> subBlocks = new ArrayList<Block>(); ASTNode children[] = node.getChildren(null); if (children.length > 0 && false /* NESTED.contains(children[0].getElementType()) */) { addNestedChildrenRecursively(children[0].getPsi(), subBlocks, myAlignment, myWrap, mySettings); } else if (canBeCorrectBlock(children[0])) { subBlocks.add(new LuaFormattingBlock(children[0], myAlignment, Indent.getContinuationWithoutFirstIndent(), myWrap, mySettings)); } if (children.length > 1) { for (ASTNode childNode : children) { if (canBeCorrectBlock(childNode) && children[0] != childNode) { subBlocks.add(new LuaFormattingBlock(childNode, myAlignment, Indent.getContinuationWithoutFirstIndent(), myWrap, mySettings)); } } } return subBlocks; } /** * Adds nested children for paths * * @param elem * @param list * @param myAlignment * @param mySettings */ private static void addNestedChildrenRecursively(PsiElement elem, List<Block> list, Alignment myAlignment, Wrap myWrap, CodeStyleSettings mySettings) { ASTNode[] children = elem.getNode().getChildren(null); // For path expressions if (children.length > 0) { addNestedChildrenRecursively(children[0].getPsi(), list, myAlignment, myWrap, mySettings); } else if (canBeCorrectBlock(children[0])) { list.add(new LuaFormattingBlock(children[0], myAlignment, Indent.getContinuationWithoutFirstIndent(), myWrap, mySettings)); } if (children.length > 1) { for (ASTNode childNode : children) { if (canBeCorrectBlock(childNode) && children[0] != childNode) { if (elem.getNode() != null) { list.add(new LuaFormattingBlock(childNode, myAlignment, Indent.getContinuationWithoutFirstIndent(), myWrap, mySettings)); } else { list.add(new LuaFormattingBlock(childNode, myAlignment, Indent.getNoneIndent(), myWrap, mySettings)); } } } } } }