Expandable indent storing additional block, which indent is used as min indent marker...
[idea/community.git] / platform / lang-api / src / com / intellij / formatting / Indent.java
1 /*
2  * Copyright 2000-2009 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.formatting;
17
18 import org.jetbrains.annotations.NonNls;
19 import org.jetbrains.annotations.NotNull;
20
21 /**
22  * The indent setting for a formatting model block. Indicates how the block is indented
23  * relative to its parent block.
24  * <p/>
25  * <b>Relative indents</b>
26  * <p/>
27  * Number of factory methods of this class use <code>'indent relative to direct parent'</code> flag. It specified anchor parent block
28  * to use to apply indent.
29  * <p/>
30  * Consider the following situation:
31  * <p/>
32  * <pre>
33  *     return a == 0
34                   && (b == 0
35                           || c == 0);
36  * </pre>
37  * <p/>
38  * Here is the following blocks hierarchy (going from child to parent):
39  * <p/>
40  * <ul>
41  *   <li><code>'|| c == 0`</code>;</li>
42  *   <li><code>'b == 0 || c == 0'</code>;</li>
43  *   <li><code>'(b == 0 || c == 0)'</code>;</li>
44  *   <li><code>'a == 0 && (b == 0 || c == 0)'</code>;</li>
45  *   <li><code>'return a == 0 && (b == 0 || c == 0)'</code>;</li>
46  * </ul>
47  * <p/>
48  * By default formatter applies block indent to the first block ancestor (direct or indirect) that starts on a new line. That means
49  * that such an ancestor for both blocks <code>'|| c == 0'</code> and <code>'&& (b == 0 || c == 0)'</code>
50  * is <code>'return a == 0 && (b == 0 || c == 0)'</code>. That means that the code above is formatted as follows:
51  * <p/>
52  * <pre>
53  *    return a == 0
54  *        && (b == 0
55  *        || c == 0);
56  * </pre>
57  * <p/>
58  * In contrast, it's possible to specify that direct parent block that starts on a line before target child block is used as an anchor.
59  * Initial formatting example illustrates such approach.
60  * <p/>
61  * <b>Enforcing indent to children</b>
62  * <p/>
63  * It's possible to configure indent to enforce parent block indent to its children that start new line. Consider the following situation:
64  * <pre>
65  *   foo("test", new Runnable() {
66  *           public void run() { 
67  *           }                   
68  *       },                      
69  *       new Runnable() {        
70  *           public void run() { 
71  *           }                   
72  *       }                       
73  *   );                          
74  * </pre>
75  * We want the first {@code 'new Runnable() {...}'} block here to be indented to the method expression list element. However, formatter
76  * uses indents only if the block starts new line. Here the block doesn't start new line ({@code 'new Runnable() ...'}), hence
77  * we need to define <code>'enforce indent to children'</code> flag in order to instruct formatter to apply parent indent to the sub-blocks.
78  *
79  * @see com.intellij.formatting.Block#getIndent()
80  * @see com.intellij.formatting.ChildAttributes#getChildIndent() 
81  */
82
83 public abstract class Indent {
84   private static IndentFactory myFactory;
85
86   public abstract Type getType();
87
88   static void setFactory(IndentFactory factory) {
89     myFactory = factory;
90   }
91
92   /**
93    * Returns an instance of a regular indent, with the width specified
94    * in "Project Code Style | General | Indent".
95    * <p/>
96    * <b>Note:</b> returned indent is not set to be <code>'relative'</code> to it's direct parent block
97    *
98    * @return the indent instance.
99    * @see #getNormalIndent(boolean)
100    */
101   public static Indent getNormalIndent() {
102     return myFactory.getNormalIndent(false);
103   }
104
105   /**
106    * Returns an instance of a regular indent, with the width specified
107    * in "Project Code Style | General | Indent" and given <code>'relative to direct parent'</code> flag
108    *
109    * @param relativeToDirectParent    flag the indicates if current indent object anchors direct block parent (feel free
110    *                                  to get more information about that at class-level javadoc)
111    * @return                          newly created indent instance configured in accordance with the given parameter
112    */
113   public static Indent getNormalIndent(boolean relativeToDirectParent) {
114     return myFactory.getNormalIndent(relativeToDirectParent);
115   }
116
117   /**
118    * Returns the standard "empty indent" instance, indicating that the block is not
119    * indented relative to its parent block.
120    *
121    * @return the empty indent instance.
122    */
123   public static Indent getNoneIndent() {
124     return myFactory.getNoneIndent();
125   }
126
127   /**
128    * Returns the "absolute none" indent instance, indicating that the block will
129    * be placed at the leftmost column in the document.
130    *
131    * @return the indent instance.
132    */
133   public static Indent getAbsoluteNoneIndent() {
134     return myFactory.getAbsoluteNoneIndent();
135   }
136
137   /**
138    * Returns the "absolute label" indent instance, indicating that the block will be
139    * indented by the number of spaces indicated in the "Project Code Style | General |
140    * Label indent" setting from the leftmost column in the document.
141    *
142    * @return the indent instance.
143    */
144   public static Indent getAbsoluteLabelIndent() {
145     return myFactory.getAbsoluteLabelIndent();
146   }
147
148   /**
149    * Returns the "label" indent instance, indicating that the block will be indented by
150    * the number of spaces indicated in the "Project Code Style | General | Label indent"
151    * setting relative to its parent block.
152    *
153    * @return the indent instance.
154    */
155   public static Indent getLabelIndent() {
156     return myFactory.getLabelIndent();
157   }
158
159   /**
160    * Returns the "continuation" indent instance, indicating that the block will be indented by
161    * the number of spaces indicated in the "Project Code Style | General | Continuation indent"
162    * setting relative to its parent block.
163    * <p/>
164    * <b>Note:</b> returned indent is not set to be <code>'relative'</code> to it's direct parent block
165    *
166    * @return the indent instance.
167    * @see #getContinuationIndent(boolean)
168    */
169   public static Indent getContinuationIndent() {
170     return myFactory.getContinuationIndent(false);
171   }
172
173   /**
174    * Returns the "continuation" indent instance, indicating that the block will be indented by
175    * the number of spaces indicated in the "Project Code Style | General | Continuation indent"
176    * setting relative to its parent block  and given <code>'relative to direct parent'</code> flag.
177    *
178    * @param relativeToDirectParent    flag the indicates if current indent object anchors direct block parent (feel free
179    *                                  to get more information about that at class-level javadoc)
180    * @return                          newly created indent instance configured in accordance with the given parameter
181    */
182   public static Indent getContinuationIndent(boolean relativeToDirectParent) {
183     return myFactory.getContinuationIndent(relativeToDirectParent);
184   }
185
186   /**
187    * Returns the "continuation without first" indent instance, indicating that the block will
188    * be indented by the number of spaces indicated in the "Project Code Style | General | Continuation indent"
189    * setting relative to its parent block, unless this block is the first of the children of its
190    * parent having the same indent type. This is used for things like parameter lists, where the first parameter
191    * does not have any indent and the remaining parameters are indented by the continuation indent.
192    * <p/>
193    * <b>Note:</b> returned indent is not set to be <code>'relative'</code> to it's direct parent block
194    *
195    * @return the indent instance.
196    * @see #getContinuationWithoutFirstIndent(boolean)
197    */
198   public static Indent getContinuationWithoutFirstIndent() {//is default
199     return myFactory.getContinuationWithoutFirstIndent(false);
200   }
201
202   /**
203    * Returns the "continuation without first" indent instance, indicating that the block will
204    * be indented by the number of spaces indicated in the "Project Code Style | General | Continuation indent"
205    * setting relative to its parent block, unless this block is the first of the children of its
206    * parent having the same indent type. This is used for things like parameter lists, where the first parameter
207    * does not have any indent and the remaining parameters are indented by the continuation indent  and given
208    * <code>'relative to direct parent'</code> flag.
209    *
210    * @param relativeToDirectParent    flag the indicates if current indent object anchors direct block parent (feel free
211    *                                  to get more information about that at class-level javadoc)
212    * @return                          newly created indent instance configured in accordance with the given parameter
213    */
214   public static Indent getContinuationWithoutFirstIndent(boolean relativeToDirectParent) {
215     return myFactory.getContinuationWithoutFirstIndent(relativeToDirectParent);
216   }
217
218   /**
219    * Returns an indent with the specified width.
220    * <p/>
221    * <b>Note:</b> returned indent is not set to be <code>'relative'</code> to it's direct parent block
222    *
223    * @param spaces the number of spaces in the indent.
224    * @return the indent instance.
225    * @see #getSpaceIndent(int, boolean)
226    */
227   public static Indent getSpaceIndent(final int spaces) {
228     return myFactory.getSpaceIndent(spaces, false);
229   }
230
231   /**
232    * Returns an indent with the specified width  and given <code>'relative to direct parent'</code> flag.
233    *
234    * @param spaces                    the number of spaces in the indent
235    * @param relativeToDirectParent    flag the indicates if current indent object anchors direct block parent (feel free
236    *                                  to get more information about that at class-level javadoc)
237    * @return                          newly created indent instance configured in accordance with the given parameter
238    */
239   public static Indent getSpaceIndent(final int spaces, final boolean relativeToDirectParent) {
240     return myFactory.getSpaceIndent(spaces, relativeToDirectParent);
241   }
242
243   /**
244    * Base factory method for {@link Indent} objects construction, i.e. all other methods may be expressed in terms of this method.
245    * 
246    * @param type                      indent type
247    * @param relativeToDirectParent    flag the indicates if current indent object anchors direct block parent (feel free
248    *                                  to get more information about that at class-level javadoc)
249    * @param enforceIndentToChildren   flag the indicates if current indent object should be enforced for multiline block children
250    *                                  (feel free to get more information about that at class-level javadoc)
251    * @return                          newly created indent configured in accordance with the given arguments
252    */
253   public static Indent getIndent(@NotNull Type type, boolean relativeToDirectParent, boolean enforceIndentToChildren) {
254     return myFactory.getIndent(type, relativeToDirectParent, enforceIndentToChildren);
255   }
256
257   /**
258    * Base factory method for {@link Indent} objects construction, i.e. all other methods may be expressed in terms of this method.
259    *
260    * @param type                      indent type
261    * @param spaces                    the number of spaces in the indent
262    * @param relativeToDirectParent    flag the indicates if current indent object anchors direct block parent (feel free
263    *                                  to get more information about that at class-level javadoc)
264    * @param enforceIndentToChildren   flag the indicates if current indent object should be enforced for multiline block children
265    *                                  (feel free to get more information about that at class-level javadoc)
266    * @return                          newly created indent configured in accordance with the given arguments
267    */
268   public static Indent getIndent(@NotNull Type type, int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren) {
269     return myFactory.getIndent(type, spaces, relativeToDirectParent, enforceIndentToChildren);
270   }
271
272   public static Indent getSmartIndent(Type type) {
273     return myFactory.getSmartIndent(type);
274   }
275
276   public static class Type {
277     private final String myName;
278
279
280     private Type(@NonNls final String name) {
281       myName = name;
282     }
283
284     public static final Type SPACES = new Type("SPACES");
285     public static final Type NONE = new Type("NONE");
286     public static final Type LABEL = new Type("LABEL");
287     public static final Type NORMAL = new Type("NORMAL");
288     public static final Type CONTINUATION = new Type("CONTINUATION");
289     public static final Type CONTINUATION_WITHOUT_FIRST = new Type("CONTINUATION_WITHOUT_FIRST");
290
291     public String toString() {
292       return myName;
293     }
294   }
295 }