001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.corext.util;
011:
012: import org.eclipse.core.runtime.Assert;
013:
014: import org.eclipse.jface.action.LegacyActionTools;
015:
016: import org.eclipse.jface.text.BadLocationException;
017: import org.eclipse.jface.text.DefaultLineTracker;
018: import org.eclipse.jface.text.ILineTracker;
019: import org.eclipse.jface.text.IRegion;
020:
021: import org.eclipse.jdt.core.IJavaProject;
022: import org.eclipse.jdt.core.formatter.IndentManipulation;
023:
024: /**
025: * Helper class to provide String manipulation functions not available in standard JDK.
026: */
027: public class Strings {
028:
029: private Strings() {
030: }
031:
032: /**
033: * tests if a char is lower case. Fix for 26529
034: */
035: public static boolean isLowerCase(char ch) {
036: return Character.toLowerCase(ch) == ch;
037: }
038:
039: public static boolean startsWithIgnoreCase(String text,
040: String prefix) {
041: int textLength = text.length();
042: int prefixLength = prefix.length();
043: if (textLength < prefixLength)
044: return false;
045: for (int i = prefixLength - 1; i >= 0; i--) {
046: if (Character.toLowerCase(prefix.charAt(i)) != Character
047: .toLowerCase(text.charAt(i)))
048: return false;
049: }
050: return true;
051: }
052:
053: public static String removeNewLine(String message) {
054: StringBuffer result = new StringBuffer();
055: int current = 0;
056: int index = message.indexOf('\n', 0);
057: while (index != -1) {
058: result.append(message.substring(current, index));
059: if (current < index && index != 0)
060: result.append(' ');
061: current = index + 1;
062: index = message.indexOf('\n', current);
063: }
064: result.append(message.substring(current));
065: return result.toString();
066: }
067:
068: /**
069: * Converts the given string into an array of lines. The lines
070: * don't contain any line delimiter characters.
071: *
072: * @return the string converted into an array of strings. Returns <code>
073: * null</code> if the input string can't be converted in an array of lines.
074: */
075: public static String[] convertIntoLines(String input) {
076: try {
077: ILineTracker tracker = new DefaultLineTracker();
078: tracker.set(input);
079: int size = tracker.getNumberOfLines();
080: String result[] = new String[size];
081: for (int i = 0; i < size; i++) {
082: IRegion region = tracker.getLineInformation(i);
083: int offset = region.getOffset();
084: result[i] = input.substring(offset, offset
085: + region.getLength());
086: }
087: return result;
088: } catch (BadLocationException e) {
089: return null;
090: }
091: }
092:
093: /**
094: * Returns <code>true</code> if the given string only consists of
095: * white spaces according to Java. If the string is empty, <code>true
096: * </code> is returned.
097: *
098: * @return <code>true</code> if the string only consists of white
099: * spaces; otherwise <code>false</code> is returned
100: *
101: * @see java.lang.Character#isWhitespace(char)
102: */
103: public static boolean containsOnlyWhitespaces(String s) {
104: int size = s.length();
105: for (int i = 0; i < size; i++) {
106: if (!Character.isWhitespace(s.charAt(i)))
107: return false;
108: }
109: return true;
110: }
111:
112: /**
113: * Removes leading tabs and spaces from the given string. If the string
114: * doesn't contain any leading tabs or spaces then the string itself is
115: * returned.
116: */
117: public static String trimLeadingTabsAndSpaces(String line) {
118: int size = line.length();
119: int start = size;
120: for (int i = 0; i < size; i++) {
121: char c = line.charAt(i);
122: if (!IndentManipulation.isIndentChar(c)) {
123: start = i;
124: break;
125: }
126: }
127: if (start == 0)
128: return line;
129: else if (start == size)
130: return ""; //$NON-NLS-1$
131: else
132: return line.substring(start);
133: }
134:
135: public static String trimTrailingTabsAndSpaces(String line) {
136: int size = line.length();
137: int end = size;
138: for (int i = size - 1; i >= 0; i--) {
139: char c = line.charAt(i);
140: if (IndentManipulation.isIndentChar(c)) {
141: end = i;
142: } else {
143: break;
144: }
145: }
146: if (end == size)
147: return line;
148: else if (end == 0)
149: return ""; //$NON-NLS-1$
150: else
151: return line.substring(0, end);
152: }
153:
154: /**
155: * Returns the indent of the given string in indentation units. Odd spaces
156: * are not counted.
157: *
158: * @param line the text line
159: * @param project the java project from which to get the formatter
160: * preferences, or <code>null</code> for global preferences
161: * @since 3.1
162: */
163: public static int computeIndentUnits(String line,
164: IJavaProject project) {
165: return IndentManipulation.measureIndentUnits(line,
166: CodeFormatterUtil.getTabWidth(project),
167: CodeFormatterUtil.getIndentWidth(project));
168: }
169:
170: /**
171: * Returns the indent of the given string in indentation units. Odd spaces
172: * are not counted.
173: *
174: * @param line the text line
175: * @param tabWidth the width of the '\t' character in space equivalents
176: * @param indentWidth the width of one indentation unit in space equivalents
177: * @since 3.1
178: */
179: public static int computeIndentUnits(String line, int tabWidth,
180: int indentWidth) {
181: return IndentManipulation.measureIndentUnits(line, tabWidth,
182: indentWidth);
183: }
184:
185: /**
186: * Computes the visual length of the indentation of a
187: * <code>CharSequence</code>, counting a tab character as the size until
188: * the next tab stop and every other whitespace character as one.
189: *
190: * @param line the string to measure the indent of
191: * @param tabSize the visual size of a tab in space equivalents
192: * @return the visual length of the indentation of <code>line</code>
193: * @since 3.1
194: */
195: public static int measureIndentLength(CharSequence line, int tabSize) {
196: return IndentManipulation.measureIndentInSpaces(line, tabSize);
197: }
198:
199: /**
200: * Removes the given number of indents from the line. Asserts that the given line
201: * has the requested number of indents. If <code>indentsToRemove <= 0</code>
202: * the line is returned.
203: *
204: * @param project the java project from which to get the formatter
205: * preferences, or <code>null</code> for global preferences
206: * @since 3.1
207: */
208: public static String trimIndent(String line, int indentsToRemove,
209: IJavaProject project) {
210: return IndentManipulation.trimIndent(line, indentsToRemove,
211: CodeFormatterUtil.getTabWidth(project),
212: CodeFormatterUtil.getIndentWidth(project));
213: }
214:
215: /**
216: * Removes the given number of indents from the line. Asserts that the given line
217: * has the requested number of indents. If <code>indentsToRemove <= 0</code>
218: * the line is returned.
219: *
220: * @since 3.1
221: */
222: public static String trimIndent(String line, int indentsToRemove,
223: int tabWidth, int indentWidth) {
224: return IndentManipulation.trimIndent(line, indentsToRemove,
225: tabWidth, indentWidth);
226: }
227:
228: /**
229: * Removes the common number of indents from all lines. If a line
230: * only consists out of white space it is ignored.
231:
232: * @param project the java project from which to get the formatter
233: * preferences, or <code>null</code> for global preferences
234: * @since 3.1
235: */
236: public static void trimIndentation(String[] lines,
237: IJavaProject project) {
238: trimIndentation(lines, CodeFormatterUtil.getTabWidth(project),
239: CodeFormatterUtil.getIndentWidth(project), true);
240: }
241:
242: /**
243: * Removes the common number of indents from all lines. If a line
244: * only consists out of white space it is ignored.
245: *
246: * @since 3.1
247: */
248: public static void trimIndentation(String[] lines, int tabWidth,
249: int indentWidth) {
250: trimIndentation(lines, tabWidth, indentWidth, true);
251: }
252:
253: /**
254: * Removes the common number of indents from all lines. If a line
255: * only consists out of white space it is ignored. If <code>
256: * considerFirstLine</code> is false the first line will be ignored.
257: *
258: * @param project the java project from which to get the formatter
259: * preferences, or <code>null</code> for global preferences
260: * @since 3.1
261: */
262: public static void trimIndentation(String[] lines,
263: IJavaProject project, boolean considerFirstLine) {
264: trimIndentation(lines, CodeFormatterUtil.getTabWidth(project),
265: CodeFormatterUtil.getIndentWidth(project),
266: considerFirstLine);
267: }
268:
269: /**
270: * Removes the common number of indents from all lines. If a line
271: * only consists out of white space it is ignored. If <code>
272: * considerFirstLine</code> is false the first line will be ignored.
273: * @since 3.1
274: */
275: public static void trimIndentation(String[] lines, int tabWidth,
276: int indentWidth, boolean considerFirstLine) {
277: String[] toDo = new String[lines.length];
278: // find indentation common to all lines
279: int minIndent = Integer.MAX_VALUE; // very large
280: for (int i = considerFirstLine ? 0 : 1; i < lines.length; i++) {
281: String line = lines[i];
282: if (containsOnlyWhitespaces(line))
283: continue;
284: toDo[i] = line;
285: int indent = computeIndentUnits(line, tabWidth, indentWidth);
286: if (indent < minIndent) {
287: minIndent = indent;
288: }
289: }
290:
291: if (minIndent > 0) {
292: // remove this indent from all lines
293: for (int i = considerFirstLine ? 0 : 1; i < toDo.length; i++) {
294: String s = toDo[i];
295: if (s != null)
296: lines[i] = trimIndent(s, minIndent, tabWidth,
297: indentWidth);
298: else {
299: String line = lines[i];
300: int indent = computeIndentUnits(line, tabWidth,
301: indentWidth);
302: if (indent > minIndent)
303: lines[i] = trimIndent(line, minIndent,
304: tabWidth, indentWidth);
305: else
306: lines[i] = trimLeadingTabsAndSpaces(line);
307: }
308: }
309: }
310: }
311:
312: /**
313: * Returns that part of the indentation of <code>line</code> that makes up
314: * a multiple of indentation units.
315: *
316: * @param line the line to scan
317: * @param project the java project from which to get the formatter
318: * preferences, or <code>null</code> for global preferences
319: * @return the indent part of <code>line</code>, but no odd spaces
320: * @since 3.1
321: */
322: public static String getIndentString(String line,
323: IJavaProject project) {
324: return IndentManipulation.extractIndentString(line,
325: CodeFormatterUtil.getTabWidth(project),
326: CodeFormatterUtil.getIndentWidth(project));
327: }
328:
329: /**
330: * Returns that part of the indentation of <code>line</code> that makes up
331: * a multiple of indentation units.
332: *
333: * @param line the line to scan
334: * @param tabWidth the size of one tab in space equivalents
335: * @param indentWidth the size of the indent in space equivalents
336: * @return the indent part of <code>line</code>, but no odd spaces
337: * @since 3.1
338: */
339: public static String getIndentString(String line, int tabWidth,
340: int indentWidth) {
341: return IndentManipulation.extractIndentString(line, tabWidth,
342: indentWidth);
343: }
344:
345: public static String[] removeTrailingEmptyLines(String[] sourceLines) {
346: int lastNonEmpty = findLastNonEmptyLineIndex(sourceLines);
347: String[] result = new String[lastNonEmpty + 1];
348: for (int i = 0; i < result.length; i++) {
349: result[i] = sourceLines[i];
350: }
351: return result;
352: }
353:
354: private static int findLastNonEmptyLineIndex(String[] sourceLines) {
355: for (int i = sourceLines.length - 1; i >= 0; i--) {
356: if (!sourceLines[i].trim().equals(""))//$NON-NLS-1$
357: return i;
358: }
359: return -1;
360: }
361:
362: /**
363: * Change the indent of, possible muti-line, code range. The current indent is removed, a new indent added.
364: * The first line of the code will not be changed. (It is considered to have no indent as it might start in
365: * the middle of a line)
366: *
367: * @param project the java project from which to get the formatter
368: * preferences, or <code>null</code> for global preferences
369: * @since 3.1
370: */
371: public static String changeIndent(String code, int codeIndentLevel,
372: IJavaProject project, String newIndent, String lineDelim) {
373: return IndentManipulation.changeIndent(code, codeIndentLevel,
374: CodeFormatterUtil.getTabWidth(project),
375: CodeFormatterUtil.getIndentWidth(project), newIndent,
376: lineDelim);
377: }
378:
379: /**
380: * Change the indent of, possible muti-line, code range. The current indent is removed, a new indent added.
381: * The first line of the code will not be changed. (It is considered to have no indent as it might start in
382: * the middle of a line)
383: * @since 3.1
384: */
385: public static String changeIndent(String code, int codeIndentLevel,
386: int tabWidth, int indentWidth, String newIndent,
387: String lineDelim) {
388: return IndentManipulation.changeIndent(code, codeIndentLevel,
389: tabWidth, indentWidth, newIndent, lineDelim);
390: }
391:
392: public static String trimIndentation(String source,
393: IJavaProject project, boolean considerFirstLine) {
394: return trimIndentation(source, CodeFormatterUtil
395: .getTabWidth(project), CodeFormatterUtil
396: .getIndentWidth(project), considerFirstLine);
397: }
398:
399: public static String trimIndentation(String source, int tabWidth,
400: int indentWidth, boolean considerFirstLine) {
401: try {
402: ILineTracker tracker = new DefaultLineTracker();
403: tracker.set(source);
404: int size = tracker.getNumberOfLines();
405: if (size == 1)
406: return source;
407: String lines[] = new String[size];
408: for (int i = 0; i < size; i++) {
409: IRegion region = tracker.getLineInformation(i);
410: int offset = region.getOffset();
411: lines[i] = source.substring(offset, offset
412: + region.getLength());
413: }
414: Strings.trimIndentation(lines, tabWidth, indentWidth,
415: considerFirstLine);
416: StringBuffer result = new StringBuffer();
417: int last = size - 1;
418: for (int i = 0; i < size; i++) {
419: result.append(lines[i]);
420: if (i < last)
421: result.append(tracker.getLineDelimiter(i));
422: }
423: return result.toString();
424: } catch (BadLocationException e) {
425: Assert.isTrue(false, "Can not happend"); //$NON-NLS-1$
426: return null;
427: }
428: }
429:
430: /**
431: * Concatenate the given strings into one strings using the passed line delimiter as a
432: * delimiter. No delimiter is added to the last line.
433: */
434: public static String concatenate(String[] lines, String delimiter) {
435: StringBuffer buffer = new StringBuffer();
436: for (int i = 0; i < lines.length; i++) {
437: if (i > 0)
438: buffer.append(delimiter);
439: buffer.append(lines[i]);
440: }
441: return buffer.toString();
442: }
443:
444: public static boolean equals(String s, char[] c) {
445: if (s.length() != c.length)
446: return false;
447:
448: for (int i = c.length; --i >= 0;)
449: if (s.charAt(i) != c[i])
450: return false;
451: return true;
452: }
453:
454: public static String removeTrailingCharacters(String text,
455: char toRemove) {
456: int size = text.length();
457: int end = size;
458: for (int i = size - 1; i >= 0; i--) {
459: char c = text.charAt(i);
460: if (c == toRemove) {
461: end = i;
462: } else {
463: break;
464: }
465: }
466: if (end == size)
467: return text;
468: else if (end == 0)
469: return ""; //$NON-NLS-1$
470: else
471: return text.substring(0, end);
472: }
473:
474: public static String removeMnemonicIndicator(String string) {
475: return LegacyActionTools.removeMnemonics(string);
476: }
477: }
|