KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > dom > rewrite > Indents


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.dom.rewrite;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Map JavaDoc;
16
17 import org.eclipse.jface.text.Assert;
18 import org.eclipse.jface.text.BadLocationException;
19 import org.eclipse.jface.text.DefaultLineTracker;
20 import org.eclipse.jface.text.ILineTracker;
21 import org.eclipse.jface.text.IRegion;
22
23 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
24
25 import org.eclipse.text.edits.ReplaceEdit;
26
27 /**
28  * Helper class to provide String manipulation functions dealing with indents
29  */

30 public class Indents {
31     
32     private Indents() {
33         // don't instanciate
34
}
35     
36     /**
37      * Indent char is a space char but not a line delimiters.
38      * <code>== Character.isWhitespace(ch) && ch != '\n' && ch != '\r'</code>
39      * @param ch
40      * @return Returns true if this the character is a indent delimiter character
41      */

42     public static boolean isIndentChar(char ch) {
43         return Character.isWhitespace(ch) && !isLineDelimiterChar(ch);
44     }
45
46     /**
47      * Line delimiter chars are '\n' and '\r'.
48      * @param ch The character to test
49      * @return Returns true if this the character is a line delimiter character
50      */

51     public static boolean isLineDelimiterChar(char ch) {
52         return ch == '\n' || ch == '\r';
53     }
54     
55     /**
56      * Returns the indent of the given string in indentation units. Odd spaces
57      * are not counted.
58      *
59      * @param line the text line
60      * @param tabWidth the width of the '\t' character in space equivalents
61      * @param indentWidth the width of one indentation unit in space equivalents
62      * @since 3.1
63      */

64     public static int computeIndentUnits(String JavaDoc line, int tabWidth, int indentWidth) {
65         if (indentWidth == 0)
66             return -1;
67         int visualLength= measureIndentLength(line, tabWidth);
68         return visualLength / indentWidth;
69     }
70     
71     /**
72      * Computes the visual length of the indentation of a
73      * <code>CharSequence</code>, counting a tab character as the size until
74      * the next tab stop and every other whitespace character as one.
75      *
76      * @param line the string to measure the indent of
77      * @param tabSize the visual size of a tab in space equivalents
78      * @return the visual length of the indentation of <code>line</code>
79      * @since 3.1
80      */

81     public static int measureIndentLength(CharSequence JavaDoc line, int tabSize) {
82         int length= 0;
83         int max= line.length();
84         for (int i= 0; i < max; i++) {
85             char ch= line.charAt(i);
86             if (ch == '\t') {
87                 int reminder= length % tabSize;
88                 length += tabSize - reminder;
89             } else if (isIndentChar(ch)) {
90                 length++;
91             } else {
92                 return length;
93             }
94         }
95         return length;
96     }
97     
98     /**
99      * Removes the given number of indents from the line. Asserts that the given line
100      * has the requested number of indents. If <code>indentsToRemove <= 0</code>
101      * the line is returned.
102      *
103      * @since 3.1
104      */

105     public static String JavaDoc trimIndent(String JavaDoc line, int indentsToRemove, int tabWidth, int indentWidth) {
106         if (line == null || indentsToRemove <= 0)
107             return line;
108
109         final int spaceEquivalentsToRemove= indentsToRemove * indentWidth;
110         
111         int start= 0;
112         int spaceEquivalents= 0;
113         int size= line.length();
114         String JavaDoc prefix= null;
115         for (int i= 0; i < size; i++) {
116             char c= line.charAt(i);
117             if (c == '\t') {
118                 int remainder= spaceEquivalents % tabWidth;
119                 spaceEquivalents += tabWidth - remainder;
120             } else if (isIndentChar(c)) {
121                 spaceEquivalents++;
122             } else {
123                 // Assert.isTrue(false, "Line does not have requested number of indents"); //$NON-NLS-1$
124
start= i;
125                 break;
126             }
127             if (spaceEquivalents == spaceEquivalentsToRemove) {
128                 start= i + 1;
129                 break;
130             }
131             if (spaceEquivalents > spaceEquivalentsToRemove) {
132                 // can happen if tabSize > indentSize, e.g tabsize==8, indent==4, indentsToRemove==1, line prefixed with one tab
133
// this implements the third option
134
start= i + 1; // remove the tab
135
// and add the missing spaces
136
char[] missing= new char[spaceEquivalents - spaceEquivalentsToRemove];
137                 Arrays.fill(missing, ' ');
138                 prefix= new String JavaDoc(missing);
139                 break;
140             }
141         }
142         String JavaDoc trimmed;
143         if (start == size)
144             trimmed= ""; //$NON-NLS-1$
145
else
146             trimmed= line.substring(start);
147         
148         if (prefix == null)
149             return trimmed;
150         return prefix + trimmed;
151     }
152
153
154     
155     /**
156      * Returns that part of the indentation of <code>line</code> that makes up
157      * a multiple of indentation units.
158      *
159      * @param line the line to scan
160      * @param tabWidth the size of one tab in space equivalents
161      * @return the indent part of <code>line</code>, but no odd spaces
162      * @since 3.1
163      */

164     public static String JavaDoc getIndentString(String JavaDoc line, int tabWidth, int indentWidth) {
165         int size= line.length();
166         int end= 0;
167         
168         int spaceEquivs= 0;
169         int characters= 0;
170         for (int i= 0; i < size; i++) {
171             char c= line.charAt(i);
172             if (c == '\t') {
173                 int remainder= spaceEquivs % tabWidth;
174                 spaceEquivs += tabWidth - remainder;
175                 characters++;
176             } else if (isIndentChar(c)) {
177                 spaceEquivs++;
178                 characters++;
179             } else {
180                 break;
181             }
182             if (spaceEquivs >= indentWidth) {
183                 end += characters;
184                 characters= 0;
185                 spaceEquivs= spaceEquivs % indentWidth;
186             }
187         }
188         if (end == 0)
189             return ""; //$NON-NLS-1$
190
else if (end == size)
191             return line;
192         else
193             return line.substring(0, end);
194     }
195     
196     /**
197      * Returns the length of the string representing the number of
198      * indents in the given string <code>line</code>. Returns
199      * <code>-1<code> if the line isn't prefixed with an indent of
200      * the given number of indents.
201      * @since 3.1
202      */

203     public static int computeIndentLength(String JavaDoc line, int numberOfIndents, int tabWidth, int indentWidth) {
204         Assert.isTrue(numberOfIndents >= 0);
205         Assert.isTrue(tabWidth >= 0);
206         Assert.isTrue(indentWidth >= 0);
207         
208         int spaceEquivalents= numberOfIndents * indentWidth;
209         
210         int size= line.length();
211         int result= -1;
212         int blanks= 0;
213         for (int i= 0; i < size && blanks < spaceEquivalents; i++) {
214             char c= line.charAt(i);
215             if (c == '\t') {
216                 int remainder= blanks % tabWidth;
217                 blanks += tabWidth - remainder;
218             } else if (isIndentChar(c)) {
219                 blanks++;
220             } else {
221                 break;
222             }
223             result= i;
224         }
225         if (blanks < spaceEquivalents)
226             return -1;
227         return result + 1;
228     }
229
230     /**
231      * Change the indent of, possible muti-line, code range. The current indent is removed, a new indent added.
232      * The first line of the code will not be changed. (It is considered to have no indent as it might start in
233      * the middle of a line)
234      * @since 3.1
235      */

236     public static String JavaDoc changeIndent(String JavaDoc code, int codeIndentLevel, int tabWidth, int indentWidth, String JavaDoc newIndent, String JavaDoc lineDelim) {
237         try {
238             ILineTracker tracker= new DefaultLineTracker();
239             tracker.set(code);
240             int nLines= tracker.getNumberOfLines();
241             if (nLines == 1) {
242                 return code;
243             }
244             
245             StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
246             
247             for (int i= 0; i < nLines; i++) {
248                 IRegion region= tracker.getLineInformation(i);
249                 int start= region.getOffset();
250                 int end= start + region.getLength();
251                 String JavaDoc line= code.substring(start, end);
252                 
253                 if (i == 0) { // no indent for first line (contained in the formatted string)
254
buf.append(line);
255                 } else { // no new line after last line
256
buf.append(lineDelim);
257                     buf.append(newIndent);
258                     buf.append(trimIndent(line, codeIndentLevel, tabWidth, indentWidth));
259                 }
260             }
261             return buf.toString();
262         } catch (BadLocationException e) {
263             // can not happen
264
return code;
265         }
266     }
267
268     /**
269      * Change the indent of, possible muti-line, code range. The current indent is removed, a new indent added.
270      * The first line of the code will not be changed. (It is considered to have no indent as it might start in
271      * the middle of a line)
272      * @param source The code to change the indent of
273      * @param sourceIndentLevel The indent level of the code
274      * @param tabWidth The current tab width setting
275      * @param newIndent The new Indent string
276      * @return Returns the resulting text edits
277      */

278     public static ReplaceEdit[] getChangeIndentEdits(String JavaDoc source, int sourceIndentLevel, int tabWidth, int indentWidth, String JavaDoc newIndent) {
279         ArrayList JavaDoc result= new ArrayList JavaDoc();
280         try {
281             ILineTracker tracker= new DefaultLineTracker();
282             tracker.set(source);
283             int nLines= tracker.getNumberOfLines();
284             if (nLines == 1)
285                 return (ReplaceEdit[])result.toArray(new ReplaceEdit[result.size()]);
286             for (int i= 1; i < nLines; i++) {
287                 IRegion region= tracker.getLineInformation(i);
288                 int offset= region.getOffset();
289                 String JavaDoc line= source.substring(offset, offset + region.getLength());
290                 int length= Indents.computeIndentLength(line, sourceIndentLevel, tabWidth, indentWidth);
291                 if (length >= 0) {
292                     result.add(new ReplaceEdit(offset, length, newIndent));
293                 } else {
294                     length= Indents.computeIndentUnits(line, tabWidth, indentWidth);
295                     result.add(new ReplaceEdit(offset, length, "")); //$NON-NLS-1$
296
}
297             }
298         } catch (BadLocationException cannotHappen) {
299             // can not happen
300
}
301         return (ReplaceEdit[])result.toArray(new ReplaceEdit[result.size()]);
302     }
303     
304     /**
305      * Returns the tab width as configured in the given map.
306      * @param options The options to look at
307      * @return the tab width
308      */

309     public static int getTabWidth(Map JavaDoc options) {
310         return parseIntValue(options, DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, 4);
311     }
312     
313     /**
314      * Returns the tab width as configured in the given map.
315      * @param options The options to look at
316      * @param tabWidth the tab width
317      * @return the indent width
318      */

319     public static int getIndentWidth(Map JavaDoc options, int tabWidth) {
320         boolean isMixedMode= DefaultCodeFormatterConstants.MIXED.equals(options.get(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR));
321         if (isMixedMode) {
322             return parseIntValue(options, DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE, tabWidth);
323         }
324         return tabWidth;
325     }
326     
327     private static int parseIntValue(Map JavaDoc options, String JavaDoc key, int def) {
328         try {
329             return Integer.parseInt((String JavaDoc) options.get(key));
330         } catch (NumberFormatException JavaDoc e) {
331             return def;
332         }
333     }
334     
335
336     /**
337      * Change the indent of, possible muti-line, code range. The current indent is removed, a new indent added.
338      * The first line of the code will not be changed. (It is considered to have no indent as it might start in
339      * the middle of a line)
340      * @deprecated use the version specifying the indent width instead
341      */

342     public static String JavaDoc changeIndent(String JavaDoc code, int codeIndentLevel, int tabWidth, String JavaDoc newIndent, String JavaDoc lineDelim) {
343         return changeIndent(code, codeIndentLevel, tabWidth, tabWidth, newIndent, lineDelim);
344     }
345
346     /**
347      * Returns the indent of the given string.
348      *
349      * @param line the text line
350      * @param tabWidth the width of the '\t' character.
351      * @deprecated use {@link #computeIndentUnits(String, int, int)} instead
352      */

353     public static int computeIndent(String JavaDoc line, int tabWidth) {
354         return computeIndentUnits(line, tabWidth, tabWidth);
355     }
356
357 }
358
359
Popular Tags