diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java index bf03e8ea3bb9..a3096bd0c09e 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java @@ -17,6 +17,7 @@ package com.intellij.psi.codeStyle.arrangement; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; @@ -140,10 +141,20 @@ public class JavaRearranger implements Rearranger, @Nullable @Override - public JavaElementArrangementEntry wrap(@NotNull PsiElement element) { - List result = new ArrayList(); - element.accept(new JavaArrangementVisitor(result, null, Collections.singleton(element.getTextRange()))); - return result.size() == 1 ? result.get(0) : null; + public Pair> parseWithNew(@NotNull PsiElement root, + @Nullable Document document, + @NotNull Collection ranges, + @NotNull PsiElement element) + { + List existingEntries = new ArrayList(); + root.accept(new JavaArrangementVisitor(existingEntries, document, ranges)); + + List newEntry = new ArrayList(); + element.accept(new JavaArrangementVisitor(newEntry, document, Collections.singleton(element.getTextRange()))); + if (newEntry.size() != 1) { + return null; + } + return Pair.create(newEntry.get(0), existingEntries); } @NotNull diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index b03272e28aa1..3667c518ed64 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -19,7 +19,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.util.*; -import com.intellij.psi.codeStyle.arrangement.ArrangementRule; +import com.intellij.psi.codeStyle.arrangement.ArrangementSettings; import com.intellij.psi.codeStyle.arrangement.ArrangementUtil; import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; import com.intellij.util.xmlb.XmlSerializer; @@ -31,8 +31,6 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; import java.util.Set; /** @@ -42,15 +40,15 @@ import java.util.Set; * @author Rustam Vishnyakov */ public class CommonCodeStyleSettings { - - @NonNls private static final String ARRANGEMENT_ELEMENT_NAME = "arrangementRules"; - - private final List myArrangementRules - = new ArrayList(); - private final Language myLanguage; - private CodeStyleSettings myRootSettings; - private IndentOptions myIndentOptions; - private FileType myFileType; + + @NonNls private static final String ARRANGEMENT_ELEMENT_NAME = "arrangement"; + + private final Language myLanguage; + + private ArrangementSettings myArrangementSettings; + private CodeStyleSettings myRootSettings; + private IndentOptions myIndentOptions; + private FileType myFileType; @NonNls private static final String INDENT_OPTIONS_TAG = "indentOptions"; @@ -122,14 +120,13 @@ public class CommonCodeStyleSettings { return myIndentOptions; } - @NotNull - public List getArrangementRules() { - return myArrangementRules; + @Nullable + public ArrangementSettings getArrangementSettings() { + return myArrangementSettings; } - public void setArrangementRules(@NotNull List rules) { - myArrangementRules.clear(); - myArrangementRules.addAll(rules); + public void setArrangementSettings(@NotNull ArrangementSettings settings) { + myArrangementSettings = settings; } @SuppressWarnings("unchecked") @@ -141,8 +138,8 @@ public class CommonCodeStyleSettings { IndentOptions targetIndentOptions = commonSettings.initIndentOptions(); targetIndentOptions.copyFrom(myIndentOptions); } - if (!myArrangementRules.isEmpty()) { - rootSettings.setArrangementRules(getArrangementRules()); + if (myArrangementSettings != null) { + rootSettings.setArrangementSettings(myArrangementSettings); } return commonSettings; } @@ -214,7 +211,7 @@ public class CommonCodeStyleSettings { } Element arrangementRulesContainer = element.getChild(ARRANGEMENT_ELEMENT_NAME); if (arrangementRulesContainer != null) { - myArrangementRules.addAll(ArrangementUtil.readExternal(arrangementRulesContainer, myLanguage)); + myArrangementSettings = ArrangementUtil.readExternal(arrangementRulesContainer, myLanguage); } } @@ -234,9 +231,9 @@ public class CommonCodeStyleSettings { } } - if (!myArrangementRules.isEmpty()) { + if (myArrangementSettings != null) { Element container = new Element(ARRANGEMENT_ELEMENT_NAME); - ArrangementUtil.writeExternal(container, myArrangementRules, myLanguage); + ArrangementUtil.writeExternal(container, myArrangementSettings, myLanguage); if (!container.getChildren().isEmpty()) { element.addContent(container); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementSettings.java new file mode 100644 index 000000000000..11fe3f6e93b6 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementSettings.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2012 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 com.intellij.psi.codeStyle.arrangement; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Holds arrangement rules. + *

+ * Implementations of this interface are expected to provide correct {@link #equals(Object)} & {@link #hashCode()} implementations. + * + * @author Denis Zhdanov + * @since 9/17/12 11:51 AM + */ +public interface ArrangementSettings { + + @NotNull + List getRules(); +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementRuleSerializer.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementSettingsSerializer.java similarity index 52% rename from platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementRuleSerializer.java rename to platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementSettingsSerializer.java index c568dde2f4f1..ddc7cf5a6060 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementRuleSerializer.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementSettingsSerializer.java @@ -20,40 +20,36 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Identifies a strategy that can tweak default {@link ArrangementRule arrangement rules} (de)serialization mechanism. + * Identifies a strategy that can tweak default {@link ArrangementSettings arrangement settings} (de)serialization mechanism. *

* Implementations of this interface are expected to be thread-safe. * * @author Denis Zhdanov * @since 7/18/12 10:30 AM */ -public interface ArrangementRuleSerializer { +public interface ArrangementSettingsSerializer { /** - * Allows to provide custom rule deserialization logic. This method is expected to be consistent with {@link #serialize(ArrangementRule)}. + * Allows to provide custom settings deserialization logic. This method is expected to be consistent + * with {@link #serialize(ArrangementSettings, Element)}. *

- * Note: it's save to return null if current rearranger doesn't use custom rules (rules over those + * Note: it's save to return null if current rearranger doesn't use custom settings (settings over those * located at the 'lang-api'/'lang-impl' modules). * - * @param element serialized rule - * @return rule de-serialized from the given element; - * null as an indication that current rearranger doesn't provide custom serialization logic - * for the target rule serialized at the given element, i.e. default deserialization algorithm should be used for it + * @param element serialized settings holder + * @return settings de-serialized from the given element */ @Nullable - ArrangementRule deserialize(@NotNull Element element); + ArrangementSettings deserialize(@NotNull Element element); /** - * Allows to provide custom rule serialization logic. This method is expected to be consistent with {@link #deserialize(Element)}. + * Allows to provide custom settings serialization logic. This method is expected to be consistent with {@link #deserialize(Element)}. *

- * Note: it's save to return null if current rearranger doesn't use custom rules (rules over those + * Note: it's save to return null if current rearranger doesn't use custom settings (settings over those * located at the 'lang-api'/'lang-impl' modules). * - * @param rule rule to serialize - * @return serialized rule; - * null as an indication that no custom serialization logic for the given rule - * is provided by the current rearranger + * @param settings settings to serialize + * @param holder element to hold serialized settings */ - @Nullable - Element serialize(ArrangementRule rule); + void serialize(ArrangementSettings settings, @NotNull Element holder); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java index 0d78cfeade01..b83b11ca6395 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java @@ -39,73 +39,25 @@ public class ArrangementUtil { //region Serialization - @NotNull - public static List readExternal(@NotNull Element element, @NotNull Language language) { - final List result = new ArrayList(); - ArrangementRuleSerializer serializer = getSerializer(language); - for (Object child : element.getChildren()) { - ArrangementRule rule = serializer.deserialize((Element)child); - if (rule != null) { - result.add(rule); - } - } - return result; + @Nullable + public static ArrangementSettings readExternal(@NotNull Element element, @NotNull Language language) { + ArrangementSettingsSerializer serializer = getSerializer(language); + return serializer.deserialize(element); } - public static void writeExternal(@NotNull Element element, @NotNull List rules, @NotNull Language language) { - if (rules.isEmpty()) { - return; - } - - ArrangementRuleSerializer serializer = getSerializer(language); - for (ArrangementRule rule : rules) { - Element e = serializer.serialize(rule); - if (e != null) { - element.addContent(e); - } - } + public static void writeExternal(@NotNull Element element, @NotNull ArrangementSettings settings, @NotNull Language language) { + ArrangementSettingsSerializer serializer = getSerializer(language); + serializer.serialize(settings, element); } - private static ArrangementRuleSerializer getSerializer(@NotNull Language language) { + private static ArrangementSettingsSerializer getSerializer(@NotNull Language language) { Rearranger rearranger = Rearranger.EXTENSION.forLanguage(language); - if (rearranger instanceof ArrangementRuleSerializer) { - return new CompositeArrangementRuleSerializer((ArrangementRuleSerializer)rearranger, DefaultArrangementRuleSerializer.INSTANCE); + if (rearranger instanceof ArrangementSettingsSerializer) { + return (ArrangementSettingsSerializer)rearranger; } return DefaultArrangementRuleSerializer.INSTANCE; } - private static class CompositeArrangementRuleSerializer implements ArrangementRuleSerializer { - - @NotNull private final List mySerializers = new ArrayList(); - - CompositeArrangementRuleSerializer(@NotNull ArrangementRuleSerializer ... serializers) { - mySerializers.addAll(Arrays.asList(serializers)); - } - - @Nullable - @Override - public ArrangementRule deserialize(@NotNull Element element) { - for (ArrangementRuleSerializer serializer : mySerializers) { - ArrangementRule rule = serializer.deserialize(element); - if (rule != null) { - return rule; - } - } - return null; - } - - @Nullable - @Override - public Element serialize(ArrangementRule rule) { - for (ArrangementRuleSerializer serializer : mySerializers) { - Element element = serializer.serialize(rule); - if (element != null) { - return element; - } - } - return null; - } - } //endregion @NotNull diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementRuleSerializer.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementRuleSerializer.java index 4f8fa7f664fb..16e662332292 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementRuleSerializer.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementRuleSerializer.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.codeStyle.arrangement; +import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingType; import com.intellij.psi.codeStyle.arrangement.match.DefaultArrangementEntryMatcherSerializer; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementEntryMatcher; import com.intellij.psi.codeStyle.arrangement.order.ArrangementEntryOrderType; @@ -22,51 +23,99 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; + +import java.util.List; + /** * @author Denis Zhdanov * @since 7/18/12 10:37 AM */ -public class DefaultArrangementRuleSerializer implements ArrangementRuleSerializer { +public class DefaultArrangementRuleSerializer implements ArrangementSettingsSerializer { - public static final ArrangementRuleSerializer INSTANCE = new DefaultArrangementRuleSerializer(); + public static final ArrangementSettingsSerializer INSTANCE = new DefaultArrangementRuleSerializer(); + @NotNull @NonNls private static final String GROUPS_ELEMENT_NAME = "groups"; + @NotNull @NonNls private static final String GROUP_ELEMENT_NAME = "group"; + @NotNull @NonNls private static final String RULES_ELEMENT_NAME = "rules"; @NotNull @NonNls private static final String RULE_ELEMENT_NAME = "rule"; @NotNull @NonNls private static final String MATCHER_ELEMENT_NAME = "match"; @NotNull @NonNls private static final String ORDER_TYPE_ELEMENT_NAME = "order"; @NotNull private final DefaultArrangementEntryMatcherSerializer myMatcherSerializer = new DefaultArrangementEntryMatcherSerializer(); - @Nullable @Override - public StdArrangementRule deserialize(@NotNull Element element) { - Element matcherElement = element.getChild(MATCHER_ELEMENT_NAME); - if (matcherElement == null) { - return null; + public void serialize(ArrangementSettings s, @NotNull Element holder) { + if (!(s instanceof StdArrangementSettings)) { + return; } - - StdArrangementEntryMatcher matcher = null; - for (Object o : matcherElement.getChildren()) { - matcher = myMatcherSerializer.deserialize((Element)o); - if (matcher != null) { - break; + + StdArrangementSettings settings = (StdArrangementSettings)s; + + List groupings = settings.getGroupings(); + if (!groupings.isEmpty()) { + Element groupingsElement = new Element(GROUPS_ELEMENT_NAME); + holder.addContent(groupingsElement); + for (ArrangementGroupingType group : groupings) { + groupingsElement.addContent(new Element(GROUP_ELEMENT_NAME).setText(group.toString())); } } - if (matcher == null) { - return null; + List rules = settings.getRules(); + if (!rules.isEmpty()) { + Element rulesElement = new Element(RULES_ELEMENT_NAME); + holder.addContent(rulesElement); + for (StdArrangementRule rule : rules) { + rulesElement.addContent(serialize(rule)); + } } - - Element orderTypeElement = element.getChild(ORDER_TYPE_ELEMENT_NAME); - ArrangementEntryOrderType orderType = ArrangementRule.DEFAULT_ORDER_TYPE; - if (orderTypeElement != null) { - orderType = ArrangementEntryOrderType.valueOf(orderTypeElement.getText()); - } - - return new StdArrangementRule(matcher, orderType); } @Nullable @Override + public ArrangementSettings deserialize(@NotNull Element element) { + StdArrangementSettings result = new StdArrangementSettings(); + Element groups = element.getChild(GROUPS_ELEMENT_NAME); + if (groups != null) { + for (Object group : groups.getChildren(GROUP_ELEMENT_NAME)) { + Element groupElement = (Element)group; + result.addGrouping(ArrangementGroupingType.valueOf(groupElement.getText())); + } + } + + Element rulesElement = element.getChild(RULES_ELEMENT_NAME); + if (rulesElement != null) { + for (Object o : rulesElement.getChildren(RULE_ELEMENT_NAME)) { + Element ruleElement = (Element)o; + Element matcherElement = ruleElement.getChild(MATCHER_ELEMENT_NAME); + if (matcherElement == null) { + continue; + } + + StdArrangementEntryMatcher matcher = null; + for (Object c : matcherElement.getChildren()) { + matcher = myMatcherSerializer.deserialize((Element)c); + if (matcher != null) { + break; + } + } + + if (matcher == null) { + return null; + } + + Element orderTypeElement = element.getChild(ORDER_TYPE_ELEMENT_NAME); + ArrangementEntryOrderType orderType = ArrangementRule.DEFAULT_ORDER_TYPE; + if (orderTypeElement != null) { + orderType = ArrangementEntryOrderType.valueOf(orderTypeElement.getText()); + } + result.addRule(new StdArrangementRule(matcher, orderType)); + } + } + + return result; + } + + @Nullable public Element serialize(@NotNull ArrangementRule rule) { Element matcherElement = myMatcherSerializer.serialize(rule.getMatcher()); if (matcherElement == null) { diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/Rearranger.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/Rearranger.java index 228d882c826a..2bad40ef5249 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/Rearranger.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/Rearranger.java @@ -17,6 +17,7 @@ package com.intellij.psi.codeStyle.arrangement; import com.intellij.lang.LanguageExtension; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -40,17 +41,21 @@ public interface Rearranger { LanguageExtension> EXTENSION = new LanguageExtension>("com.intellij.lang.rearranger"); /** - * Tries to wrap given element to the corresponding arrangement entry. + * Tries to wrap given element into arrangement entry at the target context. *

* This is useful in a situation when new element is generated and we're deciding where to insert it (e.g. new field is * generated and we want to insert it according to the arrangement rules like 'fields before methods'). * * @param element element to wrap into format eligible for further processing by arrangement engine - * @return arrangement entry for the given element if it's possible to perform the mapping; + * @return arrangement entry for the given element if it's possible to perform the mapping and list of arrangement entries + * available at the given context plus newly created entry for the given element; * null otherwise */ @Nullable - E wrap(@NotNull PsiElement element); + Pair> parseWithNew(@NotNull PsiElement root, + @Nullable Document document, + @NotNull Collection ranges, + @NotNull PsiElement element); /** * Allows to build rearranger-interested data for the given element. diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/StdArrangementSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/StdArrangementSettings.java new file mode 100644 index 000000000000..22004fce2a4b --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/StdArrangementSettings.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2012 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 com.intellij.psi.codeStyle.arrangement; + +import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingType; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @author Denis Zhdanov + * @since 9/17/12 11:53 AM + */ +public class StdArrangementSettings implements ArrangementSettings { + + @NotNull private final List myRules = new ArrayList(); + @NotNull private final List myGroupings = new ArrayList(); + + public StdArrangementSettings() { + } + + public StdArrangementSettings(@NotNull Collection rules) { + myRules.addAll(rules); + } + + @NotNull + @Override + public List getRules() { + return myRules; + } + + @NotNull + public List getGroupings() { + return myGroupings; + } + + public void addRule(@NotNull StdArrangementRule rule) { + myRules.add(rule); + } + + public void addGrouping(@NotNull ArrangementGroupingType grouping) { + myGroupings.add(grouping); + } + + @Override + public int hashCode() { + int result = myRules.hashCode(); + result = 31 * result + myGroupings.hashCode(); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + StdArrangementSettings settings = (StdArrangementSettings)o; + + if (!myGroupings.equals(settings.myGroupings)) return false; + if (!myRules.equals(settings.myRules)) return false; + + return true; + } +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/group/ArrangementGroupingType.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/group/ArrangementGroupingType.java new file mode 100644 index 000000000000..4778695b754c --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/group/ArrangementGroupingType.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2012 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 com.intellij.psi.codeStyle.arrangement.group; + +/** + * Enumerates available grouping types. + * + * @author Denis Zhdanov + * @since 9/17/12 11:47 AM + */ +public enum ArrangementGroupingType { + + GETTERS_AND_SETTERS, + + OVERRIDDEN_METHODS, + + UTILITY_METHODS +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java index 1f22c828bd59..412392d3bd1d 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java @@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.psi.codeStyle.arrangement.StdArrangementRule; +import com.intellij.psi.codeStyle.arrangement.StdArrangementSettings; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementEntryMatcher; import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; @@ -78,7 +79,7 @@ public class ArrangementRuleTree { private boolean myExplicitSelectionChange; private boolean mySkipSelectionChange; - public ArrangementRuleTree(@NotNull List rules, + public ArrangementRuleTree(@Nullable StdArrangementSettings settings, @NotNull List> groupingRules, @NotNull ArrangementNodeDisplayManager displayManager) { @@ -185,7 +186,7 @@ public class ArrangementRuleTree { } }); - setRules(rules); + setSettings(settings); myTree.setShowsRootHandles(false); myTree.setCellRenderer(new MyCellRenderer()); @@ -403,10 +404,10 @@ public class ArrangementRuleTree { * @return rules configured at the current tree at the moment */ @NotNull - public List getRules() { + public StdArrangementSettings getSettings() { int[] rows = myModels.keys(); Arrays.sort(rows); - List result = new ArrayList(); + List rules = new ArrayList(); ArrangementMatchCondition prevGroup = null; Set implicitGroupConditions = new HashSet(); for (int row : rows) { @@ -414,27 +415,32 @@ public class ArrangementRuleTree { ArrangementTreeNode topMost = model.getTopMost(); ArrangementMatchCondition currentGroup = topMost.getBackingCondition(); if (prevGroup != null && !prevGroup.equals(currentGroup)) { - result.add(new StdArrangementRule(new StdArrangementEntryMatcher(prevGroup))); + rules.add(new StdArrangementRule(new StdArrangementEntryMatcher(prevGroup))); implicitGroupConditions.add(prevGroup); prevGroup = null; } if (!myRoot.equals(topMost) && !topMost.equals(model.getBottomMost()) && !implicitGroupConditions.contains(currentGroup)) { prevGroup = currentGroup; } - result.add(model.getRule()); + rules.add(model.getRule()); } if (prevGroup != null) { - result.add(new StdArrangementRule(new StdArrangementEntryMatcher(prevGroup))); + rules.add(new StdArrangementRule(new StdArrangementEntryMatcher(prevGroup))); } - return result; + return new StdArrangementSettings(rules); } - public void setRules(@NotNull List rules) { + public void setSettings(@Nullable StdArrangementSettings settings) { myRenderers.clear(); myModels.clear(); while (myRoot.getChildCount() > 0) myTreeModel.removeNodeFromParent(myRoot.getFirstChild()); + if (settings == null) { + return; + } + + List rules = settings.getRules(); map(rules); expandAll(myTree, new TreePath(myRoot)); @@ -631,6 +637,7 @@ public class ArrangementRuleTree { && ((ArrangementCompositeMatchCondition)condition).getOperands().isEmpty(); } + @SuppressWarnings("MethodMayBeStatic") public void disposeUI() { Container parent = EMPTY_RENDERER.getParent(); if (parent != null) parent.remove(EMPTY_RENDERER); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java index df828d051bb0..100cccda4a82 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java @@ -25,11 +25,10 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Ref; import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.arrangement.ArrangementRule; -import com.intellij.psi.codeStyle.arrangement.Rearranger; -import com.intellij.psi.codeStyle.arrangement.StdArrangementRule; +import com.intellij.psi.codeStyle.arrangement.*; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; import com.intellij.psi.codeStyle.arrangement.settings.*; import com.intellij.ui.IdeBorderFactory; @@ -96,7 +95,7 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { toolbarControl.setBorder(IdeBorderFactory.createBorder(SideBorder.LEFT | SideBorder.TOP | SideBorder.RIGHT)); myContent.add(toolbarControl, new GridBag().weightx(1).fillCellHorizontally().coverLine()); - myRuleTree = new ArrangementRuleTree(getRules(settings), groupingRules, displayManager); + myRuleTree = new ArrangementRuleTree(getSettings(settings), groupingRules, displayManager); final Tree treeComponent = myRuleTree.getTreeComponent(); actionToolbar.setTargetComponent(treeComponent); JBScrollPane scrollPane = new JBScrollPane(treeComponent); @@ -283,26 +282,16 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { } @SuppressWarnings("unchecked") - @NotNull - private List getRules(@NotNull CodeStyleSettings settings) { - List storedRules = settings.getCommonSettings(myLanguage).getArrangementRules(); - if (storedRules.isEmpty()) { + @Nullable + private StdArrangementSettings getSettings(@NotNull CodeStyleSettings settings) { + StdArrangementSettings result = (StdArrangementSettings)settings.getCommonSettings(myLanguage).getArrangementSettings(); + if (result == null) { List defaultRules = mySettingsAware.getDefaultRules(); if (defaultRules != null) { - return defaultRules; + result = new StdArrangementSettings(defaultRules); } } - else { - // We use unchecked cast here in assumption that current rearranger is based on standard settings if it uses standard - // settings-based rule editor. - // Note: unchecked cast for the whole collection doesn't work here (compiler error). - List result = new ArrayList(); - for (ArrangementRule rule : storedRules) { - result.add((StdArrangementRule)rule); - } - return result; - } - return Collections.emptyList(); + return result; } private static void setupKeyboardActions(@NotNull ActionManager actionManager, @NotNull Tree treeComponent) { @@ -329,17 +318,17 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { @Override public boolean isModified(@NotNull CodeStyleSettings settings) { - return !getRules(settings).equals(myRuleTree.getRules()); + return !Comparing.equal(getSettings(settings), myRuleTree.getSettings()); } @Override public void apply(@NotNull CodeStyleSettings settings) { - settings.getCommonSettings(myLanguage).setArrangementRules(myRuleTree.getRules()); + settings.getCommonSettings(myLanguage).setArrangementSettings(myRuleTree.getSettings()); } @Override protected void resetImpl(@NotNull CodeStyleSettings settings) { - myRuleTree.setRules(getRules(settings)); + myRuleTree.setSettings(getSettings(settings)); } @Override diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java index 01d81c56b193..026dac863838 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java @@ -16,6 +16,7 @@ package com.intellij.psi.codeStyle.arrangement; import com.intellij.lang.Language; +import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine; @@ -44,7 +45,7 @@ public class MemberOrderService { /** * Tries to find an element at the given context which should be the previous sibling for the given 'member'element according to the - * {@link CommonCodeStyleSettings#getArrangementRules() user-defined arrangement rules}. + * {@link CommonCodeStyleSettings#getArrangementSettings() user-defined arrangement rules}. *

* E.g. the IDE might generate given 'member' element and wants to know element after which it should be inserted * @@ -64,30 +65,31 @@ public class MemberOrderService { return null; } - List rules = settings.getArrangementRules(); - if (rules.isEmpty() && rearranger instanceof ArrangementStandardSettingsAware) { - rules = ((ArrangementStandardSettingsAware)rearranger).getDefaultRules(); - } - - if (rules == null) { - return null; - } - - ArrangementEntry memberEntry = rearranger.wrap(member); - if (memberEntry == null) { - return null; + ArrangementSettings arrangementSettings = settings.getArrangementSettings(); + if (arrangementSettings == null && rearranger instanceof ArrangementStandardSettingsAware) { + List rules = ((ArrangementStandardSettingsAware)rearranger).getDefaultRules(); + if (rules != null && !rules.isEmpty()) { + arrangementSettings = new StdArrangementSettings(rules); + } } - List entries = rearranger.parse(context, null, Collections.singleton(context.getTextRange())); - if (entries.isEmpty()) { + if (arrangementSettings == null) { return null; } + Pair> pair = + rearranger.parseWithNew(context, null, Collections.singleton(context.getTextRange()), member); + if (pair == null || pair.second.isEmpty()) { + return null; + } + + ArrangementEntry memberEntry = pair.first; + List entries = pair.second; ArrangementEntry parentEntry = entries.get(0); List nonArranged = parentEntry.getChildren(); List entriesWithNew = new ArrayList(nonArranged); entriesWithNew.add(memberEntry); - List arranged = ArrangementEngine.arrange(entriesWithNew, rules); + List arranged = ArrangementEngine.arrange(entriesWithNew, arrangementSettings.getRules()); int i = arranged.indexOf(memberEntry); if (i <= 0) { diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java index 2b6178bb0eca..2cf371ffb6f3 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java @@ -26,10 +26,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.codeStyle.arrangement.ArrangementEntry; -import com.intellij.psi.codeStyle.arrangement.ArrangementRule; -import com.intellij.psi.codeStyle.arrangement.Rearranger; -import com.intellij.psi.codeStyle.arrangement.StdArrangementRule; +import com.intellij.psi.codeStyle.arrangement.*; import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.Stack; @@ -70,14 +67,15 @@ public class ArrangementEngine { } final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(file.getProject()).getCurrentSettings(); - List arrangementRules = settings.getCommonSettings(file.getLanguage()).getArrangementRules(); - if (arrangementRules.isEmpty() && rearranger instanceof ArrangementStandardSettingsAware) { + ArrangementSettings arrangementSettings = settings.getCommonSettings(file.getLanguage()).getArrangementSettings(); + if (arrangementSettings == null && rearranger instanceof ArrangementStandardSettingsAware) { List defaultRules = ((ArrangementStandardSettingsAware)rearranger).getDefaultRules(); - if (defaultRules != null) { - arrangementRules = defaultRules; + if (defaultRules != null && !defaultRules.isEmpty()) { + arrangementSettings = new StdArrangementSettings(defaultRules); } } - if (arrangementRules.isEmpty()) { + + if (arrangementSettings == null) { return; } @@ -89,7 +87,9 @@ public class ArrangementEngine { documentEx = null; } - final Context context = Context.from(rearranger, document, file, ranges, arrangementRules, settings); + final Context context = Context.from( + rearranger, document, file, ranges, arrangementSettings.getRules(), settings + ); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override diff --git a/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.groovy b/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.groovy index 9f29e2288d55..9dbbcc7eede1 100644 --- a/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.groovy +++ b/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.groovy @@ -74,7 +74,7 @@ abstract class AbstractRearrangerTest extends LightPlatformCodeInsightFixtureTes protected void doTest(@NotNull String initial, @NotNull String expected, - @NotNull List rules, + @NotNull List rules, Collection ranges = null) { def (String textToUse, List rangesToUse) = parseRanges(initial) @@ -89,7 +89,7 @@ abstract class AbstractRearrangerTest extends LightPlatformCodeInsightFixtureTes myFixture.configureByText(fileType, textToUse) def settings = CodeStyleSettingsManager.getInstance(myFixture.project).currentSettings.getCommonSettings(language) - settings.arrangementRules = rules + settings.arrangementSettings = new StdArrangementSettings(rules) ArrangementEngine engine = ServiceManager.getService(myFixture.project, ArrangementEngine) engine.arrange(myFixture.file, rangesToUse); junit.framework.Assert.assertEquals(expected, myFixture.editor.document.text);