IDEA-19061 Integrate the Rearranger-plugin into core-IDEA

'Grouping rules' are now part of the arrangement settings
This commit is contained in:
Denis.Zhdanov
2012-09-17 17:03:37 +04:00
parent 36aa395e84
commit 63264bd2ec
14 changed files with 340 additions and 188 deletions
@@ -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<JavaElementArrangementEntry>,
@Nullable
@Override
public JavaElementArrangementEntry wrap(@NotNull PsiElement element) {
List<JavaElementArrangementEntry> result = new ArrayList<JavaElementArrangementEntry>();
element.accept(new JavaArrangementVisitor(result, null, Collections.singleton(element.getTextRange())));
return result.size() == 1 ? result.get(0) : null;
public Pair<JavaElementArrangementEntry, List<JavaElementArrangementEntry>> parseWithNew(@NotNull PsiElement root,
@Nullable Document document,
@NotNull Collection<TextRange> ranges,
@NotNull PsiElement element)
{
List<JavaElementArrangementEntry> existingEntries = new ArrayList<JavaElementArrangementEntry>();
root.accept(new JavaArrangementVisitor(existingEntries, document, ranges));
List<JavaElementArrangementEntry> newEntry = new ArrayList<JavaElementArrangementEntry>();
element.accept(new JavaArrangementVisitor(newEntry, document, Collections.singleton(element.getTextRange())));
if (newEntry.size() != 1) {
return null;
}
return Pair.create(newEntry.get(0), existingEntries);
}
@NotNull
@@ -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<ArrangementRule> myArrangementRules
= new ArrayList<ArrangementRule>();
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<ArrangementRule> getArrangementRules() {
return myArrangementRules;
@Nullable
public ArrangementSettings getArrangementSettings() {
return myArrangementSettings;
}
public void setArrangementRules(@NotNull List<? extends ArrangementRule> 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);
}
@@ -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.
* <p/>
* 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<? extends ArrangementRule> getRules();
}
@@ -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.
* <p/>
* 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)}.
* <p/>
* <b>Note:</b> it's save to return <code>null</code> if current rearranger doesn't use custom rules (rules over those
* <b>Note:</b> it's save to return <code>null</code> if current rearranger doesn't use custom settings (settings over those
* located at the <code>'lang-api'</code>/<code>'lang-impl'</code> modules).
*
* @param element serialized rule
* @return rule de-serialized from the given element;
* <code>null</code> 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)}.
* <p/>
* <b>Note:</b> it's save to return <code>null</code> if current rearranger doesn't use custom rules (rules over those
* <b>Note:</b> it's save to return <code>null</code> if current rearranger doesn't use custom settings (settings over those
* located at the <code>'lang-api'</code>/<code>'lang-impl'</code> modules).
*
* @param rule rule to serialize
* @return serialized rule;
* <code>null</code> 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);
}
@@ -39,73 +39,25 @@ public class ArrangementUtil {
//region Serialization
@NotNull
public static List<ArrangementRule> readExternal(@NotNull Element element, @NotNull Language language) {
final List<ArrangementRule> result = new ArrayList<ArrangementRule>();
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<ArrangementRule> 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<ArrangementRuleSerializer> mySerializers = new ArrayList<ArrangementRuleSerializer>();
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
@@ -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<ArrangementGroupingType> 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<StdArrangementRule> 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) {
@@ -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<E extends ArrangementEntry> {
LanguageExtension<Rearranger<?>> EXTENSION = new LanguageExtension<Rearranger<?>>("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.
* <p/>
* 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;
* <code>null</code> otherwise
*/
@Nullable
E wrap(@NotNull PsiElement element);
Pair<E, List<E>> parseWithNew(@NotNull PsiElement root,
@Nullable Document document,
@NotNull Collection<TextRange> ranges,
@NotNull PsiElement element);
/**
* Allows to build rearranger-interested data for the given element.
@@ -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<StdArrangementRule> myRules = new ArrayList<StdArrangementRule>();
@NotNull private final List<ArrangementGroupingType> myGroupings = new ArrayList<ArrangementGroupingType>();
public StdArrangementSettings() {
}
public StdArrangementSettings(@NotNull Collection<StdArrangementRule> rules) {
myRules.addAll(rules);
}
@NotNull
@Override
public List<StdArrangementRule> getRules() {
return myRules;
}
@NotNull
public List<ArrangementGroupingType> 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;
}
}
@@ -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
}
@@ -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<StdArrangementRule> rules,
public ArrangementRuleTree(@Nullable StdArrangementSettings settings,
@NotNull List<Set<ArrangementMatchCondition>> 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<StdArrangementRule> getRules() {
public StdArrangementSettings getSettings() {
int[] rows = myModels.keys();
Arrays.sort(rows);
List<StdArrangementRule> result = new ArrayList<StdArrangementRule>();
List<StdArrangementRule> rules = new ArrayList<StdArrangementRule>();
ArrangementMatchCondition prevGroup = null;
Set<ArrangementMatchCondition> implicitGroupConditions = new HashSet<ArrangementMatchCondition>();
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<StdArrangementRule> rules) {
public void setSettings(@Nullable StdArrangementSettings settings) {
myRenderers.clear();
myModels.clear();
while (myRoot.getChildCount() > 0)
myTreeModel.removeNodeFromParent(myRoot.getFirstChild());
if (settings == null) {
return;
}
List<StdArrangementRule> 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);
@@ -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<StdArrangementRule> getRules(@NotNull CodeStyleSettings settings) {
List<ArrangementRule> 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<StdArrangementRule> 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<StdArrangementRule> result = new ArrayList<StdArrangementRule>();
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
@@ -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}.
* <p/>
* 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<? extends ArrangementRule> 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<StdArrangementRule> rules = ((ArrangementStandardSettingsAware)rearranger).getDefaultRules();
if (rules != null && !rules.isEmpty()) {
arrangementSettings = new StdArrangementSettings(rules);
}
}
List<? extends ArrangementEntry> entries = rearranger.parse(context, null, Collections.singleton(context.getTextRange()));
if (entries.isEmpty()) {
if (arrangementSettings == null) {
return null;
}
Pair<? extends ArrangementEntry,? extends List<? extends ArrangementEntry>> pair =
rearranger.parseWithNew(context, null, Collections.singleton(context.getTextRange()), member);
if (pair == null || pair.second.isEmpty()) {
return null;
}
ArrangementEntry memberEntry = pair.first;
List<? extends ArrangementEntry> entries = pair.second;
ArrangementEntry parentEntry = entries.get(0);
List<? extends ArrangementEntry> nonArranged = parentEntry.getChildren();
List<ArrangementEntry> entriesWithNew = new ArrayList<ArrangementEntry>(nonArranged);
entriesWithNew.add(memberEntry);
List<ArrangementEntry> arranged = ArrangementEngine.arrange(entriesWithNew, rules);
List<ArrangementEntry> arranged = ArrangementEngine.arrange(entriesWithNew, arrangementSettings.getRules());
int i = arranged.indexOf(memberEntry);
if (i <= 0) {
@@ -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<? extends ArrangementRule> 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<StdArrangementRule> 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<? extends ArrangementEntry> context = Context.from(rearranger, document, file, ranges, arrangementRules, settings);
final Context<? extends ArrangementEntry> context = Context.from(
rearranger, document, file, ranges, arrangementSettings.getRules(), settings
);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
@@ -74,7 +74,7 @@ abstract class AbstractRearrangerTest extends LightPlatformCodeInsightFixtureTes
protected void doTest(@NotNull String initial,
@NotNull String expected,
@NotNull List<ArrangementRule> rules,
@NotNull List<StdArrangementRule> rules,
Collection<TextRange> ranges = null)
{
def (String textToUse, List<TextRange> 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);