blob: 37d5e89343c7fce505d0d67727c520b416bdef04 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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 org.jetbrains.idea.eclipse.importer;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.openapi.options.SchemeImportException;
import com.intellij.openapi.options.SchemeImporter;
import com.intellij.psi.codeStyle.CodeStyleScheme;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
/**
* @author Rustam Vishnyakov
*/
public class EclipseCodeStyleSchemeImporter implements SchemeImporter<CodeStyleScheme>, EclipseXmlProfileElements {
private static final Logger LOG = Logger.getInstance("#" + EclipseCodeStyleSchemeImporter.class.getName());
private final static String PROGRAMMATIC_IMPORT_KEY = "<Programmatic>";
private final EclipseImportMap myImportMap;
public EclipseCodeStyleSchemeImporter() {
myImportMap = new EclipseImportMap();
myImportMap.load();
}
@Override
public String getSourceExtension() {
return "xml";
}
@NotNull
@Override
public String[] readSchemeNames(@NotNull InputStream inputStream) throws SchemeImportException {
final Set<String> names = new HashSet<String>();
EclipseXmlProfileReader reader = new EclipseXmlProfileReader(new EclipseXmlProfileReader.OptionHandler() {
@Override
public void handleOption(@NotNull String eclipseKey, @NotNull String value) throws SchemeImportException {
// Ignore
}
@Override
public void handleName(String name) {
names.add(name);
}
});
reader.readSettings(inputStream);
return ArrayUtil.toStringArray(names);
}
@Override
public void importScheme(@NotNull InputStream inputStream, final @Nullable String sourceScheme, final CodeStyleScheme scheme)
throws SchemeImportException {
final CodeStyleSettings settings = scheme.getCodeStyleSettings();
EclipseXmlProfileReader reader = new EclipseXmlProfileReader(new EclipseXmlProfileReader.OptionHandler() {
private String myCurrScheme;
@Override
public void handleOption(@NotNull String eclipseKey, @NotNull String value) throws SchemeImportException {
if (sourceScheme == null || myCurrScheme != null && myCurrScheme.equals(sourceScheme)) {
setCodeStyleOption(settings, eclipseKey, value);
}
}
@Override
public void handleName(String name) {
myCurrScheme = name;
}
});
reader.readSettings(inputStream);
}
private void setCodeStyleOption(@NotNull CodeStyleSettings settings, @NotNull String key, @NotNull String value)
throws SchemeImportException {
EclipseImportMap.ImportDescriptor importDescriptor = myImportMap.getImportDescriptor(key);
if (importDescriptor != null) {
try {
if (importDescriptor.isLanguageSpecific()) {
CommonCodeStyleSettings languageSettings = settings.getCommonSettings(importDescriptor.getLanguage());
if (languageSettings != null) {
if (importDescriptor.isIndentOptions()) {
CommonCodeStyleSettings.IndentOptions indentOptions = languageSettings.getIndentOptions();
if (indentOptions != null) {
setValue(indentOptions, key, importDescriptor.getFieldName(), value);
}
}
else {
setValue(languageSettings, key, importDescriptor.getFieldName(), value);
}
}
}
else {
setValue(settings, key, importDescriptor.getFieldName(), value);
}
}
catch (Exception e) {
throw new SchemeImportException(e);
}
}
}
private static void setValue(Object object, String key, String fieldName, String value) throws SchemeImportException {
if (PROGRAMMATIC_IMPORT_KEY.equalsIgnoreCase(fieldName)) {
setProgrammatically(object, key, value);
return;
}
try {
Field targetField = object.getClass().getField(fieldName);
Class<?> fieldType = targetField.getType();
if (fieldType.isPrimitive()) {
if (Boolean.TYPE.equals(fieldType)) {
targetField.setBoolean(object, valueToBoolean(key, value));
}
else if (Integer.TYPE.equals(fieldType)) {
targetField.setInt(object, valueToInt(value));
}
}
else if (fieldType.equals(String.class)) {
targetField.set(object, value);
}
}
catch (IllegalAccessException e) {
LOG.error(e);
}
catch (NoSuchFieldException e) {
LOG.error("Field '" + fieldName + "' does not exist in " + object.getClass().getName(), e);
}
}
private static boolean valueToBoolean(@NotNull String key, @NotNull String value) throws SchemeImportException {
if (VALUE_INSERT.equals(value) ||
VALUE_TRUE.equals(value)) {
return true;
}
if (!(VALUE_DO_NOT_INSERT.equals(value) ||
VALUE_FALSE.equals(value))) {
throw new SchemeImportException("Unrecognized boolean value: " + value + ", key: " + key);
}
return false;
}
private static int valueToInt(@NotNull String value) {
if (VALUE_END_OF_LINE.equals(value)) return CommonCodeStyleSettings.END_OF_LINE;
if (VALUE_NEXT_LINE.equals(value)) return CommonCodeStyleSettings.NEXT_LINE;
if (VALUE_NEXT_LINE_SHIFTED.equals(value)) return CommonCodeStyleSettings.NEXT_LINE_SHIFTED;
if (VALUE_NEXT_LINE_IF_WRAPPED.equals(value)) return CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED;
return Integer.parseInt(value);
}
private static class AlignmentAndWrapValueDecoder {
int myEncodedValue;
public AlignmentAndWrapValueDecoder(int encodedValue) {
myEncodedValue = encodedValue;
}
public int getWrapType() {
switch (getEclipseWrap()) {
case WRAP_WHERE_NECESSARY:
case WRAP_FIRST_OTHERS_WHERE_NECESSARY:
return CommonCodeStyleSettings.WRAP_AS_NEEDED;
case WRAP_ALL_EXCEPT_FIRST:
case WRAP_ALL_INDENT_EXCEPT_FIRST:
case WRAP_ALL_ON_NEW_LINE_EACH:
return CommonCodeStyleSettings.WRAP_AS_NEEDED | CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM;
}
return CommonCodeStyleSettings.DO_NOT_WRAP;
}
public int getFirstElementWrapType() {
return isNewLineBeforeFirst() ? CommonCodeStyleSettings.WRAP_ALWAYS :
getEclipseWrap() == WRAP_ALL_EXCEPT_FIRST ? CommonCodeStyleSettings.DO_NOT_WRAP :
CommonCodeStyleSettings.WRAP_AS_NEEDED;
}
public boolean isFirstElementWrapped() {
int eclipseWrapValue = getEclipseWrap();
return eclipseWrapValue == WRAP_FIRST_OTHERS_WHERE_NECESSARY ||
eclipseWrapValue == WRAP_ALL_INDENT_EXCEPT_FIRST ||
eclipseWrapValue == WRAP_ALL_ON_NEW_LINE_EACH ||
isNewLineBeforeFirst();
}
public boolean isNewLineBeforeFirst() {
return (myEncodedValue & 1) != 0;
}
public boolean isAlignmentOn() {
return (myEncodedValue & 2) != 0;
}
public int getEclipseWrap() {
return myEncodedValue & WRAP_MASK;
}
}
private static void setProgrammatically(@NotNull Object object, @NotNull String key, @NotNull String value) throws SchemeImportException {
if (key.contains("alignment") && value.matches("\\d*") && object instanceof CommonCodeStyleSettings) {
if (setAlignmentAndWrappingOptions((CommonCodeStyleSettings)object, key, value)) return;
}
if (object instanceof CodeStyleSettings) {
CodeStyleSettings settings = (CodeStyleSettings)object;
if (OPTION_REMOVE_JAVADOC_BLANK_LINES.equals(key)) {
settings.JD_KEEP_EMPTY_LINES = !valueToBoolean(key, value);
}
else if (OPTION_NEW_LINE_AT_EOF.equals(key)) {
EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
editorSettings.setEnsureNewLineAtEOF(valueToBoolean(key, value));
}
}
else if (object instanceof CommonCodeStyleSettings) {
CommonCodeStyleSettings commonSettings = (CommonCodeStyleSettings)object;
if (OPTION_SPACE_AFTER_BINARY_OPERATOR.equals(key)) {
boolean addSpace = valueToBoolean(key, value);
commonSettings.SPACE_AROUND_ADDITIVE_OPERATORS =
commonSettings.SPACE_AROUND_BITWISE_OPERATORS =
commonSettings.SPACE_AROUND_LOGICAL_OPERATORS =
commonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS =
commonSettings.SPACE_AROUND_RELATIONAL_OPERATORS =
commonSettings.SPACE_AROUND_SHIFT_OPERATORS =
commonSettings.SPACE_AROUND_EQUALITY_OPERATORS =
addSpace;
}
else if (OPTION_INDENT_CLASS_BODY_DECL.equals(key)) {
commonSettings.DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS = !valueToBoolean(key, value);
}
else if (OPTION_BLANK_LINES_BEFORE_FIRST_DECLARATION_IN_CLASS.equals(key)) {
int intValue = valueToInt(value);
commonSettings.BLANK_LINES_AFTER_CLASS_HEADER = intValue;
commonSettings.BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER = intValue;
}
else if (OPTION_EMPTY_LINES_TO_PRESERVE.equals(key)) {
int intValue = valueToInt(value);
commonSettings.KEEP_BLANK_LINES_IN_CODE = intValue;
commonSettings.KEEP_BLANK_LINES_IN_DECLARATIONS = intValue;
commonSettings.KEEP_BLANK_LINES_BEFORE_RBRACE = intValue;
}
else if (OPTION_SPACE_AFTER_CLOSING_BRACE_IN_BLOCK.equals(key)) {
boolean insertSpace = valueToBoolean(key, value);
commonSettings.SPACE_BEFORE_ELSE_KEYWORD = insertSpace;
commonSettings.SPACE_BEFORE_CATCH_KEYWORD = insertSpace;
commonSettings.SPACE_BEFORE_FINALLY_KEYWORD = insertSpace;
}
else if (OPTION_SPACE_BEFORE_OPENING_BRACE_IN_BLOCK.equals(key)) {
boolean insertSpace = valueToBoolean(key, value);
commonSettings.SPACE_BEFORE_IF_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_FOR_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_WHILE_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_DO_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_TRY_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_CATCH_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_FINALLY_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_SYNCHRONIZED_LBRACE = insertSpace;
}
}
else if (object instanceof CommonCodeStyleSettings.IndentOptions) {
CommonCodeStyleSettings.IndentOptions indentOptions = (CommonCodeStyleSettings.IndentOptions)object;
if (OPTION_TAB_CHAR.equals(key)) {
if (TAB_CHAR_TAB.equals(value) || TAB_CHAR_MIXED.equals(value)) {
indentOptions.USE_TAB_CHARACTER = true;
}
else if (TAB_CHAR_SPACE.equals(value)) {
indentOptions.USE_TAB_CHARACTER = false;
}
}
else if (OPTION_CONTINUATION_INDENT.equals(key)) {
indentOptions.CONTINUATION_INDENT_SIZE = indentOptions.TAB_SIZE * valueToInt(value);
}
else if (OPTION_TAB_SIZE.equals(key)) {
int newTabSize = valueToInt(value);
int continuationTabs = indentOptions.TAB_SIZE > 0 ? indentOptions.CONTINUATION_INDENT_SIZE / indentOptions.TAB_SIZE : -1;
indentOptions.TAB_SIZE = newTabSize;
if (continuationTabs >= 0) {
indentOptions.CONTINUATION_INDENT_SIZE = continuationTabs * newTabSize;
}
}
}
}
private static boolean setAlignmentAndWrappingOptions(@NotNull CommonCodeStyleSettings settings,
@NotNull String key,
@NotNull String value) {
int encodedValue = Integer.parseInt(value);
AlignmentAndWrapValueDecoder decoder = new AlignmentAndWrapValueDecoder(encodedValue);
if (OPTION_ALIGN_ARGS_IN_ANNOTATION.equals(key)) {
settings.FIELD_ANNOTATION_WRAP =
settings.METHOD_ANNOTATION_WRAP =
settings.PARAMETER_ANNOTATION_WRAP =
settings.VARIABLE_ANNOTATION_WRAP =
settings.CLASS_ANNOTATION_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_EXPR_IN_ARRAY_INITIALIZER.equals(key)) {
settings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION = decoder.isAlignmentOn();
settings.ARRAY_INITIALIZER_WRAP = decoder.getWrapType();
settings.ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_ARGS_IN_METHOD_INVOCATION.equals(key)) {
settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = decoder.isAlignmentOn();
settings.CALL_PARAMETERS_WRAP = decoder.getWrapType();
settings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_INTERFACES_IN_TYPE_DECL.equals(key)) {
settings.ALIGN_MULTILINE_EXTENDS_LIST = decoder.isAlignmentOn();
settings.EXTENDS_KEYWORD_WRAP = decoder.getFirstElementWrapType();
settings.EXTENDS_LIST_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_ASSIGNMENT.equals(key)) {
settings.ALIGN_MULTILINE_ASSIGNMENT = decoder.isAlignmentOn();
settings.ASSIGNMENT_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_METHOD_DECL_PARAMETERS.equals(key)) {
settings.ALIGN_MULTILINE_PARAMETERS = decoder.isAlignmentOn();
settings.METHOD_PARAMETERS_WRAP = decoder.getWrapType();
settings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_BINARY_EXPR.equals(key)) {
settings.ALIGN_MULTILINE_BINARY_OPERATION = decoder.isAlignmentOn();
settings.BINARY_OPERATION_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_THROWS_IN_METHOD_DECL.equals(key)) {
settings.ALIGN_MULTILINE_THROWS_LIST = decoder.isAlignmentOn();
settings.THROWS_KEYWORD_WRAP = decoder.getFirstElementWrapType();
settings.THROWS_LIST_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_RESOURCES_IN_TRY.equals(key)) {
settings.ALIGN_MULTILINE_RESOURCES = decoder.isAlignmentOn();
settings.RESOURCE_LIST_WRAP = decoder.getWrapType();
settings.RESOURCE_LIST_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_CHAINED_CALLS.equals(key)) {
settings.METHOD_CALL_CHAIN_WRAP = decoder.getWrapType();
settings.ALIGN_MULTILINE_CHAINED_METHODS = decoder.isAlignmentOn();
}
else if (OPTION_ALIGN_CONDITIONALS.equals(key)) {
settings.TERNARY_OPERATION_WRAP = decoder.getWrapType();
settings.ALIGN_MULTILINE_TERNARY_OPERATION = decoder.isAlignmentOn();
}
return false;
}
}