diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java index 5dd4279b3cd1..36aff625f280 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java @@ -329,18 +329,10 @@ public class JavaDebugProcess extends XDebugProcess { private volatile boolean myAutoModeEnabled; public AutoVarsSwitchAction() { - super("", "", AllIcons.Debugger.AutoVariablesMode); + super(DebuggerBundle.message("action.auto.variables.mode"), DebuggerBundle.message("action.auto.variables.mode.description"), null); myAutoModeEnabled = DebuggerSettings.getInstance().AUTO_VARIABLES_MODE; } - @Override - public void update(@NotNull final AnActionEvent e) { - super.update(e); - final Presentation presentation = e.getPresentation(); - final boolean autoModeEnabled = Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY)); - presentation.setText(autoModeEnabled ? "All-Variables Mode" : "Auto-Variables Mode"); - } - @Override public boolean isSelected(AnActionEvent e) { return myAutoModeEnabled; @@ -356,15 +348,13 @@ public class JavaDebugProcess extends XDebugProcess { private static class WatchLastMethodReturnValueAction extends ToggleAction { private volatile boolean myWatchesReturnValues; - private final String myTextEnable; + private final String myText; private final String myTextUnavailable; - private final String myMyTextDisable; public WatchLastMethodReturnValueAction() { super("", DebuggerBundle.message("action.watch.method.return.value.description"), null); myWatchesReturnValues = DebuggerSettings.getInstance().WATCH_RETURN_VALUES; - myTextEnable = DebuggerBundle.message("action.watches.method.return.value.enable"); - myMyTextDisable = DebuggerBundle.message("action.watches.method.return.value.disable"); + myText = DebuggerBundle.message("action.watches.method.return.value.enable"); myTextUnavailable = DebuggerBundle.message("action.watches.method.return.value.unavailable.reason"); } @@ -372,12 +362,10 @@ public class JavaDebugProcess extends XDebugProcess { public void update(@NotNull final AnActionEvent e) { super.update(e); final Presentation presentation = e.getPresentation(); - final boolean watchValues = Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY)); DebugProcessImpl process = getCurrentDebugProcess(e.getProject()); - final String actionText = watchValues ? myMyTextDisable : myTextEnable; if (process == null || process.canGetMethodReturnValue()) { presentation.setEnabled(true); - presentation.setText(actionText); + presentation.setText(myText); } else { presentation.setEnabled(false); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index dcc54be00a2c..acdf8687dea2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -27,7 +27,7 @@ import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.engine.events.SuspendContextCommandImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.settings.ToStringBasedRenderer; +import com.intellij.debugger.ui.tree.render.ToStringBasedRenderer; import com.intellij.debugger.ui.impl.DebuggerTreeRenderer; import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.*; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java index 4413c8384da5..633e3f5cf7bf 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -20,13 +20,13 @@ */ package com.intellij.debugger.engine.evaluation.expression; +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; -import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl; -import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.openapi.project.Project; import com.sun.jdi.*; @@ -50,7 +50,7 @@ class ArrayAccessEvaluator implements Evaluator { throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.array.reference.expected")); } myEvaluatedArrayReference = (ArrayReference)arrayValue; - if (!DebuggerUtilsEx.isInteger(indexValue)) { + if (!DebuggerUtils.isInteger(indexValue)) { throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.index.expression")); } myEvaluatedIndex = ((PrimitiveValue)indexValue).intValue(); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java index bb36ecf04672..7387c7ffb0b2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java @@ -20,6 +20,7 @@ */ package com.intellij.debugger.engine.evaluation.expression; +import com.intellij.Patches; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebugProcessImpl; @@ -180,7 +181,7 @@ public class MethodEvaluator implements Evaluator { return debugProcess.invokeInstanceMethod(context, objRef, jdiMethod, args, ObjectReference.INVOKE_NONVIRTUAL); } // fix for default methods in interfaces, see IDEA-124066 - if (myCheckDefaultInterfaceMethod && jdiMethod.declaringType() instanceof InterfaceType) { + if (Patches.JDK_BUG_ID_8042123 && myCheckDefaultInterfaceMethod && jdiMethod.declaringType() instanceof InterfaceType) { try { return invokeDefaultMethod(debugProcess, context, objRef, myMethodName); } catch (EvaluateException e) { diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java index 5874f8b33b86..5e4308884471 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java @@ -361,7 +361,8 @@ public class NodeRendererSettings implements PersistentStateComponent { return renderer; } - private ExpressionChildrenRenderer createExpressionChildrenRenderer(@NonNls String expressionText, @NonNls String childrenExpandableText) { + public static ExpressionChildrenRenderer createExpressionChildrenRenderer(@NonNls String expressionText, + @NonNls String childrenExpandableText) { final ExpressionChildrenRenderer childrenRenderer = new ExpressionChildrenRenderer(); childrenRenderer.setChildrenExpression(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expressionText, "", StdFileTypes.JAVA)); if (childrenExpandableText != null) { @@ -370,7 +371,7 @@ public class NodeRendererSettings implements PersistentStateComponent { return childrenRenderer; } - private EnumerationChildrenRenderer createEnumerationChildrenRenderer(@NonNls String[][] expressions) { + private static EnumerationChildrenRenderer createEnumerationChildrenRenderer(@NonNls String[][] expressions) { final EnumerationChildrenRenderer childrenRenderer = new EnumerationChildrenRenderer(); if (expressions != null && expressions.length > 0) { final ArrayList> childrenList = new ArrayList>(expressions.length); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java index 584b09bca900..bf6bc9c9bd1c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -20,7 +20,6 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.tree.ArrayElementDescriptor; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; @@ -31,8 +30,6 @@ import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.Value; public class ArrayElementDescriptorImpl extends ValueDescriptorImpl implements ArrayElementDescriptor{ - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl"); - private final int myIndex; private final ArrayReference myArray; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ColorObjectRenderer.java similarity index 95% rename from java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ColorObjectRenderer.java index 420638ed0c5e..31bf6f0981d7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ColorObjectRenderer.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.util.ui.ColorIcon; import com.sun.jdi.*; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java index 68608c82c67b..1af0b6acb5da 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java @@ -33,6 +33,7 @@ import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiExpression; import com.sun.jdi.BooleanValue; import com.sun.jdi.Value; @@ -148,7 +149,7 @@ public class ExpressionChildrenRenderer extends ReferenceRenderer implements Chi expressionValue, context); } - private NodeRenderer getChildrenRenderer(Value childrenValue, ValueDescriptor parentDescriptor) { + private static NodeRenderer getChildrenRenderer(Value childrenValue, ValueDescriptor parentDescriptor) { NodeRenderer renderer = getLastChildrenRenderer(parentDescriptor); if (renderer == null || childrenValue == null || !renderer.isApplicable(childrenValue.type())) { renderer = DebugProcessImpl.getDefaultRenderer(childrenValue != null ? childrenValue.type() : null); @@ -160,7 +161,7 @@ public class ExpressionChildrenRenderer extends ReferenceRenderer implements Chi public boolean isExpandable(Value value, final EvaluationContext context, NodeDescriptor parentDescriptor) { final EvaluationContext evaluationContext = context.createEvaluationContext(value); - if(!"".equals(myChildrenExpandable.getReferenceExpression().getText())) { + if(!StringUtil.isEmpty(myChildrenExpandable.getReferenceExpression().getText())) { try { Value expanded = myChildrenExpandable.getEvaluator(evaluationContext.getProject()).evaluate(evaluationContext); if(expanded instanceof BooleanValue) { @@ -174,9 +175,7 @@ public class ExpressionChildrenRenderer extends ReferenceRenderer implements Chi try { Value children = evaluateChildren(evaluationContext, parentDescriptor); - - ChildrenRenderer defaultChildrenRenderer = ((DebugProcessImpl)evaluationContext.getDebugProcess()).getDefaultRenderer(value.type()); - + ChildrenRenderer defaultChildrenRenderer = DebugProcessImpl.getDefaultRenderer(value.type()); return defaultChildrenRenderer.isExpandable(children, evaluationContext, parentDescriptor); } catch (EvaluateException e) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/FileObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/FileObjectRenderer.java new file mode 100644 index 000000000000..9a03f6b0af57 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/FileObjectRenderer.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2015 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.debugger.ui.tree.render; + +import com.intellij.debugger.settings.NodeRendererSettings; + +/** + * @author egor + */ +public class FileObjectRenderer extends ToStringBasedRenderer { + public FileObjectRenderer(final NodeRendererSettings rendererSettings) { + super(rendererSettings, "File", null, NodeRendererSettings.createExpressionChildrenRenderer("listFiles()", null)); + setClassName("java.io.File"); + setEnabled(true); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java similarity index 96% rename from java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java index 614430311377..eccc01d16e03 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.FullValueEvaluatorProvider; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.sun.jdi.*; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java similarity index 95% rename from java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java index 2850a85c2f6e..c9b5d635fffb 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.FullValueEvaluatorProvider; @@ -21,9 +21,9 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.DebuggerUtilsImpl; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.icons.AllIcons; import com.intellij.xdebugger.frame.XFullValueEvaluator; import org.jetbrains.annotations.Nullable; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java similarity index 96% rename from java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java index b6cb26dcdba3..e511a6aca5a8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebugProcess; @@ -22,6 +22,8 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.ClassLoadingUtils; +import com.intellij.debugger.settings.CustomPopupFullValueEvaluator; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.rt.debugger.ImageSerializer; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringBasedRenderer.java similarity index 95% rename from java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringBasedRenderer.java index 9db4db739fb9..3fc5070ec15b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringBasedRenderer.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.tree.ValueDescriptor; import com.intellij.debugger.ui.tree.render.*; diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java index ed1c71dd095f..d48d6f6be400 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java @@ -25,6 +25,7 @@ import com.intellij.util.concurrency.AtomicFieldUpdater; import gnu.trove.TLongHashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; @@ -42,7 +43,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; */ abstract class IntervalTreeImpl extends RedBlackTree implements IntervalTree { private int keySize; // number of all intervals, counting all duplicates, some of them maybe gced - protected final ReadWriteLock l = new ReentrantReadWriteLock(); + final ReadWriteLock l = new ReentrantReadWriteLock(); protected abstract int compareEqualStartIntervals(@NotNull IntervalNode i1, @NotNull IntervalNode i2); private final ReferenceQueue myReferenceQueue = new ReferenceQueue(); @@ -52,9 +53,9 @@ abstract class IntervalTreeImpl extends RedBlackTree< private volatile int myStart; private volatile int myEnd; private static final byte ATTACHED_TO_TREE_FLAG = COLOR_MASK <<1; // true if the node is inserted to the tree - protected final List> intervals; + final List> intervals; int maxEnd; // max of all intervalEnd()s among all children. - protected int delta; // delta of startOffset. getStartOffset() = myStartOffset + Sum of deltas up to root + int delta; // delta of startOffset. getStartOffset() = myStartOffset + Sum of deltas up to root private volatile long cachedDeltaUpToRoot; // field (packed to long for atomicity) containing deltaUpToRoot, node modCount and allDeltasUpAreNull flag // fields are packed as following @@ -62,6 +63,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< // private int deltaUpToRoot; // sum of all deltas up to the root (including this node' delta). Has valid value only if modCount == IntervalTreeImpl.this.modCount // private boolean allDeltasUpAreNull; // true if all deltas up the tree (including this node) are 0. Has valid value only if modCount == IntervalTreeImpl.this.modCount + @NotNull private final IntervalTreeImpl myIntervalTree; public IntervalNode(@NotNull IntervalTreeImpl intervalTree, @NotNull E key, int start, int end) { @@ -170,7 +172,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } private static class WeakReferencedGetter extends WeakReference implements Getter { - private WeakReferencedGetter(T referent, ReferenceQueue q) { + private WeakReferencedGetter(@NotNull T referent, @NotNull ReferenceQueue q) { super(referent, q); } @@ -290,6 +292,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return myEnd; } + @NotNull public IntervalTreeImpl getTree() { return myIntervalTree; } @@ -373,12 +376,12 @@ abstract class IntervalTreeImpl extends RedBlackTree< private void assertUnderWriteLock() { assert isAcquired(l.writeLock()) : l.writeLock(); } - private static boolean isAcquired(Lock l) { + private static boolean isAcquired(@NotNull Lock l) { String s = l.toString(); return s.contains("Locked by thread"); } - private void pushDeltaFromRoot(IntervalNode node) { + private void pushDeltaFromRoot(@Nullable IntervalNode node) { if (node != null) { long packedOffsets = node.cachedDeltaUpToRoot; if (IntervalNode.allDeltasUpAreNull(packedOffsets) && node.isValid() && IntervalNode.modCount(packedOffsets) == modCount) return; @@ -390,7 +393,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< @NotNull protected abstract IntervalNode createNewNode(@NotNull T key, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer); protected abstract IntervalNode lookupNode(@NotNull T key); - protected abstract void setNode(@NotNull T key, IntervalNode node); + protected abstract void setNode(@NotNull T key, @Nullable IntervalNode node); private int compareNodes(@NotNull IntervalNode i1, int delta1, @NotNull IntervalNode i2, int delta2, @NotNull List> invalid) { if (!i2.hasAliveKey(false)) { @@ -411,14 +414,16 @@ abstract class IntervalTreeImpl extends RedBlackTree< try { l.readLock().lock(); checkMax(true); - return process(getRoot(), processor, modCount); + return process(getRoot(), modCount, processor); } finally { l.readLock().unlock(); } } - private boolean process(final IntervalNode root, final Processor processor, final int modCountBefore) { + private boolean process(@Nullable IntervalNode root, + final int modCountBefore, + @NotNull final Processor processor) { if (root == null) return true; WalkingState.TreeGuide> guide = getGuide(); @@ -437,19 +442,19 @@ abstract class IntervalTreeImpl extends RedBlackTree< try { l.readLock().lock(); checkMax(true); - return processOverlappingWith(getRoot(), start, end, processor, modCount, 0); + return processOverlappingWith(getRoot(), start, end, modCount, 0, processor); } finally { l.readLock().unlock(); } } - private boolean processOverlappingWith(IntervalNode root, + private boolean processOverlappingWith(@Nullable IntervalNode root, int start, int end, - Processor processor, int modCountBefore, - int deltaUpToRootExclusive) { + int deltaUpToRootExclusive, + @NotNull Processor processor) { if (root == null) { return true; } @@ -460,7 +465,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // right of the rightmost interval in the subtree } - if (!processOverlappingWith(root.getLeft(), start, end, processor, modCountBefore, delta)) return false; + if (!processOverlappingWith(root.getLeft(), start, end, modCountBefore, delta, processor)) return false; int myStartOffset = root.intervalStart() + delta; int myEndOffset = root.intervalEnd() + delta; boolean overlaps = Math.max(myStartOffset, start) <= Math.min(myEndOffset, end); @@ -473,25 +478,25 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // left of the root, cant be in the right subtree } - return processOverlappingWith(root.getRight(), start, end, processor, modCountBefore, delta); + return processOverlappingWith(root.getRight(), start, end, modCountBefore, delta, processor); } boolean processOverlappingWithOutside(int start, int end, @NotNull Processor processor) { try { l.readLock().lock(); checkMax(true); - return processOverlappingWithOutside(getRoot(), start, end, processor, modCount, 0); + return processOverlappingWithOutside(getRoot(), start, end, modCount, 0, processor); } finally { l.readLock().unlock(); } } - private boolean processOverlappingWithOutside(IntervalNode root, + private boolean processOverlappingWithOutside(@Nullable IntervalNode root, int start, int end, - @NotNull Processor processor, int modCountBefore, - int deltaUpToRootExclusive) { + int deltaUpToRootExclusive, + @NotNull Processor processor) { if (root == null) { return true; } @@ -502,7 +507,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< int rootStartOffset = root.intervalStart() + delta; int rootEndOffset = root.intervalEnd() + delta; - if (!processOverlappingWithOutside(root.getLeft(), start, end, processor, modCountBefore, delta)) return false; + if (!processOverlappingWithOutside(root.getLeft(), start, end, modCountBefore, delta, processor)) return false; boolean toProcess = rootStartOffset < start || rootEndOffset > end; if (toProcess) { @@ -512,7 +517,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< if (rootStartOffset >= start && rootMaxEnd <= end) return true; // cant intersect outside - return processOverlappingWithOutside(root.getRight(), start, end, processor, modCountBefore, delta); + return processOverlappingWithOutside(root.getRight(), start, end, modCountBefore, delta, processor); } @@ -521,17 +526,17 @@ abstract class IntervalTreeImpl extends RedBlackTree< try { l.readLock().lock(); checkMax(true); - return processContaining(getRoot(), offset, processor, modCount, 0); + return processContaining(getRoot(), offset, modCount, 0, processor); } finally { l.readLock().unlock(); } } - private boolean processContaining(IntervalNode root, + private boolean processContaining(@Nullable IntervalNode root, int offset, - Processor processor, int modCountBefore, - int deltaUpToRootExclusive) { + int deltaUpToRootExclusive, + @NotNull Processor processor) { if (root == null) { return true; } @@ -541,7 +546,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // right of the rightmost interval in the subtree } - if (!processContaining(root.getLeft(), offset, processor, modCountBefore, delta)) return false; + if (!processContaining(root.getLeft(), offset, modCountBefore, delta, processor)) return false; int myStartOffset = root.intervalStart() + delta; int myEndOffset = root.intervalEnd() + delta; boolean overlaps = myStartOffset <= offset && offset < myEndOffset; @@ -555,7 +560,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // left of the root, cant be in the right subtree } - return processContaining(root.getRight(), offset, processor, modCountBefore, delta); + return processContaining(root.getRight(), offset, modCountBefore, delta, processor); } interface PeekableIterator extends DisposableIterator { @@ -608,7 +613,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return new PeekableIterator() { private IntervalNode currentNode = firstOverlap; private int deltaUpToRootExclusive = firstOverlapDelta-firstOverlap.delta; - private int indexInCurrentList = 0; + private int indexInCurrentList; private T current; @Override @@ -717,7 +722,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } - private boolean overlaps(IntervalNode root, @NotNull TextRangeInterval rangeInterval, int deltaUpToRootExclusive) { + private boolean overlaps(@Nullable IntervalNode root, @NotNull TextRangeInterval rangeInterval, int deltaUpToRootExclusive) { if (root == null) return false; int delta = root.delta + deltaUpToRootExclusive; int start = root.intervalStart() + delta; @@ -725,6 +730,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return rangeInterval.intersects(start, end); } + @NotNull IntervalNode findOrInsert(@NotNull IntervalNode node) { assertUnderWriteLock(); node.setRed(); @@ -789,7 +795,11 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } + @NotNull public IntervalTreeImpl.IntervalNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + if (firingBeforeRemove) { + throw new IncorrectOperationException("Must not add rangemarker from within beforeRemoved listener"); + } try { l.writeLock().lock(); checkMax(true); @@ -852,13 +862,13 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns real (minStart, maxStart, maxEnd) - private IntTrinity checkMax(IntervalNode root, + private IntTrinity checkMax(@Nullable IntervalNode root, int deltaUpToRootExclusive, boolean assertInvalid, - AtomicBoolean allValid, - int[] keyCounter, - int[] nodeCounter, - TLongHashSet ids, + @NotNull AtomicBoolean allValid, + @NotNull int[] keyCounter, + @NotNull int[] nodeCounter, + @NotNull TLongHashSet ids, boolean allDeltasUpAreNull) { if (root == null) return new IntTrinity(Integer.MAX_VALUE,Integer.MIN_VALUE,Integer.MIN_VALUE); long packedOffsets = root.cachedDeltaUpToRoot; @@ -914,8 +924,9 @@ abstract class IntervalTreeImpl extends RedBlackTree< return new IntTrinity(minStart, maxStart, root.maxEnd + delta); } + @NotNull @Override - protected Node maximumNode(Node n) { + protected Node maximumNode(@NotNull Node n) { IntervalNode root = (IntervalNode)n; pushDelta(root.getParent()); pushDelta(root); @@ -926,7 +937,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return root; } - protected void checkBelongsToTheTree(T interval, boolean assertInvalid) { + protected void checkBelongsToTheTree(@NotNull T interval, boolean assertInvalid) { IntervalNode root = lookupNode(interval); if (root == null) return; assert root.getTree() == this : root.getTree() +"; this: "+this; @@ -966,7 +977,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< IntervalNode node = lookupNode(interval); if (node == null) return false; - reportInvalidation(interval, "Explicit Dispose"); + beforeRemove(interval, "Explicit Dispose"); node.removeInterval(interval); setNode(interval, null); @@ -1005,7 +1016,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns true if all deltas involved are still 0 - boolean pushDelta(IntervalNode root) { + boolean pushDelta(@Nullable IntervalNode root) { if (root == null || !root.isValid()) return true; IntervalNode parent = root.getParent(); assertAllDeltasAreNull(parent); @@ -1026,7 +1037,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns true if all deltas involved are still 0 - private boolean incDelta(IntervalNode root, int delta) { + private boolean incDelta(@Nullable IntervalNode root, int delta) { if (root == null) return true; if (root.isValid()) { int newDelta = root.changeDelta(delta); @@ -1041,7 +1052,8 @@ abstract class IntervalTreeImpl extends RedBlackTree< } @Override - protected IntervalNode swapWithMaxPred(Node root, Node maxPred) { + @NotNull + protected IntervalNode swapWithMaxPred(@NotNull Node root, @NotNull Node maxPred) { checkMax(false); IntervalNode a = (IntervalNode)root; IntervalNode d = (IntervalNode)maxPred; @@ -1068,7 +1080,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< assert d.delta == 0 : d.delta; return a; } - private void swapNodes(IntervalNode n1, IntervalNode n2) { + private void swapNodes(@NotNull IntervalNode n1, @NotNull IntervalNode n2) { IntervalNode l1 = n1.getLeft(); IntervalNode r1 = n1.getRight(); IntervalNode p1 = n1.getParent(); @@ -1102,7 +1114,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns real max endOffset of all intervals below - private int maxEndOf(IntervalNode node, int deltaUpToRootExclusive) { + private int maxEndOf(@Nullable IntervalNode node, int deltaUpToRootExclusive) { if (node == null) { return 0; } @@ -1121,7 +1133,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< node.maxEnd = realMax - deltaUpToRoot; } - private void correctMaxUp(IntervalNode node) { + private void correctMaxUp(@Nullable IntervalNode node) { int delta = node == null ? 0 : node.computeDeltaUpToRoot(); assert delta == 0 : delta; while (node != null) { @@ -1136,7 +1148,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } @Override - protected void rotateRight(Node n) { + protected void rotateRight(@NotNull Node n) { checkMax(false); IntervalNode node1 = (IntervalNode)n; IntervalNode node2 = node1.getLeft(); @@ -1162,7 +1174,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } @Override - protected void rotateLeft(Node n) { + protected void rotateLeft(@NotNull Node n) { checkMax(false); IntervalNode node1 = (IntervalNode)n; IntervalNode node2 = node1.getLeft(); @@ -1201,7 +1213,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } - private void assertAllDeltasAreNull(IntervalNode node) { + private void assertAllDeltasAreNull(@Nullable IntervalNode node) { if (node == null) return; if (!node.isValid()) return; assert node.delta == 0; @@ -1209,7 +1221,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< assert IntervalNode.modCount(packedOffsets) != modCount || IntervalNode.allDeltasUpAreNull(packedOffsets); } - private IntervalNode findMinOverlappingWith(IntervalNode root, Interval interval, int modCountBefore, int deltaUpToRootExclusive) { + private IntervalNode findMinOverlappingWith(@Nullable IntervalNode root, @NotNull Interval interval, int modCountBefore, int deltaUpToRootExclusive) { if (root == null) { return null; } @@ -1235,7 +1247,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return findMinOverlappingWith(root.getRight(), interval, modCountBefore, delta); } - void changeData(T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + void changeData(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { try { l.writeLock().lock(); @@ -1284,14 +1296,14 @@ abstract class IntervalTreeImpl extends RedBlackTree< @Override public void clear() { + l.writeLock().lock(); process(new Processor() { @Override public boolean process(T t) { - reportInvalidation(t, "Clear all"); + beforeRemove(t, "Clear all"); return true; } }); - l.writeLock().lock(); try { super.clear(); keySize = 0; @@ -1301,23 +1313,39 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } - private void collectGced(IntervalNode root, List> gced) { + private void collectGced(@Nullable IntervalNode root, @NotNull List> gced) { if (root == null) return; - if (!root.hasAliveKey(true)) gced.add(root); + if (!root.hasAliveKey(true)) { + gced.add(root); + } collectGced(root.getLeft(), gced); collectGced(root.getRight(), gced); } private void printSorted() { printSorted(getRoot());} - private void printSorted(IntervalNode root) { + private void printSorted(@Nullable IntervalNode root) { if (root == null) return; printSorted(root.getLeft()); System.out.println(root); printSorted(root.getRight()); } - void reportInvalidation(T markerEx, @NonNls Object reason) { + void fireBeforeRemoved(@NotNull T markerEx, @NotNull @NonNls Object reason) { + } + + private boolean firingBeforeRemove; // accessed under l.writeLock() only + void beforeRemove(@NotNull T markerEx, @NonNls @NotNull Object reason) { + if (firingBeforeRemove) { + throw new IllegalStateException(); + } + firingBeforeRemove = true; + try { + fireBeforeRemoved(markerEx, reason); + } + finally { + firingBeforeRemove = false; + } } private static class IntervalTreeGuide implements WalkingState.TreeGuide> { @@ -1348,6 +1376,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } private static final IntervalTreeGuide INTERVAL_TREE_GUIDE_INSTANCE = new IntervalTreeGuide(); + @NotNull private static WalkingState.TreeGuide> getGuide() { //noinspection unchecked return (WalkingState.TreeGuide)INTERVAL_TREE_GUIDE_INSTANCE; @@ -1358,7 +1387,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return maxHeight(root); } - private int maxHeight(Node root) { + private int maxHeight(@Nullable Node root) { return root == null ? 0 : 1 + Math.max(maxHeight(root.left), maxHeight(root.right)); } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java index 59c124698166..915bd1723883 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -15,6 +15,7 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.impl.event.DocumentEventImpl; @@ -43,6 +44,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { private void storeLinesAndCols(DocumentEvent e) { // document might have been changed already int startOffset = getStartOffset(); + Document myDocument = getDocument(); if (startOffset <= myDocument.getTextLength()) { myStartLine = myDocument.getLineNumber(startOffset); myStartColumn = startOffset - myDocument.getLineStartOffset(myStartLine); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java index 8e3cdcdd8567..e4d4199b3de8 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -27,8 +27,8 @@ import org.jetbrains.annotations.NotNull; public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx, MutableInterval { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerImpl"); - protected final DocumentEx myDocument; - protected RangeMarkerTree.RMNode myNode; + private final DocumentEx myDocument; + RangeMarkerTree.RMNode myNode; private final long myId; private static final StripedIDGenerator counter = new StripedIDGenerator(); @@ -89,7 +89,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx return intervalEnd() + (node == null ? 0 : node.computeDeltaUpToRoot()); } - public void invalidate(@NotNull final Object reason) { + void invalidate(@NotNull final Object reason) { setValid(false); RangeMarkerTree.RMNode node = myNode; @@ -97,7 +97,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx node.processAliveKeys(new Processor() { @Override public boolean process(RangeMarkerEx markerEx) { - myNode.getTree().reportInvalidation(markerEx, reason); + myNode.getTree().beforeRemove(markerEx, reason); return true; } }); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java index 5df198263512..d27218eefbcf 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java @@ -29,6 +29,7 @@ import com.intellij.openapi.util.Segment; import com.intellij.util.Processor; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -88,16 +89,16 @@ public class RangeMarkerTree extends IntervalTreeImpl addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { - RangeMarkerImpl marker = (RangeMarkerImpl)interval; - marker.setValid(true); - RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); + interval.setValid(true); + RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); if (DEBUG && !ApplicationInfoImpl.isInPerformanceTest() && node.intervals.size() > DUPLICATE_LIMIT) { l.readLock().lock(); @@ -136,18 +137,20 @@ public class RangeMarkerTree extends IntervalTreeImpl lookupNode(@NotNull T key) { + //noinspection unchecked return (RMNode)((RangeMarkerImpl)key).myNode; } @Override protected void setNode(@NotNull T key, IntervalNode intervalNode) { + //noinspection unchecked ((RangeMarkerImpl)key).myNode = (RMNode)intervalNode; } @@ -166,11 +169,11 @@ public class RangeMarkerTree extends IntervalTreeImpl extends IntervalTreeImpl root, + private boolean collectAffectedMarkersAndShiftSubtrees(@Nullable IntervalNode root, @NotNull DocumentEvent e, @NotNull List> affected) { if (root == null) return true; @@ -303,7 +306,7 @@ public class RangeMarkerTree extends IntervalTreeImpl sweepProcessor) { + public boolean sweep(final int start, final int end, @NotNull SweepProcessor sweepProcessor) { return sweep(new Generator() { @Override public boolean generateInStartOffsetOrder(@NotNull Processor processor) { @@ -319,7 +322,7 @@ public class RangeMarkerTree extends IntervalTreeImpl boolean sweep(@NotNull Generator generator, @NotNull final SweepProcessor sweepProcessor) { final Queue ends = new PriorityQueue(5, new Comparator() { @Override - public int compare(T o1, T o2) { + public int compare(@NotNull T o1, @NotNull T o2) { return o1.getEndOffset() - o2.getEndOffset(); } }); @@ -391,7 +394,7 @@ public class RangeMarkerTree extends IntervalTreeImpl root, + private void collectNodesToRetarget(@Nullable IntervalNode root, int start, int end, @NotNull List> affected) { if (root == null) return; diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java index 41197feb5e74..6e1ab7fe6a15 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java @@ -36,7 +36,7 @@ public abstract class RedBlackTree { verifyProperties(); } - protected void rotateLeft(Node n) { + protected void rotateLeft(@NotNull Node n) { Node r = n.getRight(); replaceNode(n, r); n.setRight(r.getLeft()); @@ -47,7 +47,7 @@ public abstract class RedBlackTree { n.setParent(r); } - protected void rotateRight(Node n) { + protected void rotateRight(@NotNull Node n) { Node l = n.getLeft(); replaceNode(n, l); n.setLeft(l.getRight()); @@ -177,10 +177,11 @@ public abstract class RedBlackTree { verifyProperties(); } - protected abstract Node swapWithMaxPred(Node nowAscendant, Node nowDescendant); + @NotNull + protected abstract Node swapWithMaxPred(@NotNull Node nowAscendant, @NotNull Node nowDescendant); - protected Node maximumNode(Node n) { - assert n != null; + @NotNull + protected Node maximumNode(@NotNull Node n) { while (n.getRight() != null) { n = n.getRight(); } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java index 3b9dd10ff0ba..c9659764e2c8 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -66,13 +66,13 @@ public class RangeHighlighterTree extends RangeMarkerTree { //range highlighters are strongly referenced @Override protected Getter createGetter(@NotNull RangeHighlighterEx interval) { + //noinspection unchecked return (Getter)interval; } } @Override - void reportInvalidation(RangeHighlighterEx markerEx, Object reason) { - super.reportInvalidation(markerEx, reason); + void fireBeforeRemoved(@NotNull RangeHighlighterEx markerEx, @NotNull Object reason) { myMarkupModel.fireBeforeRemoved(markerEx); } } diff --git a/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java b/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java index 5092eff72e94..474ec528e7cf 100644 --- a/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java +++ b/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java @@ -20,8 +20,6 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.ex.util.EditorUtil; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ToolWindowManager; import org.jetbrains.annotations.Nullable; /** @@ -48,13 +46,9 @@ public abstract class EditorMacro extends Macro { @Override public final String expand(DataContext dataContext) throws ExecutionCancelledException { - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) return null; - if (ToolWindowManager.getInstance(project).isEditorComponentActive()) { - Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor != null){ - return expand(editor); - } + Editor editor = CommonDataKeys.EDITOR.getData(dataContext); + if (editor != null){ + return expand(editor); } return null; } diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java b/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java index 3712158a6b4c..e2a0958c4e2a 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java @@ -27,6 +27,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.TokenType; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; @@ -36,18 +37,19 @@ public class PsiBasedFormattingModel implements FormattingModelEx { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.PsiBasedFormattingModel"); + private final Project myProject; private final ASTNode myASTNode; private final FormattingDocumentModelImpl myDocumentModel; @NotNull private final Block myRootBlock; protected boolean myCanModifyAllWhiteSpaces = false; - + public PsiBasedFormattingModel(final PsiFile file, @NotNull final Block rootBlock, final FormattingDocumentModelImpl documentModel) { myASTNode = SourceTreeToPsiMap.psiElementToTree(file); myDocumentModel = documentModel; myRootBlock = rootBlock; - + myProject = file.getProject(); } @@ -81,7 +83,7 @@ public class PsiBasedFormattingModel implements FormattingModelEx { @Nullable - private String replaceWithPSI(final TextRange textRange, String whiteSpace) { + private String replaceWithPSI(final TextRange textRange, final String whiteSpace) { final int offset = textRange.getEndOffset(); ASTNode leafElement = findElementAt(offset); @@ -101,7 +103,14 @@ public class PsiBasedFormattingModel implements FormattingModelEx { return replaceWithPsiInLeaf(textRange, whiteSpace, leafElement); } } else if (textRange.getEndOffset() == myASTNode.getTextLength()){ - FormatterUtil.replaceLastWhiteSpace(myASTNode, whiteSpace, textRange); + + CodeStyleManager.getInstance(myProject).performActionWithFormatterDisabled(new Runnable() { + @Override + public void run() { + FormatterUtil.replaceLastWhiteSpace(myASTNode, whiteSpace, textRange); + } + }); + return whiteSpace; } else { return null; @@ -109,12 +118,18 @@ public class PsiBasedFormattingModel implements FormattingModelEx { } @Nullable - protected String replaceWithPsiInLeaf(final TextRange textRange, String whiteSpace, ASTNode leafElement) { + protected String replaceWithPsiInLeaf(final TextRange textRange, final String whiteSpace, final ASTNode leafElement) { if (!myCanModifyAllWhiteSpaces) { if (leafElement.getElementType() == TokenType.WHITE_SPACE) return null; } - FormatterUtil.replaceWhiteSpace(whiteSpace, leafElement, TokenType.WHITE_SPACE, textRange); + CodeStyleManager.getInstance(myProject).performActionWithFormatterDisabled(new Runnable() { + @Override + public void run() { + FormatterUtil.replaceWhiteSpace(whiteSpace, leafElement, TokenType.WHITE_SPACE, textRange); + } + }); + return whiteSpace; } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java index e630db6d7f17..3e490d6e0dc3 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java @@ -77,7 +77,7 @@ public class DocumentFragmentTooltipRenderer implements TooltipRenderer { FoldingModelEx foldingModel = (FoldingModelEx)editor.getFoldingModel(); foldingModel.setFoldingEnabled(false); TextRange textRange = new TextRange(startOffset, endOffset); - hint = EditorFragmentComponent.showEditorFragmentHintAt(editor, textRange, p.y, false, false, true); + hint = EditorFragmentComponent.showEditorFragmentHintAt(editor, textRange, p.y, false, false, true, true, true); foldingModel.setFoldingEnabled(true); return hint; } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java index 2d8be80bc861..aa1c18f4c71f 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java @@ -150,21 +150,6 @@ public class EditorFragmentComponent extends JPanel { /** * @param y y coordinate in layered pane coordinate system. - * @param hideByAnyKey - */ - @Nullable - public static LightweightHint showEditorFragmentHintAt(Editor editor, - TextRange range, - int y, - boolean showUpward, - boolean showFolding, - boolean hideByAnyKey) { - return showEditorFragmentHintAt(editor, range, y, showUpward, showFolding, hideByAnyKey, true); - } - - /** - * @param y y coordinate in layered pane coordinate system. - * @param hideByAnyKey */ @Nullable public static LightweightHint showEditorFragmentHintAt(Editor editor, @@ -173,6 +158,7 @@ public class EditorFragmentComponent extends JPanel { boolean showUpward, boolean showFolding, boolean hideByAnyKey, + boolean hideByScrolling, boolean useCaretRowBackground) { if (ApplicationManager.getApplication().isUnitTestMode()) return null; Document document = editor.getDocument(); @@ -215,6 +201,7 @@ public class EditorFragmentComponent extends JPanel { Point p = new Point(x, y); LightweightHint hint = new MyComponentHint(fragmentComponent); HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, (hideByAnyKey ? HintManager.HIDE_BY_ANY_KEY : 0) | + (hideByScrolling ? HintManager.HIDE_BY_SCROLLING : 0) | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_MOUSEOVER, 0, false, new HintHint(editor, p)); return hint; @@ -252,7 +239,7 @@ public class EditorFragmentComponent extends JPanel { if (rootPane == null) return null; JLayeredPane layeredPane = rootPane.getLayeredPane(); Point point = SwingUtilities.convertPoint(editorComponent, -2, 0, layeredPane); - return showEditorFragmentHintAt(editor, range, point.y, true, showFolding, hideByAnyKey, false); + return showEditorFragmentHintAt(editor, range, point.y, true, showFolding, hideByAnyKey, true, false); } public static Color getBackgroundColor(Editor editor){ diff --git a/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java b/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java index f38ef84a2b93..6f2bfccea08f 100644 --- a/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java +++ b/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -15,6 +15,8 @@ */ package com.intellij.help.impl; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.application.ApplicationStarter; import com.intellij.openapi.application.PathManager; @@ -45,15 +47,17 @@ public class KeymapGenerator implements ApplicationStarter { @Override public void main(String[] args) { + ActionManager actionManager = ActionManager.getInstance(); StringBuilder xml = new StringBuilder(); xml.append("\n"); for (Keymap keymap : KeymapManagerEx.getInstanceEx().getAllKeymaps()) { - + xml.append(" \n"); for (String id : keymap.getActionIds()) { String shortcuts = KeymapUtil.getShortcutsText(keymap.getShortcuts(id)); if (!StringUtil.isEmpty(shortcuts)) { + AnAction action = actionManager.getAction(id); xml.append(" \n"); Set addedShortcuts = new THashSet(); for (Shortcut shortcut : keymap.getShortcuts(id)) { @@ -64,6 +68,12 @@ public class KeymapGenerator implements ApplicationStarter { xml.append(" ").append(shortcutText).append("\n"); } } + if (action != null) { + String text = action.getTemplatePresentation().getText(); + if (text != null) { + xml.append(" ").append(StringUtil.escapeXml(text)).append("\n"); + } + } xml.append(" \n"); } } diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index bfd8fecc4441..f6a0b2d9e7fb 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -410,7 +410,8 @@ public class IdeEventQueue extends EventQueue { //private static boolean altGrIsPressed = false; private static AWTEvent fixNonEnglishKeyboardLayouts(AWTEvent e) { - if (!KeyboardSettingsExternalizable.getInstance().isNonEnglishKeyboardSupportEnabled()) return e; + KeyboardSettingsExternalizable externalizable = KeyboardSettingsExternalizable.getInstance(); + if (externalizable == null || !externalizable.isNonEnglishKeyboardSupportEnabled()) return e; if (e instanceof KeyEvent) { KeyEvent ke = (KeyEvent)e; diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java index 19dfd08e3c57..b1da26956ac4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java @@ -26,13 +26,14 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.KeyStrokeAdapter; import javax.swing.*; +import java.awt.*; import java.awt.event.KeyEvent; public class ShortcutTextField extends JTextField { private KeyStroke myKeyStroke; public ShortcutTextField() { - enableEvents(KeyEvent.KEY_EVENT_MASK); + enableEvents(AWTEvent.KEY_EVENT_MASK); setFocusTraversalKeysEnabled(false); } diff --git a/platform/util/src/com/intellij/Patches.java b/platform/util/src/com/intellij/Patches.java index cb1c9c07347d..daea52abff4e 100644 --- a/platform/util/src/com/intellij/Patches.java +++ b/platform/util/src/com/intellij/Patches.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -108,4 +108,10 @@ public class Patches { * fixed in JDK8 */ public static final boolean JDK_BUG_ID_7103570 = true; + + /** + * Support default methods in JDI + * See JDK-8042123 + */ + public static final boolean JDK_BUG_ID_8042123 = !SystemInfo.isJavaVersionAtLeast("1.8.0_40"); } diff --git a/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java b/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java index c365be8b33aa..983c8012e4dd 100644 --- a/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java +++ b/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java @@ -23,12 +23,13 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; public class UserDataHolderBase implements UserDataHolderEx, Cloneable { - public static final Key COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY"); + private static final Key COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY"); /** * Concurrent writes to this field are via CASes only, using the {@link #updater} */ - @NotNull private volatile KeyFMap myUserMap = KeyFMap.EMPTY_MAP; + @NotNull + private volatile KeyFMap myUserMap = KeyFMap.EMPTY_MAP; @Override protected Object clone() { @@ -47,10 +48,10 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable { public String getUserDataString() { final KeyFMap userMap = getUserMap(); final KeyFMap copyableMap = getUserData(COPYABLE_USER_MAP_KEY); - return userMap.toString() + (copyableMap == null ? "" : copyableMap.toString()); + return userMap + (copyableMap == null ? "" : copyableMap.toString()); } - public void copyUserDataTo(UserDataHolderBase other) { + public void copyUserDataTo(@NotNull UserDataHolderBase other) { other.setUserMap(getUserMap()); } diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 7835e488d617..97b40512dff8 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -2086,6 +2086,15 @@ public class StringUtil extends StringUtilRt { return replace(text, REPLACES_DISP, REPLACES_REFS); } + @NonNls private static final String[] MN_QUOTED = {"&&", "__"}; + @NonNls private static final String[] MN_CHARS = {"&", "_"}; + + @Contract(value = "null -> null; !null -> !null", pure = true) + public static String escapeMnemonics(@Nullable String text) { + if (text == null) return null; + return replace(text, MN_CHARS, MN_QUOTED); + } + @NotNull @Contract(pure = true) public static String htmlEmphasize(@NotNull String text) { diff --git a/platform/util/src/com/intellij/util/ArrayUtil.java b/platform/util/src/com/intellij/util/ArrayUtil.java index 462f90c86447..2550a1d41d41 100644 --- a/platform/util/src/com/intellij/util/ArrayUtil.java +++ b/platform/util/src/com/intellij/util/ArrayUtil.java @@ -414,6 +414,7 @@ public class ArrayUtil extends ArrayUtilRt { return result; } + @NotNull @Contract(pure=true) public static T[] append(@NotNull final T[] src, final T element, @NotNull ArrayFactory factory) { int length = src.length; diff --git a/platform/util/src/com/intellij/util/containers/MultiMap.java b/platform/util/src/com/intellij/util/containers/MultiMap.java index f8af63cc7ba8..4bc55fd5cd5e 100644 --- a/platform/util/src/com/intellij/util/containers/MultiMap.java +++ b/platform/util/src/com/intellij/util/containers/MultiMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -47,6 +47,11 @@ public class MultiMap implements Serializable { putAllValues(toCopy); } + @NotNull + public MultiMap copy() { + return new MultiMap(this); + } + public MultiMap(int i, float v) { myMap = createMap(i, v); } diff --git a/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java b/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java index 9bcd04a41e61..cde64d3dc698 100644 --- a/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java +++ b/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; @@ -42,7 +43,7 @@ public class SynchronizeCurrentFileAction extends AnAction implements DumbAware String message = getMessage(files); e.getPresentation().setEnabledAndVisible(true); - e.getPresentation().setText(message.replace("_", "__").replace("&", "&&")); + e.getPresentation().setText(StringUtil.escapeMnemonics(message)); } private static String getMessage(VirtualFile[] files) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java index 7d535982cfd0..8d3e0d3fd9bf 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java @@ -23,10 +23,10 @@ import org.jetbrains.annotations.Nullable; import java.util.List; /** - * Collects incoming requests into a list, and provides them to an underlying background task via {@link #popRequests()}.
+ * Collects incoming requests into a list, and provides them to the underlying background task via {@link #popRequests()}.
* Such task is started immediately after the first request arrives, if no other task is currently running.
- * A task indicates its completion by calling {@link #taskCompleted(Object)} and providing a result which is immediately passed to the - * result handler. + * A task reports its completion by calling {@link #taskCompleted(Object)} and providing a result which is immediately passed to the + * result handler (unless it is null in which case the task is stopped but the result is not passed to the handler). *

* The purpose of this class is to provide a single thread, which processes incoming requests in the background and continues to process * new ones if they arrive while the previous ones were processed. An alternative would be a long living thread which always checks some diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java index 16a1ce54d933..b75002919dce 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -73,6 +73,7 @@ public class XVariablesView extends XVariablesViewBase { tree.getProject().putUserData(DEBUG_VARIABLES, null); tree.getProject().putUserData(DEBUG_VARIABLES_TIMESTAMPS, null); tree.setSourcePosition(null); + tree.updateEditor(); XDebuggerTreeNode node; XDebugSession session = getSession(getPanel()); diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java index 6fe520e18ba4..9f4e34cf2eb7 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java @@ -82,20 +82,24 @@ public abstract class GradleImportingTestCase extends ExternalSystemImportingTes @org.junit.runners.Parameterized.Parameter(0) public String gradleVersion; private GradleProjectSettings myProjectSettings; + private String myJdkHome; @Override public void setUp() throws Exception { + myJdkHome = IdeaTestUtil.requireRealJdkHome(); super.setUp(); assumeThat(gradleVersion, versionMatcherRule.getMatcher()); - final String jdkHome = IdeaTestUtil.requireRealJdkHome(); - assertNull("JDK " + GRADLE_JDK_NAME + " already exists", ProjectJdkTable.getInstance().findJdk(GRADLE_JDK_NAME)); new WriteAction() { @Override protected void run(@NotNull Result result) throws Throwable { - VirtualFile jdkHomeDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(jdkHome)); + Sdk oldJdk = ProjectJdkTable.getInstance().findJdk(GRADLE_JDK_NAME); + if (oldJdk != null) { + ProjectJdkTable.getInstance().removeJdk(oldJdk); + } + VirtualFile jdkHomeDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(myJdkHome)); Sdk jdk = SdkConfigurationUtil.setupSdk(new Sdk[0], jdkHomeDir, JavaSdk.getInstance(), true, null, GRADLE_JDK_NAME); - assertNotNull("Cannot create JDK for " + jdkHome, jdk); - SdkConfigurationUtil.addSdk(jdk); + assertNotNull("Cannot create JDK for " + myJdkHome, jdk); + ProjectJdkTable.getInstance().addJdk(jdk); } }.execute(); myProjectSettings = new GradleProjectSettings(); @@ -126,11 +130,7 @@ public abstract class GradleImportingTestCase extends ExternalSystemImportingTes @Override protected void collectAllowedRoots(List roots) throws IOException { - final String javaHome = System.getenv("JAVA_HOME"); - if (javaHome != null) { - roots.add(javaHome); - } - + roots.add(myJdkHome); roots.add(PathManager.getOptionsPath()); } diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index 1b03c9f26b2c..1a87f49963e7 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.tree.TreeUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; @@ -38,6 +39,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static com.jetbrains.python.formatter.PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON; +import static com.jetbrains.python.formatter.PyCodeStyleSettings.DICT_ALIGNMENT_ON_VALUE; + /** * @author yole */ @@ -83,6 +87,7 @@ public class PyBlock implements ASTBlock { private final PyBlockContext myContext; private List mySubBlocks = null; private Alignment myChildAlignment; + private final Alignment myDictAlignment; private final boolean myEmptySequence; public PyBlock(final PyBlock parent, @@ -98,6 +103,8 @@ public class PyBlock implements ASTBlock { myWrap = wrap; myContext = context; myEmptySequence = isEmptySequence(node); + + myDictAlignment = node.getElementType() == PyElementTypes.DICT_LITERAL_EXPRESSION ? Alignment.createAlignment(true) : null; } @NotNull @@ -147,7 +154,10 @@ public class PyBlock implements ASTBlock { private PyBlock buildSubBlock(ASTNode child) { final IElementType parentType = myNode.getElementType(); - final IElementType grandparentType = myNode.getTreeParent() == null ? null : myNode.getTreeParent().getElementType(); + + final ASTNode grandParentNode = myNode.getTreeParent(); + final IElementType grandparentType = grandParentNode == null ? null : grandParentNode.getElementType(); + final IElementType childType = child.getElementType(); Wrap wrap = null; Indent childIndent = Indent.getNoneIndent(); @@ -216,6 +226,7 @@ public class PyBlock implements ASTBlock { } } + PyCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(child.getPsi().getProject()).getCustomSettings(PyCodeStyleSettings.class); if (parentType == PyElementTypes.LIST_LITERAL_EXPRESSION || parentType == PyElementTypes.LIST_COMP_EXPRESSION) { if (childType == PyTokenTypes.RBRACKET || childType == PyTokenTypes.LBRACKET) { childIndent = Indent.getNoneIndent(); @@ -241,7 +252,7 @@ public class PyBlock implements ASTBlock { else if (parentType == PyElementTypes.FROM_IMPORT_STATEMENT) { if (myNode.findChildByType(PyTokenTypes.LPAR) != null) { if (childType == PyElementTypes.IMPORT_ELEMENT) { - if (myContext.getPySettings().ALIGN_MULTILINE_IMPORTS) { + if (settings.ALIGN_MULTILINE_IMPORTS) { childAlignment = getAlignmentForChildren(); } else { @@ -330,12 +341,27 @@ public class PyBlock implements ASTBlock { } } } - if (isAfterStatementList(child) && !hasLineBreaksBefore(child, 2) && child.getElementType() != PyTokenTypes.END_OF_LINE_COMMENT) { // maybe enter was pressed and cut us from a previous (nested) statement list childIndent = Indent.getNormalIndent(); } + if (settings.DICT_ALIGNMENT == DICT_ALIGNMENT_ON_VALUE) { + if (isDictLiteralPropertyValue(child) && !ourListElementTypes.contains(childType)) { + childAlignment = myParent.myDictAlignment; + } + else if (isDictLiteralPropertyValue(myNode) && + ourListElementTypes.contains(parentType) && + PyTokenTypes.OPEN_BRACES.contains(childType)) { + childAlignment = myParent.myParent.myDictAlignment; + } + } + else if (myContext.getPySettings().DICT_ALIGNMENT == DICT_ALIGNMENT_ON_COLON) { + if (isInsideDictLiteralKeyValue(child) && childType == PyTokenTypes.COLON) { + childAlignment = myParent.myDictAlignment; + } + } + ASTNode prev = child.getTreePrev(); while (prev != null && prev.getElementType() == TokenType.WHITE_SPACE) { if (prev.textContains('\\') && @@ -350,6 +376,23 @@ public class PyBlock implements ASTBlock { return new PyBlock(this, child, childAlignment, childIndent, wrap, myContext); } + private static boolean isDictLiteralPropertyValue(@NotNull ASTNode node) { + return isInsideDictLiteralKeyValue(node) && node.getTreeParent().getPsi(PyKeyValueExpression.class).getValue() == node.getPsi(); + } + + private static boolean isInsideDictLiteralKeyValue(@NotNull ASTNode node) { + final ASTNode nodeParent = node.getTreeParent(); + if (nodeParent == null) { + return false; + } + final ASTNode nodeGrandParent = nodeParent.getTreeParent(); + if (nodeGrandParent == null) { + return false; + } + return nodeParent.getElementType() == PyElementTypes.KEY_VALUE_EXPRESSION && + nodeGrandParent.getElementType() == PyElementTypes.DICT_LITERAL_EXPRESSION; + } + private static boolean isEmptySequence(@NotNull ASTNode node) { return node.getPsi() instanceof PySequenceExpression && ((PySequenceExpression)node.getPsi()).isEmpty(); } diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java b/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java index 479074df2826..b48315f9004f 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java @@ -27,4 +27,9 @@ public class PyCodeStyleMainPanel extends TabbedLanguageCodeStylePanel { super(PythonLanguage.getInstance(), currentSettings, settings); } + @Override + protected void initTabs(CodeStyleSettings settings) { + super.initTabs(settings); + addTab(new PyCodeStylePanel(settings)); + } } diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form index d776fac9f890..9884e8a9fee5 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form +++ b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form @@ -1,12 +1,70 @@

- + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java index 66315fe0d46b..00334078dc9b 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java @@ -20,23 +20,57 @@ import com.intellij.ide.highlighter.HighlighterFactory; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.psi.PsiFile; +import com.intellij.openapi.ui.ComboBox; import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.jetbrains.python.highlighting.PyHighlighter; +import com.intellij.ui.components.JBCheckBox; import com.jetbrains.python.PythonFileType; +import com.jetbrains.python.PythonLanguage; +import com.jetbrains.python.formatter.PyCodeStyleSettings.DictAlignment; +import com.jetbrains.python.highlighting.PyHighlighter; import com.jetbrains.python.psi.LanguageLevel; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; /** * @author yole */ public class PyCodeStylePanel extends CodeStyleAbstractPanel { + private JPanel myPanel; + private JBCheckBox myAddTrailingBlankLineCheckbox; + private ComboBox myDictAlignmentCombo; + private JPanel myPreviewPanel; protected PyCodeStylePanel(CodeStyleSettings settings) { - super(settings); + super(PythonLanguage.getInstance(), null, settings); + addPanelToWatch(myPanel); + installPreviewPanel(myPreviewPanel); + + for (DictAlignment alignment : DictAlignment.values()) { + //noinspection unchecked + myDictAlignmentCombo.addItem(alignment); + } + + myDictAlignmentCombo.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + somethingChanged(); + } + } + }); + + myAddTrailingBlankLineCheckbox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + somethingChanged(); + } + }); } @Override @@ -49,10 +83,6 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel { return 80; } - @Override - protected void prepareForReformat(PsiFile psiFile) { - } - @NotNull @Override protected FileType getFileType() { @@ -61,24 +91,54 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel { @Override protected String getPreviewText() { - return ""; + return PREVIEW; } @Override protected void resetImpl(CodeStyleSettings settings) { + for (DictAlignment alignment : DictAlignment.values()) { + if (getCustomSettings(settings).DICT_ALIGNMENT == alignment.asInt()) { + myDictAlignmentCombo.setSelectedItem(alignment); + break; + } + } + myAddTrailingBlankLineCheckbox.setSelected(getCustomSettings(settings).BLANK_LINE_AT_FILE_END); } @Override public void apply(CodeStyleSettings settings) { + final PyCodeStyleSettings customSettings = getCustomSettings(settings); + customSettings.DICT_ALIGNMENT = getDictAlignmentAsInt(); + customSettings.BLANK_LINE_AT_FILE_END = ensureTrailingBlankLine(); } @Override public boolean isModified(CodeStyleSettings settings) { - return false; + final PyCodeStyleSettings customSettings = getCustomSettings(settings); + return customSettings.DICT_ALIGNMENT != getDictAlignmentAsInt() || + customSettings.BLANK_LINE_AT_FILE_END != ensureTrailingBlankLine(); } @Override public JComponent getPanel() { return myPanel; } + + @NotNull + private static PyCodeStyleSettings getCustomSettings(@NotNull CodeStyleSettings settings) { + return settings.getCustomSettings(PyCodeStyleSettings.class); + } + + private int getDictAlignmentAsInt() { + return ((DictAlignment)myDictAlignmentCombo.getSelectedItem()).asInt(); + } + + private boolean ensureTrailingBlankLine() { + return myAddTrailingBlankLineCheckbox.isSelected(); + } + + public static final String PREVIEW = "{\n" + + " \"green\": 42,\n" + + " \"eggs and ham\": -0.0e0\n" + + "}"; } diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java index c060b782d1ad..795b8c42e987 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java @@ -22,6 +22,33 @@ import com.intellij.psi.codeStyle.CustomCodeStyleSettings; * @author yole */ public class PyCodeStyleSettings extends CustomCodeStyleSettings { + + public enum DictAlignment { + NONE("Do not align"), + ON_VALUE("Align on value"), + ON_COLON("Align on colon"); + + String description; + + DictAlignment(String description) { + this.description = description; + } + + public int asInt() { + return ordinal(); + } + + @Override + public String toString() { + return description; + } + } + + // Unfortunately, the old serializer for code style settings can't handle enums + public static final int DICT_ALIGNMENT_NONE = DictAlignment.NONE.asInt(); + public static final int DICT_ALIGNMENT_ON_VALUE = DictAlignment.ON_VALUE.asInt(); + public static final int DICT_ALIGNMENT_ON_COLON = DictAlignment.ON_COLON.asInt(); + public boolean SPACE_WITHIN_BRACES = false; public boolean SPACE_BEFORE_PY_COLON = false; public boolean SPACE_AFTER_PY_COLON = true; @@ -32,7 +59,7 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { public int BLANK_LINES_AROUND_TOP_LEVEL_CLASSES_FUNCTIONS = 2; // TODO make boolean (it needs special editor in BlankLinesPanel) - public int BLANKS_LINES_AT_FILE_END = 1; + public boolean BLANK_LINE_AT_FILE_END = true; public boolean ALIGN_COLLECTIONS_AND_COMPREHENSIONS = true; public boolean ALIGN_MULTILINE_IMPORTS = true; @@ -43,6 +70,8 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { public boolean SPACE_AFTER_NUMBER_SIGN = true; public boolean SPACE_BEFORE_NUMBER_SIGN = true; + public int DICT_ALIGNMENT = DICT_ALIGNMENT_NONE; + public PyCodeStyleSettings(CodeStyleSettings container) { super("Python", container); } diff --git a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java index ed213eaf36a9..a74c457d9efb 100644 --- a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java +++ b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java @@ -88,7 +88,6 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin consumer.showCustomOption(PyCodeStyleSettings.class, "BLANK_LINES_AROUND_TOP_LEVEL_CLASSES_FUNCTIONS", "Around top-level classes and functions:", BLANK_LINES); - consumer.showCustomOption(PyCodeStyleSettings.class, "BLANKS_LINES_AT_FILE_END", "Blank lines at the end of file", BLANK_LINES); } else if (settingsType == SettingsType.WRAPPING_AND_BRACES_SETTINGS) { consumer.showStandardOptions("RIGHT_MARGIN", diff --git a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java index 489000630a5c..db9ed9544658 100644 --- a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java +++ b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java @@ -20,7 +20,6 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -34,11 +33,11 @@ import org.jetbrains.annotations.NotNull; * Handles extra blank lines at the end of the file if corresponding whitespace elements belong to formatted range/element. * These trailing whitespaces are replaced by line feeds if either: *
    - *
  • Option {@link PyCodeStyleSettings#BLANKS_LINES_AT_FILE_END} has positive value. In this case that number of line feeds will be - * inserted at the end of file.
  • + *
  • Option {@link PyCodeStyleSettings#BLANK_LINE_AT_FILE_END} is enabled.
  • *
  • Setting {@link EditorSettingsExternalizable#isEnsureNewLineAtEOF()} is enabled. Otherwise extra new line added on the next * "Save" action will be removed after reformatting.
  • *
+ * and file is not empty. * If none of these conditions holds, blank lines are removed completely. * * @author Mikhail Golubev @@ -56,6 +55,7 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces public PsiElement processElement(@NotNull PsiElement source, @NotNull CodeStyleSettings settings) { final PsiFile psiFile = source.getContainingFile(); if (isApplicableTo(psiFile)) { + applyPendingChangesToPsi(source); final TextRange whitespaceRange = findTrailingWhitespacesRange(psiFile); if (source.getTextRange().intersects(whitespaceRange)) { replaceOrDeleteTrailingWhitespaces(psiFile, whitespaceRange); @@ -69,6 +69,7 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces if (!isApplicableTo(source)) { return rangeToReformat; } + applyPendingChangesToPsi(source); final TextRange oldWhitespaceRange = findTrailingWhitespacesRange(source); if (rangeToReformat.intersects(oldWhitespaceRange)) { final TextRange newWhitespaceRange = replaceOrDeleteTrailingWhitespaces(source, oldWhitespaceRange); @@ -92,6 +93,14 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces return rangeToReformat; } + private static void applyPendingChangesToPsi(@NotNull PsiElement source) { + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(source.getContainingFile().getProject()); + final Document document = documentManager.getDocument(source.getContainingFile()); + if (document != null) { + documentManager.doPostponedOperationsAndUnblockDocument(document); + } + } + @NotNull private static TextRange findTrailingWhitespacesRange(@NotNull PsiFile file) { final CharSequence contents = file.getViewProvider().getContents(); @@ -113,14 +122,12 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); final Document document = documentManager.getDocument(pyFile); if (document != null) { - int numLineFeeds = CodeStyleSettingsManager.getSettings(project).getCustomSettings(PyCodeStyleSettings.class).BLANKS_LINES_AT_FILE_END; - if (numLineFeeds <= 0 && EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF()) { - numLineFeeds = 1; - } - documentManager.doPostponedOperationsAndUnblockDocument(document); + final PyCodeStyleSettings customSettings = CodeStyleSettingsManager.getSettings(project).getCustomSettings(PyCodeStyleSettings.class); + final boolean addLineFeed = customSettings.BLANK_LINE_AT_FILE_END || EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF(); try { - final String text = StringUtil.repeat("\n", numLineFeeds); - if (numLineFeeds > 0 && whitespaceRange.getStartOffset() != 0) { + final String text = addLineFeed ? "\n" : ""; + // Do not add extra blank line in empty file + if (!text.isEmpty() && whitespaceRange.getStartOffset() != 0) { if (!whitespaceRange.isEmpty()) { document.replaceString(whitespaceRange.getStartOffset(), whitespaceRange.getEndOffset(), text); } diff --git a/python/testData/formatter/alignDictLiteralOnColon.py b/python/testData/formatter/alignDictLiteralOnColon.py new file mode 100644 index 000000000000..ec4809b888d3 --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnColon.py @@ -0,0 +1,7 @@ +{ + "a": 1, + "bbb": [ + 2 + ], + "bbbbb": 3 +} \ No newline at end of file diff --git a/python/testData/formatter/alignDictLiteralOnColon_after.py b/python/testData/formatter/alignDictLiteralOnColon_after.py new file mode 100644 index 000000000000..663d95a84b7c --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnColon_after.py @@ -0,0 +1,7 @@ +{ + "a" : 1, + "bbb" : [ + 2 + ], + "bbbbb": 3 +} diff --git a/python/testData/formatter/alignDictLiteralOnValue.py b/python/testData/formatter/alignDictLiteralOnValue.py new file mode 100644 index 000000000000..afe69120050c --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnValue.py @@ -0,0 +1,7 @@ +{ + "a": 1, + "bbb": [ + 2 + ], + "bbbbb": 3 +} diff --git a/python/testData/formatter/alignDictLiteralOnValue_after.py b/python/testData/formatter/alignDictLiteralOnValue_after.py new file mode 100644 index 000000000000..13881b918e21 --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnValue_after.py @@ -0,0 +1,7 @@ +{ + "a": 1, + "bbb": [ + 2 + ], + "bbbbb": 3 +} diff --git a/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting.py b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting.py new file mode 100644 index 000000000000..a0486c9a8d5e --- /dev/null +++ b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting.py @@ -0,0 +1,4 @@ +{ + "aaaaa": 1, + "bbb aaaaaaa": 2 +} \ No newline at end of file diff --git a/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting_after.py b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting_after.py new file mode 100644 index 000000000000..e04ac0be0bc5 --- /dev/null +++ b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting_after.py @@ -0,0 +1,4 @@ +{ + "aaaaa" : 1, + "bbb aaaaaaa": 2 +} diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index 02c62a2113c2..605a8b5f83da 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -567,6 +567,18 @@ public class PyFormatterTest extends PyTestCase { doTest(); } + // PY-14962 + public void testAlignDictLiteralOnValue() { + getCustomSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_VALUE; + doTest(); + } + + // PY-14962 + public void testAlignDictLiteralOnColon() { + getCustomSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON; + doTest(); + } + // PY-15530 public void testAlignmentInArgumentListWhereFirstArgumentIsEmptyCall() { doTest(); @@ -589,6 +601,11 @@ public class PyFormatterTest extends PyTestCase { doTest(); } + public void testDoNotDestroyAlignment_OnPostponedFormatting() throws Exception { + getCustomSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON; + doTest(); + } + public void testAlignmentOfEmptyCollectionLiterals() { doTest(); } diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java index 0e6c77e4f6f2..e311f362be58 100644 --- a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java +++ b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java @@ -49,10 +49,7 @@ import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.UsefulTestCase; -import com.intellij.testFramework.fixtures.CodeInsightTestFixture; -import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; -import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; -import com.intellij.testFramework.fixtures.TestFixtureBuilder; +import com.intellij.testFramework.fixtures.*; import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl; import com.intellij.usageView.UsageInfo; import com.intellij.usages.Usage; @@ -124,12 +121,20 @@ public abstract class PyTestCase extends UsefulTestCase { TestFixtureBuilder fixtureBuilder = factory.createLightFixtureBuilder(getProjectDescriptor()); final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture(); myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixture, - new LightTempDirTestFixtureImpl(true)); + createTempDirFixture()); myFixture.setUp(); myFixture.setTestDataPath(getTestDataPath()); } + /** + * @return fixture to be used as temporary dir. + */ + @NotNull + protected TempDirTestFixture createTempDirFixture() { + return new LightTempDirTestFixtureImpl(true); // "tmp://" dir by default + } + protected String getTestDataPath() { return PythonTestUtil.getTestDataPath(); } diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 55687bf4d04d..929447158cd4 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -444,6 +444,8 @@ action.watch.method.return.value.description=Enables watching last executed meth action.watches.method.return.value.enable=Watch method return values action.watches.method.return.value.disable=Stop watching method return values action.watches.method.return.value.unavailable.reason=Feature is not supported by the target VM +action.auto.variables.mode=Auto-Variables Mode +action.auto.variables.mode.description=Show only variables used near the execution point action.maximizeContent.text breakpoint.properties.panel.option.depends.disable.again=Disable again breakpoint.properties.panel.option.depends.leave.enabled=Leave enabled diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index b8b47df466cf..a518d3a5e771 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1521,12 +1521,13 @@ - - - - + + + + +