JSBlock.java

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