1 /* 2 * Copyright 2000-2005 JetBrains s.r.o. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.intellij.lang.javascript.formatter.blocks; 17 18 import com.intellij.formatting.*; 19 import com.intellij.lang.ASTNode; 20 import com.intellij.lang.javascript.JSElementTypes; 21 import com.intellij.lang.javascript.JSTokenTypes; 22 import com.intellij.lang.javascript.formatter.JSSpacingProcessor; 23 import com.intellij.openapi.util.TextRange; 24 import com.intellij.psi.PsiErrorElement; 25 import com.intellij.psi.PsiWhiteSpace; 26 import com.intellij.psi.codeStyle.CodeStyleSettings; 27 import org.jetbrains.annotations.NotNull; 28 import org.jetbrains.annotations.Nullable; 29 30 import java.util.List; 31 32 /** 33 * @author ven 34 */ 35 public class JSBlock implements Block { 36 private ASTNode myNode; 37 38 private final CodeStyleSettings mySettings; 39 40 private Alignment myAlignment; 41 private Indent myIndent; 42 private Wrap myWrap; 43 private List<Block> mySubBlocks = null; 44 45 public JSBlock(final ASTNode node, final Alignment alignment, final Indent indent, final Wrap wrap, final CodeStyleSettings settings) { 46 myAlignment = alignment; 47 myIndent = indent; 48 myNode = node; 49 myWrap = wrap; 50 mySettings = settings; 51 } 52 53 public ASTNode getNode() { 54 return myNode; 55 } 56 57 @NotNull 58 public TextRange getTextRange() { 59 return myNode.getTextRange(); 60 } 61 62 @NotNull 63 public List<Block> getSubBlocks() { 64 if (mySubBlocks == null) { 65 SubBlockVisitor visitor = new SubBlockVisitor(getSettings()); 66 visitor.visit(myNode); 67 mySubBlocks = visitor.getBlocks(); 68 } 69 return mySubBlocks; 70 } 71 72 @Nullable 73 public Wrap getWrap() { 74 return myWrap; 75 } 76 77 @Nullable 78 public Indent getIndent() { 79 return myIndent; 80 } 81 82 @Nullable 83 public Alignment getAlignment() { 84 return myAlignment; 85 } 86 87 @Nullable 88 public Spacing getSpacing(Block child1, Block child2) { 89 return new JSSpacingProcessor(getNode(), ((JSBlock)child1).getNode(), ((JSBlock)child2).getNode(), mySettings).getResult(); 90 } 91 92 @NotNull 93 public ChildAttributes getChildAttributes(final int newChildIndex) { 94 Indent indent = null; 95 if (myNode.getElementType() == JSElementTypes.BLOCK) { 96 indent = Indent.getNormalIndent(); 97 } 98 else if (myNode.getElementType() == JSElementTypes.FILE) { 99 indent = Indent.getNoneIndent(); 100 } 101 else if (JSElementTypes.SOURCE_ELEMENTS.isInSet(myNode.getElementType())) { 102 indent = Indent.getNoneIndent(); 103 } 104 105 Alignment alignment = null; 106 final List<Block> subBlocks = getSubBlocks(); 107 for (int i = 0; i < newChildIndex; i++) { 108 final Alignment childAlignment = subBlocks.get(i).getAlignment(); 109 if (childAlignment != null) { 110 alignment = childAlignment; 111 break; 112 } 113 } 114 115 // in for loops, alignment is required only for items within parentheses 116 if (myNode.getElementType() == JSElementTypes.FOR_STATEMENT || 117 myNode.getElementType() == JSElementTypes.FOR_IN_STATEMENT) { 118 for(int i=0; i < newChildIndex; i++) { 119 if (((JSBlock) subBlocks.get(i)).getNode().getElementType() == JSTokenTypes.RPAR) { 120 alignment = null; 121 break; 122 } 123 } 124 } 125 126 return new ChildAttributes(indent, alignment); 127 } 128 129 public boolean isIncomplete() { 130 return isIncomplete(myNode); 131 } 132 133 private boolean isIncomplete(ASTNode node) { 134 ASTNode lastChild = node.getLastChildNode(); 135 while (lastChild != null && lastChild.getPsi() instanceof PsiWhiteSpace) { 136 lastChild = lastChild.getTreePrev(); 137 } 138 if (lastChild == null) return false; 139 if (lastChild.getPsi() instanceof PsiErrorElement) return true; 140 return isIncomplete(lastChild); 141 } 142 143 public CodeStyleSettings getSettings() { 144 return mySettings; 145 } 146 147 public boolean isLeaf() { 148 return myNode.getFirstChildNode() == null; 149 } 150 } 151