/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui.internal.util;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.core.formatter.DefaultCodeFormatterConstants;
import com.google.dart.tools.ui.DartToolsPlugin;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DefaultPositionUpdater;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.Position;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
public class CodeFormatterUtil {
/**
* Creates a string that represents the given number of indentation units. The returned string can
* contain tabs and/or spaces depending on the core formatter preferences.
*
* @param indentationUnits the number of indentation units to generate
* @return the indent string
*/
public static String createIndentString(int indentationUnits) {
StringBuffer s = new StringBuffer();
for (int i = 0; i < indentationUnits; i++) {
s.append(" ");
}
return s.toString();
}
/**
* Evaluates the edit on the given string.
*
* @throws IllegalArgumentException If the positions are not inside the string, a
* IllegalArgumentException is thrown.
*/
public static String evaluateFormatterEdit(String string, TextEdit edit, Position[] positions) {
try {
Document doc = createDocument(string, positions);
edit.apply(doc, 0);
if (positions != null) {
for (int i = 0; i < positions.length; i++) {
Assert.isTrue(!positions[i].isDeleted, "Position got deleted"); //$NON-NLS-1$
}
}
return doc.get();
} catch (BadLocationException e) {
DartToolsPlugin.log(e); // bug in the formatter
Assert.isTrue(false, "Formatter created edits with wrong positions: " + e.getMessage()); //$NON-NLS-1$
}
return null;
}
/**
* Returns the current indent width.
*
* @param project the project where the source is used or <code>null</code> if the project is
* unknown and the workspace default should be used
* @return the indent width
*/
public static int getIndentWidth(IProject project) {
String key;
if (DefaultCodeFormatterConstants.MIXED.equals(getCoreOption(
project,
DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) {
key = DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE;
} else {
key = DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE;
}
return getCoreOption(project, key, 2);
}
/**
* Gets the current tab width.
*
* @return The tab width
*/
public static int getTabWidth() {
IPreferenceStore preferenceStore = DartToolsPlugin.getDefault().getPreferenceStore();
if (preferenceStore != null) {
int width = preferenceStore.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
if (width != 0) {
return width;
}
}
return 2;
// /*
// * If the tab-char is SPACE, FORMATTER_INDENTATION_SIZE is not used by the core formatter. We
// * piggy back the visual tab length setting in that preference in that case.
// */
// String key;
// if (JavaScriptCore.SPACE.equals(getCoreOption(
// project,
// DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) {
// key = DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE;
// } else {
// key = DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE;
// }
//
// return getCoreOption(project, key, 2);
}
private static Document createDocument(String string, Position[] positions)
throws IllegalArgumentException {
Document doc = new Document(string);
try {
if (positions != null) {
final String POS_CATEGORY = "myCategory"; //$NON-NLS-1$
doc.addPositionCategory(POS_CATEGORY);
doc.addPositionUpdater(new DefaultPositionUpdater(POS_CATEGORY) {
@Override
protected boolean notDeleted() {
if (fOffset < fPosition.offset
&& (fPosition.offset + fPosition.length < fOffset + fLength)) {
fPosition.offset = fOffset + fLength; // deleted positions: set to
// end of remove
return false;
}
return true;
}
});
for (int i = 0; i < positions.length; i++) {
try {
doc.addPosition(POS_CATEGORY, positions[i]);
} catch (BadLocationException e) {
throw new IllegalArgumentException(
"Position outside of string. offset: " + positions[i].offset + ", length: " + positions[i].length + ", string size: " + string.length()); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
}
}
}
} catch (BadPositionCategoryException cannotHappen) {
// can not happen: category is correctly set up
}
return doc;
}
/**
* Returns the possibly <code>project</code>-specific core preference defined under
* <code>key</code>.
*
* @param project the project to get the preference from, or <code>null</code> to get the global
* preference
* @param key the key of the preference
* @return the value of the preference
*/
private static String getCoreOption(IProject project, String key) {
// if (project != null) {
// return project.getOption(key, true);
// }
return DartCore.getOption(key);
}
/**
* Returns the possibly <code>project</code>-specific core preference defined under
* <code>key</code>, or <code>def</code> if the value is not a integer.
*
* @param project the project to get the preference from, or <code>null</code> to get the global
* preference
* @param key the key of the preference
* @param def the default value
* @return the value of the preference
*/
private static int getCoreOption(IProject project, String key, int def) {
try {
return Integer.parseInt(getCoreOption(project, key));
} catch (NumberFormatException e) {
return def;
}
}
}