diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java index 18e54211dc45..5fe4804736bb 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java @@ -44,7 +44,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Map; @@ -205,20 +204,11 @@ public class JavaMarkObjectActionHandler extends MarkObjectActionHandler { } private static List getReferringObjects(ObjectReference value) { - // invoke the following method using Reflection in order to remain compilable on jdk 1.5 - // java.util.List referringObjects(long l); try { - final Method apiMethod = ObjectReference.class.getMethod("referringObjects", long.class); - //noinspection unchecked - return (List)apiMethod.invoke(value, AUTO_MARKUP_REFERRING_OBJECTS_LIMIT); + return value.referringObjects(AUTO_MARKUP_REFERRING_OBJECTS_LIMIT); } - catch (IllegalAccessException e) { - LOG.error(e); // should not happen - } - catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - catch (NoSuchMethodException ignored) { + catch (UnsupportedOperationException e) { + LOG.info(e); } return Collections.emptyList(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java index fe2ac9ee5bf5..cd4aa14b7703 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java @@ -65,6 +65,6 @@ public class ObjectMarkupPropertiesDialog extends ValueMarkerPresentationDialogB } public boolean isMarkAdditionalFields() { - return myCbMarkAdditionalFields.isSelected(); + return mySuggestAdditionalMarkup && myCbMarkAdditionalFields.isSelected(); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java index 87ee0491bfbe..f60ab7f2eaaa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java @@ -23,13 +23,12 @@ import com.intellij.psi.PsiExpressionCodeFragment; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; -public class TextWithImportsImpl implements TextWithImports{ +public final class TextWithImportsImpl implements TextWithImports{ private final CodeFragmentKind myKind; private String myText; private final String myImports; - public TextWithImportsImpl (PsiExpression expression) { myKind = CodeFragmentKind.EXPRESSION; final String text = expression.getText(); @@ -92,9 +91,13 @@ public class TextWithImportsImpl implements TextWithImports{ } public String toString() { + return getText(); + } + + public String toExternalForm() { return "".equals(myImports) ? myText : myText + DebuggerEditorImpl.SEPARATOR + myImports; } - + public int hashCode() { return myText.hashCode(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java index a03cd3b99eac..269799d07624 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java @@ -66,7 +66,7 @@ public class DebuggerUtilsImpl extends DebuggerUtilsEx{ public Element writeTextWithImports(TextWithImports text) { Element element = new Element("TextWithImports"); - element.setAttribute("text", text.toString()); + element.setAttribute("text", text.toExternalForm()); element.setAttribute("type", text.getKind() == CodeFragmentKind.EXPRESSION ? "expression" : "code fragment"); return element; } @@ -85,7 +85,7 @@ public class DebuggerUtilsImpl extends DebuggerUtilsEx{ public void writeTextWithImports(Element root, String name, TextWithImports value) { LOG.assertTrue(value.getKind() == CodeFragmentKind.EXPRESSION); - JDOMExternalizerUtil.writeField(root, name, value.toString()); + JDOMExternalizerUtil.writeField(root, name, value.toExternalForm()); } public TextWithImports readTextWithImports(Element root, String name) { diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java index d28dbb4a02ec..df2b69812114 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java @@ -210,7 +210,7 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable{ exprColumn.setCellRenderer(new DefaultTableCellRenderer() { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { final TextWithImports textWithImports = (TextWithImports)value; - String text = (textWithImports != null)? textWithImports.toString() : ""; + final String text = (textWithImports != null)? textWithImports.getText() : ""; return super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column); } }); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index 0dafd39824e5..0943b4f3e658 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -260,7 +260,7 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa public void writeExternal(Element parentNode) throws WriteExternalException { super.writeExternal(parentNode); - JDOMExternalizerUtil.writeField(parentNode, LOG_MESSAGE_OPTION_NAME, getLogMessage().toString()); + JDOMExternalizerUtil.writeField(parentNode, LOG_MESSAGE_OPTION_NAME, getLogMessage().toExternalForm()); } public TextWithImports getLogMessage() { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java index f402dd47ac58..ce09ba5a67a8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java @@ -143,7 +143,7 @@ public abstract class FilteredRequestor implements LocatableEventRequestor, JDOM public void writeExternal(Element parentNode) throws WriteExternalException { DefaultJDOMExternalizer.writeExternal(this, parentNode); - JDOMExternalizerUtil.writeField(parentNode, CONDITION_OPTION_NAME, getCondition().toString()); + JDOMExternalizerUtil.writeField(parentNode, CONDITION_OPTION_NAME, getCondition().toExternalForm()); DebuggerUtilsEx.writeFilters(parentNode, FILTER_OPTION_NAME, myClassFilters); DebuggerUtilsEx.writeFilters(parentNode, EXCLUSION_FILTER_OPTION_NAME, myClassExclusionFilters); DebuggerUtilsEx.writeFilters(parentNode, INSTANCE_ID_OPTION_NAME, InstanceFilter.createClassFilters(myInstanceFilters)); diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/TextWithImports.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/TextWithImports.java index 1f4b6883b92e..95cf9946c064 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/TextWithImports.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/TextWithImports.java @@ -19,8 +19,15 @@ import org.jetbrains.annotations.NotNull; public interface TextWithImports { String getText(); + void setText(String newText); - @NotNull String getImports(); + + @NotNull + String getImports(); + CodeFragmentKind getKind(); + boolean isEmpty(); + + String toExternalForm(); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index b1adde398275..c26ea53d17bb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; import com.intellij.codeInsight.guess.GuessManager; import com.intellij.codeInsight.lookup.*; +import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -44,6 +45,8 @@ import com.intellij.psi.filters.element.ExcludeDeclaredFilter; import com.intellij.psi.filters.element.ExcludeSillyAssignment; import com.intellij.psi.html.HtmlTag; import com.intellij.psi.impl.source.PsiImmediateClassType; +import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; +import com.intellij.psi.impl.source.tree.TreeUtil; import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.psi.scope.BaseScopeProcessor; import com.intellij.psi.scope.ElementClassFilter; @@ -764,7 +767,7 @@ public class JavaCompletionUtil { assert document != null; document.replaceString(startOffset, endOffset, name); - final RangeMarker toDelete = insertTemporary(startOffset + name.length(), document, "#"); + final RangeMarker toDelete = insertTemporary(startOffset + name.length(), document, " "); PsiDocumentManager.getInstance(project).commitAllDocuments(); @@ -781,9 +784,15 @@ public class JavaCompletionUtil { ? ((PsiImportStaticReferenceElement)ref).bindToTargetClass(psiClass) : ref.bindToElement(psiClass); - RangeMarker marker = document.createRangeMarker(newElement.getTextRange()); + ASTNode newNode = newElement.getNode(); + CodeEditUtil.disablePostponedFormatting(newNode); + ASTNode next = TreeUtil.nextLeaf(newNode); + if (next != null) { + CodeEditUtil.disablePostponedFormatting(next); + } + newElement = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(newElement); - newStartOffset = marker.getStartOffset(); + newStartOffset = newElement.getTextRange().getStartOffset(); if (!staticImport && newElement instanceof PsiJavaCodeReferenceElement && diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java index 87bbd9b94ad6..1dcef334633d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java @@ -71,7 +71,7 @@ public class WordCompletionTest extends CompletionTestCase { } }; PsiReferenceRegistrarImpl registrar = - (PsiReferenceRegistrarImpl)ReferenceProvidersRegistry.getInstance().getRegistrar(StdLanguages.JAVA); + ReferenceProvidersRegistry.getInstance().getRegistrar(StdLanguages.JAVA); try { registrar.registerReferenceProvider(PsiLiteralExpression.class, softProvider); registrar.registerReferenceProvider(PsiLiteralExpression.class, hardProvider); diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java index e32d3d541523..fb98f7ed9c9b 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java @@ -23,6 +23,7 @@ import com.intellij.lang.Commenter; import com.intellij.lang.LanguageCommenters; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -61,7 +62,7 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase final String relativePath = quickFixTestCase.getBasePath() + "/" + BEFORE_PREFIX + testName; final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath; final File testFile = new File(testFullPath); - CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() { + CommandProcessor.getInstance().executeCommand(quickFixTestCase.getProject(), new Runnable() { @Override public void run() { try { @@ -263,17 +264,22 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase @Override public void configureFromFileText(String name, String contents) throws IOException { - LightCodeInsightTestCase.configureFromFileText(name, contents); + LightQuickFixTestCase.configureFromFileText(name, contents); } @Override public PsiFile getFile() { - return LightCodeInsightTestCase.getFile(); + return LightQuickFixTestCase.getFile(); + } + + @Override + public Project getProject() { + return LightQuickFixTestCase.getProject(); } @Override public void bringRealEditorBack() { - LightCodeInsightTestCase.bringRealEditorBack(); + LightQuickFixTestCase.bringRealEditorBack(); } }); } diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java index 3ea3502a09df..613488732762 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon.quickFix; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiFile; @@ -57,4 +58,6 @@ public interface QuickFixTestCase { void configureFromFileText(String name, String contents) throws Throwable; PsiFile getFile(); + + Project getProject(); } diff --git a/platform/extensions/src/com/intellij/openapi/extensions/Extensions.java b/platform/extensions/src/com/intellij/openapi/extensions/Extensions.java index 8d32554056e4..ba6e11113c73 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/Extensions.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/Extensions.java @@ -34,7 +34,7 @@ public class Extensions { public static final ExtensionPointName AREA_LISTENER_EXTENSION_POINT = new ExtensionPointName("com.intellij.arealistener"); private static final Map ourAreaInstance2area = new HashMap(); - private static final ExtensionsAreaImpl ourRootArea = createRootArea(); + private static ExtensionsAreaImpl ourRootArea = createRootArea(); private static final MultiMap ourAreaClass2instances = new MultiMap(); private static final Map ourAreaInstance2class = new HashMap(); private static final Map ourAreaClass2Configuration = new HashMap(); @@ -42,7 +42,6 @@ public class Extensions { private static ExtensionsAreaImpl createRootArea() { ExtensionsAreaImpl rootArea = new ExtensionsAreaImpl(null, null, null, ourLogger); rootArea.registerExtensionPoint(AREA_LISTENER_EXTENSION_POINT.getName(), AreaListener.class.getName()); - ourAreaInstance2area.put(null, rootArea); return rootArea; } @@ -72,7 +71,7 @@ public class Extensions { oldRootArea.notifyAreaReplaced(); Disposer.register(parentDisposable, new Disposable() { public void dispose() { - ourAreaInstance2area.put(null, oldRootArea); + ourRootArea = oldRootArea; newArea.notifyAreaReplaced(); } }); @@ -123,7 +122,7 @@ public class Extensions { if (!ourAreaClass2Configuration.containsKey(areaClass)) { throw new IllegalArgumentException("Area class is not registered: " + areaClass); } - if (ourAreaInstance2area.containsKey(areaInstance)) { + if ((areaInstance == null && ourRootArea != null) || ourAreaInstance2area.containsKey(areaInstance)) { throw new IllegalArgumentException("Area already instantiated for: " + areaInstance); } ExtensionsArea parentArea = getArea(parentAreaInstance); diff --git a/platform/lang-api/src/com/intellij/patterns/ElementPatternBean.java b/platform/lang-api/src/com/intellij/patterns/ElementPatternBean.java new file mode 100644 index 000000000000..354524c9e6fc --- /dev/null +++ b/platform/lang-api/src/com/intellij/patterns/ElementPatternBean.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2011 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.patterns; + +import com.intellij.patterns.compiler.PatternCompilerFactory; +import com.intellij.psi.PsiElement; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.util.xmlb.annotations.Text; +import org.jetbrains.annotations.Nullable; + +@Tag("pattern") +public class ElementPatternBean { + + @Attribute("type") + public String type; + + @Text + public String text; + + @Nullable + public ElementPattern compilePattern() { + return PatternCompilerFactory.getFactory().getPatternCompiler(type).compileElementPattern(text); + } +} diff --git a/platform/lang-api/src/com/intellij/psi/PsiReferenceContributor.java b/platform/lang-api/src/com/intellij/psi/PsiReferenceContributor.java index 04d5e2f79646..55f4f0d1d8aa 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiReferenceContributor.java +++ b/platform/lang-api/src/com/intellij/psi/PsiReferenceContributor.java @@ -15,7 +15,10 @@ import com.intellij.openapi.extensions.ExtensionPointName; * Some elements return them from {@link PsiElement#getReferences()} directly though, but one should not rely on that * behavior since it may be changed in the future. * + * The alternative way to register {@link PsiReferenceProvider} is by using {@link PsiReferenceProviderBean}. + * * @author peter + * @see PsiReferenceProviderBean */ public abstract class PsiReferenceContributor implements Disposable { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.psi.referenceContributor"); diff --git a/platform/lang-api/src/com/intellij/psi/PsiReferenceProvider.java b/platform/lang-api/src/com/intellij/psi/PsiReferenceProvider.java index e6dcea63dc81..799428dbd824 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiReferenceProvider.java +++ b/platform/lang-api/src/com/intellij/psi/PsiReferenceProvider.java @@ -20,6 +20,8 @@ import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; /** + * Register it via {@link PsiReferenceContributor} or {@link PsiReferenceProviderBean#EP_NAME} + * * @author ik */ public abstract class PsiReferenceProvider { diff --git a/platform/lang-impl/src/com/intellij/psi/PsiReferenceProviderBean.java b/platform/lang-api/src/com/intellij/psi/PsiReferenceProviderBean.java similarity index 59% rename from platform/lang-impl/src/com/intellij/psi/PsiReferenceProviderBean.java rename to platform/lang-api/src/com/intellij/psi/PsiReferenceProviderBean.java index ec4b893043c5..643ff81c622d 100644 --- a/platform/lang-impl/src/com/intellij/psi/PsiReferenceProviderBean.java +++ b/platform/lang-api/src/com/intellij/psi/PsiReferenceProviderBean.java @@ -19,27 +19,41 @@ package com.intellij.psi; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.AbstractExtensionPointBean; +import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.ElementPatternBean; import com.intellij.patterns.StandardPatterns; -import com.intellij.patterns.compiler.PatternCompilerFactory; -import com.intellij.util.xmlb.annotations.*; +import com.intellij.util.NullableFunction; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Property; +import com.intellij.util.xmlb.annotations.Tag; import org.jetbrains.annotations.Nullable; +/** + * Registers a {@link PsiReferenceProvider} in plugin.xml + */ public class PsiReferenceProviderBean extends AbstractExtensionPointBean { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiReferenceProviderBean"); + + public static final ExtensionPointName EP_NAME = + new ExtensionPointName("com.intellij.psi.referenceProvider"); @Attribute("providerClass") public String className; + @Tag("description") public String description; @Property(surroundWithTag = false) @AbstractCollection(surroundWithTag = false) - public Info[] patterns; + public ElementPatternBean[] patterns; public String getDescription() { return description; } + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiReferenceProviderBean"); + public PsiReferenceProvider instantiate() { try { return (PsiReferenceProvider)instantiate(className, ApplicationManager.getApplication().getPicoContainer()); @@ -50,30 +64,25 @@ public class PsiReferenceProviderBean extends AbstractExtensionPointBean { return null; } + private static final NullableFunction> PATTERN_NULLABLE_FUNCTION = new NullableFunction>() { + @Override + public ElementPattern fun(ElementPatternBean elementPatternBean) { + return elementPatternBean.compilePattern(); + } + }; + @Nullable public ElementPattern createElementPattern() { - final PatternCompilerFactory factory = PatternCompilerFactory.getFactory(); if (patterns.length > 1) { - final ElementPattern[] result = new ElementPattern[this.patterns.length]; - for (int i = 0, len = this.patterns.length; i < len; i++) { - result[i] = factory.getPatternCompiler(patterns[i].type).compileElementPattern(patterns[i].text); - } - return StandardPatterns.or(result); + return StandardPatterns.or(ContainerUtil.mapNotNull(patterns, + PATTERN_NULLABLE_FUNCTION).toArray(new ElementPattern[0])); } else if (patterns.length == 1) { - return factory.getPatternCompiler(patterns[0].type).compileElementPattern(patterns[0].text); + return patterns[0].compilePattern(); } else { LOG.error("At least one pattern should be specified"); return null; } } - - @Tag("pattern") - public static class Info { - @Attribute("type") - public String type; - @Text - public String text; - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java index eecb16174ce9..d16d88e4b38e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java @@ -20,6 +20,8 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; import java.util.*; @@ -76,7 +78,7 @@ class LiftShorterItemsClassifier extends Classifier { } private Iterable> liftShorterElements(List source, Set lifted) { - final Set srcSet = new HashSet(source); + final Set srcSet = new THashSet(source, TObjectHashingStrategy.IDENTITY); final Iterable> classified = myNext.classify(source); final Set processed = new HashSet(); @@ -84,6 +86,7 @@ class LiftShorterItemsClassifier extends Classifier { for (List list : classified) { final ArrayList group = new ArrayList(); for (LookupElement element : list) { + assert srcSet.contains(element) : myNext; if (processed.add(element)) { final List prefixes = new SmartList(); for (String string : getAllLookupStrings(element)) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java index 42e363939a57..6f2a0989329a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java @@ -18,6 +18,8 @@ package com.intellij.codeInsight.lookup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.StripedLockConcurrentHashMap; +import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -26,7 +28,7 @@ import java.util.*; * @author peter */ public abstract class ComparingClassifier extends Classifier { - private final Map myWeights = new HashMap(); + private final Map myWeights = new StripedLockConcurrentHashMap(TObjectHashingStrategy.IDENTITY); private final Classifier myNext; private final String myName; @@ -49,7 +51,7 @@ public abstract class ComparingClassifier extends Classifier { for (T t : source) { final Comparable weight = myWeights.get(t); if (weight == null) { - throw new AssertionError(myName + "; " + myWeights.containsKey(t)); + throw new AssertionError(myName + "; " + myWeights.containsKey(t) + "; element=" + t); } List list = map.get(weight); if (list == null) { diff --git a/platform/lang-impl/src/com/intellij/conversion/impl/ConversionContextImpl.java b/platform/lang-impl/src/com/intellij/conversion/impl/ConversionContextImpl.java index bb02cadb6225..7a78fdc6fdc5 100644 --- a/platform/lang-impl/src/com/intellij/conversion/impl/ConversionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/conversion/impl/ConversionContextImpl.java @@ -84,7 +84,7 @@ public class ConversionContextImpl implements ConversionContext { myWorkspaceFile = new File(StringUtil.trimEnd(projectPath, ProjectFileType.DOT_DEFAULT_EXTENSION) + WorkspaceFileType.DOT_DEFAULT_EXTENSION); } - myModuleFiles = findModuleFiles(JDomConvertingUtil.loadDocument(modulesFile).getRootElement()); + myModuleFiles = modulesFile.exists() ? findModuleFiles(JDomConvertingUtil.loadDocument(modulesFile).getRootElement()) : new File[0]; } public Set getAllProjectFiles() { diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java index e73e1646d491..f7b999698a4e 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java @@ -38,8 +38,7 @@ public abstract class AbstractBlockAlignmentProcessor implements BlockAlignmentP return Result.TARGET_BLOCK_PROCESSED_NOT_ALIGNED; } WhiteSpace whiteSpace = context.targetBlock.getWhiteSpace(); - if (whiteSpace.containsLineFeeds()) { - applyIndentToTheFirstBlockOnLine(indent, context); + if (whiteSpace.containsLineFeeds() && applyIndentToTheFirstBlockOnLine(indent, context)) { return Result.TARGET_BLOCK_ALIGNED; } @@ -118,8 +117,10 @@ public abstract class AbstractBlockAlignmentProcessor implements BlockAlignmentP * * @param alignmentAnchorIndent alignment anchor indent * @param context current processing context + * @return true if desired alignment indent is applied to the current block; + * false otherwise */ - protected abstract void applyIndentToTheFirstBlockOnLine(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context); + protected abstract boolean applyIndentToTheFirstBlockOnLine(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context); /** * Calculates the difference between alignment anchor indent and current target block indent. diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java index debe73fdb099..6fbbc070b4dc 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java @@ -134,36 +134,6 @@ public abstract class AbstractBlockWrapper { if (wrap != null) wrap.reset(); } - /** - * Calculates indent for the given block and target start offset according to the given indent options. - * - * @param options indent options to use - * @param block target wrapped block - * @param tokenBlockStartOffset target wrapped block offset - * @return indent to use for the given parameters - */ - private static IndentData getIndent(CodeStyleSettings.IndentOptions options, - AbstractBlockWrapper block, - final int tokenBlockStartOffset) { - final IndentImpl indent = block.getIndent(); - if (indent.getType() == Indent.Type.CONTINUATION) { - return new IndentData(options.CONTINUATION_INDENT_SIZE); - } - if (indent.getType() == Indent.Type.CONTINUATION_WITHOUT_FIRST) { - if (block.getStartOffset() != block.getParent().getStartOffset() && block.getStartOffset() == tokenBlockStartOffset) { - return new IndentData(options.CONTINUATION_INDENT_SIZE); - } - else { - return new IndentData(0); - } - } - if (indent.getType() == Indent.Type.LABEL) return new IndentData(options.LABEL_INDENT_SIZE); - if (indent.getType() == Indent.Type.NONE) return new IndentData(0); - if (indent.getType() == Indent.Type.SPACES) return new IndentData(0, indent.getSpaces()); - return new IndentData(options.INDENT_SIZE); - - } - public IndentData getChildOffset(AbstractBlockWrapper child, CodeStyleSettings.IndentOptions options, int targetBlockStartOffset) { final boolean childStartsNewLine = child.getWhiteSpace().containsLineFeeds(); IndentImpl.Type childIndentType = child.getIndent().getType(); @@ -173,7 +143,7 @@ public abstract class AbstractBlockWrapper { if (childStartsNewLine || (!getWhiteSpace().containsLineFeeds() && RELATIVE_INDENT_TYPES.contains(childIndentType) && indentAlreadyUsedBefore(child))) { - childIndent = getIndent(options, child, targetBlockStartOffset); + childIndent = CoreFormatterUtil.getIndent(options, child, targetBlockStartOffset); } else if (child.getIndent().isEnforceIndentToChildren() && !child.getWhiteSpace().containsLineFeeds()) { // Enforce indent if child doesn't start new line, e.g. prefer the code below: @@ -231,7 +201,7 @@ public abstract class AbstractBlockWrapper { } return anchorBlock.getNumberOfSymbolsBeforeBlock(); } - childIndent = getIndent(options, child, getStartOffset()); + childIndent = CoreFormatterUtil.getIndent(options, child, getStartOffset()); } else { childIndent = new IndentData(0); diff --git a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java index f46438928c2d..b245b81a13ff 100644 --- a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java @@ -15,6 +15,7 @@ */ package com.intellij.formatting; +import com.intellij.psi.codeStyle.CodeStyleSettings; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -64,16 +65,19 @@ public interface BlockAlignmentProcessor { @NotNull public final LeafBlockWrapper targetBlock; @NotNull public final Map> alignmentMappings; @NotNull public final Map> backwardShiftedAlignedBlocks; + @NotNull public final CodeStyleSettings.IndentOptions indentOptions; public Context(@NotNull AlignmentImpl alignment, @NotNull LeafBlockWrapper targetBlock, @NotNull Map> alignmentMappings, - @NotNull Map> backwardShiftedAlignedBlocks) + @NotNull Map> backwardShiftedAlignedBlocks, + @NotNull CodeStyleSettings.IndentOptions indentOptions) { this.alignment = alignment; this.targetBlock = targetBlock; this.alignmentMappings = alignmentMappings; this.backwardShiftedAlignedBlocks = backwardShiftedAlignedBlocks; + this.indentOptions = indentOptions; } } } diff --git a/platform/lang-impl/src/com/intellij/formatting/CoreFormatterUtil.java b/platform/lang-impl/src/com/intellij/formatting/CoreFormatterUtil.java index 1d45e6a0fb31..2909a43f5850 100644 --- a/platform/lang-impl/src/com/intellij/formatting/CoreFormatterUtil.java +++ b/platform/lang-impl/src/com/intellij/formatting/CoreFormatterUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.formatting; +import com.intellij.psi.codeStyle.CodeStyleSettings; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -207,4 +208,33 @@ public class CoreFormatterUtil { return true; } + /** + * Calculates indent for the given block and target start offset according to the given indent options. + * + * @param options indent options to use + * @param block target wrapped block + * @param tokenBlockStartOffset target wrapped block offset + * @return indent to use for the given parameters + */ + public static IndentData getIndent(CodeStyleSettings.IndentOptions options, AbstractBlockWrapper block, + final int tokenBlockStartOffset) + { + final IndentImpl indent = block.getIndent(); + if (indent.getType() == Indent.Type.CONTINUATION) { + return new IndentData(options.CONTINUATION_INDENT_SIZE); + } + if (indent.getType() == Indent.Type.CONTINUATION_WITHOUT_FIRST) { + if (block.getStartOffset() != block.getParent().getStartOffset() && block.getStartOffset() == tokenBlockStartOffset) { + return new IndentData(options.CONTINUATION_INDENT_SIZE); + } + else { + return new IndentData(0); + } + } + if (indent.getType() == Indent.Type.LABEL) return new IndentData(options.LABEL_INDENT_SIZE); + if (indent.getType() == Indent.Type.NONE) return new IndentData(0); + if (indent.getType() == Indent.Type.SPACES) return new IndentData(0, indent.getSpaces()); + return new IndentData(options.INDENT_SIZE); + + } } diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index e5799aca2a9e..18ca02120bbf 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -599,7 +599,7 @@ class FormatProcessor { } BlockAlignmentProcessor.Context context = new BlockAlignmentProcessor.Context( - alignment, myCurrentBlock, myAlignmentMappings, myBackwardShiftedAlignedBlocks + alignment, myCurrentBlock, myAlignmentMappings, myBackwardShiftedAlignedBlocks, myIndentOption ); BlockAlignmentProcessor.Result result = alignmentProcessor.applyAlignment(context); switch (result) { diff --git a/platform/lang-impl/src/com/intellij/formatting/LeftEdgeAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/LeftEdgeAlignmentProcessor.java index 86403b27d23e..94f719de1f98 100644 --- a/platform/lang-impl/src/com/intellij/formatting/LeftEdgeAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/LeftEdgeAlignmentProcessor.java @@ -56,9 +56,10 @@ public class LeftEdgeAlignmentProcessor extends AbstractBlockAlignmentProcessor } @Override - protected void applyIndentToTheFirstBlockOnLine(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context) { + protected boolean applyIndentToTheFirstBlockOnLine(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context) { WhiteSpace whiteSpace = context.targetBlock.getWhiteSpace(); whiteSpace.setSpaces(alignmentAnchorIndent.getSpaces(), alignmentAnchorIndent.getIndentSpaces()); + return true; } @Override diff --git a/platform/lang-impl/src/com/intellij/formatting/RightEdgeAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/RightEdgeAlignmentProcessor.java index d3d6d23d110a..210826105dc7 100644 --- a/platform/lang-impl/src/com/intellij/formatting/RightEdgeAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/RightEdgeAlignmentProcessor.java @@ -52,15 +52,50 @@ public class RightEdgeAlignmentProcessor extends AbstractBlockAlignmentProcessor } @Override - protected void applyIndentToTheFirstBlockOnLine(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context) { + protected boolean applyIndentToTheFirstBlockOnLine(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context) { WhiteSpace whiteSpace = context.targetBlock.getWhiteSpace(); int indentSpaces = alignmentAnchorIndent.getIndentSpaces(); int spaces = alignmentAnchorIndent.getSpaces() - context.targetBlock.getSymbolsAtTheLastLine(); if (spaces < 0) { - indentSpaces = Math.max(0, indentSpaces + spaces); + indentSpaces += spaces; spaces = 0; } - whiteSpace.setSpaces(spaces, indentSpaces); + + if (indentSpaces >= 0) { + whiteSpace.setSpaces(spaces, indentSpaces); + return true; + } + if (whiteSpace.getTotalSpaces() > 0) { + // The general idea is that there is a possible case that particular block that starts new line is much wider than its + // preceding aligned block and its white space is not empty. We may move it to the left then trying to preserve its + // indent. + // + // Example: + // block11 block12 + // test-block-that-has-rather-big-width-and-aligned-to-block12 + // Let's say, the last block has indent '10', hence, the result would be: + // block11 block12 + // test-block-that-has-rather-big-width-and-aligned-to-block12 + CompositeBlockWrapper parent = context.targetBlock.getParent(); + if (parent != null) { + IndentData childOffset = CoreFormatterUtil.getIndent( + context.indentOptions, context.targetBlock, context.targetBlock.getStartOffset() + ); + if (whiteSpace.getTotalSpaces() > childOffset.getTotalSpaces()) { + int leftShift = whiteSpace.getTotalSpaces() - childOffset.getTotalSpaces(); + if (leftShift >= whiteSpace.getSpaces()) { + spaces = 0; + indentSpaces = whiteSpace.getIndentSpaces() - (leftShift - whiteSpace.getSpaces()); + } + else { + spaces = whiteSpace.getSpaces() - leftShift; + indentSpaces = whiteSpace.getIndentSpaces(); + } + } + whiteSpace.setSpaces(spaces, indentSpaces); + } + } + return false; } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java index 6aeef1d6dfd9..d7b23d3be7d7 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java @@ -107,7 +107,7 @@ public class NavBarModel { updateModel(psiElement); } else { - if (UISettings.getInstance().SHOW_NAVIGATION_BAR) return; + if (UISettings.getInstance().SHOW_NAVIGATION_BAR && !myModel.isEmpty()) return; Object moduleOrProject = LangDataKeys.MODULE.getData(dataContext); if (moduleOrProject == null) { diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarRootPaneExtension.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarRootPaneExtension.java index 0fe084574760..4b3b06b72ee2 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarRootPaneExtension.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarRootPaneExtension.java @@ -25,6 +25,7 @@ import com.intellij.ide.ui.UISettingsListener; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.wm.IdeRootPaneNorthExtension; @@ -48,6 +49,8 @@ public class NavBarRootPaneExtension extends IdeRootPaneNorthExtension { private NavBarPanel myNavigationBar; private JPanel myRunPanel; private boolean myNavToolbarGroupExist; + private JScrollPane myScrollPane; + private JLabel myCloseIcon; public NavBarRootPaneExtension(Project project) { myProject = project; @@ -122,7 +125,6 @@ public class NavBarRootPaneExtension extends IdeRootPaneNorthExtension { } }; myWrapperPanel.add(buildNavBarPanel(), BorderLayout.CENTER); - myWrapperPanel.putClientProperty("NavBarPanel", myNavigationBar); toggleRunPanel(!UISettings.getInstance().SHOW_MAIN_TOOLBAR); } @@ -185,6 +187,49 @@ public class NavBarRootPaneExtension extends IdeRootPaneNorthExtension { private JComponent buildNavBarPanel() { final JComponent result = new JPanel(new BorderLayout()) { + @Override + public void updateUI() { + super.updateUI(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + removeAll(); + myScrollPane = null; + myCloseIcon = null; + if (myNavigationBar != null && !Disposer.isDisposed(myNavigationBar)) { + Disposer.dispose(myNavigationBar); + } + myNavigationBar = new NavBarPanel(myProject); + myWrapperPanel.putClientProperty("NavBarPanel", myNavigationBar); + myNavigationBar.getModel().setFixedComponent(true); + + myScrollPane = ScrollPaneFactory.createScrollPane(myNavigationBar); + myScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + myScrollPane.setHorizontalScrollBar(null); + myScrollPane.setBorder(null); + + myScrollPane.setOpaque(false); + myScrollPane.getViewport().setOpaque(false); + + setBackground(UIUtil.isUnderGTKLookAndFeel() ? Color.WHITE : UIUtil.getListBackground()); + setOpaque(!UIUtil.isUnderAquaLookAndFeel() || UISettings.getInstance().SHOW_MAIN_TOOLBAR); + setBorder(UIUtil.isUnderAquaLookAndFeel() ? BorderFactory.createEmptyBorder(2, 0, 2, 4) : new NavBarBorder(true, 0)); + myNavigationBar.setBorder(null); + add(myScrollPane, BorderLayout.CENTER); + if (!SystemInfo.isMac) { + myCloseIcon = new JLabel(CROSS_ICON); + myCloseIcon.addMouseListener(new MouseAdapter() { + public void mouseClicked(final MouseEvent e) { + UISettings.getInstance().SHOW_NAVIGATION_BAR = false; + uiSettingsChanged(UISettings.getInstance()); + } + }); + add(myCloseIcon, BorderLayout.EAST); + } + } + }); + } + @Override protected void paintComponent(Graphics g) { if (UIUtil.isUnderAquaLookAndFeel()) { @@ -231,9 +276,9 @@ public class NavBarRootPaneExtension extends IdeRootPaneNorthExtension { final Rectangle r = getBounds(); final Insets insets = getInsets(); int x = insets.left; - - final Component navBar = getComponent(0); - final Component closeLabel = getComponentCount() == 2 ? getComponent(1) : null; + if (myScrollPane == null) return; + final Component navBar = myScrollPane; + final Component closeLabel = myCloseIcon; final Dimension preferredSize = navBar.getPreferredSize(); final Dimension closePreferredSize = closeLabel == null ? new Dimension() : closeLabel.getPreferredSize(); @@ -248,37 +293,7 @@ public class NavBarRootPaneExtension extends IdeRootPaneNorthExtension { } } }; - - result.setBackground(UIUtil.isUnderGTKLookAndFeel() ? Color.WHITE : UIUtil.getListBackground()); - result.setOpaque(!UIUtil.isUnderAquaLookAndFeel() || UISettings.getInstance().SHOW_MAIN_TOOLBAR); - - myNavigationBar = new NavBarPanel(myProject); - myNavigationBar.getModel().setFixedComponent(true); - - JScrollPane scroller = ScrollPaneFactory.createScrollPane(myNavigationBar); - scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - scroller.setHorizontalScrollBar(null); - scroller.setBorder(null); - scroller.setOpaque(false); - scroller.getViewport().setOpaque(false); - - result.add(scroller, BorderLayout.CENTER); - - if (!SystemInfo.isMac) { - JLabel closeLabel = new JLabel(CROSS_ICON); - closeLabel.addMouseListener(new MouseAdapter() { - public void mouseClicked(final MouseEvent e) { - UISettings.getInstance().SHOW_NAVIGATION_BAR = false; - uiSettingsChanged(UISettings.getInstance()); - } - }); - result.add(closeLabel, BorderLayout.EAST); - } - - result.setBorder(UIUtil.isUnderAquaLookAndFeel() ? BorderFactory.createEmptyBorder(2, 0, 2, 4) : new NavBarBorder(true, 0)); - myNavigationBar.setBorder(null); - return result; } diff --git a/platform/lang-impl/src/com/intellij/psi/PsiReferenceContributorImpl.java b/platform/lang-impl/src/com/intellij/psi/PsiReferenceContributorImpl.java deleted file mode 100644 index c937b32861c9..000000000000 --- a/platform/lang-impl/src/com/intellij/psi/PsiReferenceContributorImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi; - -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.patterns.ElementPattern; - -/** - * @author Gregory.Shrago - */ -public class PsiReferenceContributorImpl extends PsiReferenceContributor { - - public static final ExtensionPointName PSI_REFERENCE_PROVIDERS_EP = - new ExtensionPointName("com.intellij.psi.referenceProvider"); - @Override - public void registerReferenceProviders(PsiReferenceRegistrar registrar) { - for (PsiReferenceProviderBean providerBean : PSI_REFERENCE_PROVIDERS_EP.getExtensions()) { - registerReferenceProvider(registrar, providerBean); - } - } - - private static void registerReferenceProvider(PsiReferenceRegistrar registrar, PsiReferenceProviderBean providerBean) { - final ElementPattern pattern = providerBean.createElementPattern(); - if (pattern != null) { - final PsiReferenceProvider provider = providerBean.instantiate(); - if (provider != null) { - registrar.registerReferenceProvider(pattern, provider); - } - } - } -} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java index b96bcdc8ea63..6a9bc57c8539 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java @@ -477,6 +477,8 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable protected boolean visitNode(TreeElement element) { if (nodesToProcess.contains(element)) return false; + if (CodeEditUtil.isPostponedFormattingDisabled(element)) return false; + final boolean currentNodeGenerated = CodeEditUtil.isNodeGenerated(element); CodeEditUtil.setNodeGenerated(element, false); if (currentNodeGenerated && !inGeneratedContext) { @@ -507,6 +509,8 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable inGeneratedContext = oldGeneratedContext; } }); + + CodeEditUtil.enablePostponedFormattingInTree(node); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java index a5fc25fa03bc..69f5f2136fd1 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java @@ -29,10 +29,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.impl.source.tree.Factory; -import com.intellij.psi.impl.source.tree.LeafElement; -import com.intellij.psi.impl.source.tree.TreeElement; -import com.intellij.psi.impl.source.tree.TreeUtil; +import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiUtilBase; @@ -45,6 +42,7 @@ public class CodeEditUtil { private static final Key INDENT_INFO = new Key("INDENT_INFO"); private static final Key REFORMAT_BEFORE_KEY = new Key("REFORMAT_BEFORE_KEY"); private static final Key REFORMAT_KEY = new Key("REFORMAT_KEY"); + private static final Key DISABLE_POSTPONED_REFORMAT_KEY = new Key("DISABLE_POSTPONED_REFORMAT_KEY"); private static final ThreadLocal ALLOW_TO_MARK_NODES_TO_REFORMAT = new ThreadLocal() { @Override protected Boolean initialValue() { @@ -330,12 +328,7 @@ public class CodeEditUtil { } public static void markToReformatBefore(final ASTNode right, boolean value) { - if (value) { - right.putCopyableUserData(REFORMAT_BEFORE_KEY, true); - } - else { - right.putCopyableUserData(REFORMAT_BEFORE_KEY, null); - } + right.putCopyableUserData(REFORMAT_BEFORE_KEY, value ? true : null); } private static int getBlankLines(final String text) { @@ -400,12 +393,7 @@ public class CodeEditUtil { public static void setNodeGenerated(final ASTNode next, final boolean value) { if (next == null) return; - if (value) { - next.putCopyableUserData(GENERATED_FLAG, true); - } - else { - next.putCopyableUserData(GENERATED_FLAG, null); - } + next.putCopyableUserData(GENERATED_FLAG, value ? true : null); } public static void setOldIndentation(final TreeElement treeElement, final int oldIndentation) { @@ -429,7 +417,7 @@ public class CodeEditUtil { * @return true if given node is configured to be reformatted; false otherwise */ public static boolean isMarkedToReformat(final ASTNode node) { - return node.getCopyableUserData(REFORMAT_KEY) != null && ALLOW_NODES_REFORMATTING.get(); + return node.getCopyableUserData(REFORMAT_KEY) != null && isSuspendedNodesReformattingAllowed(); } /** @@ -444,6 +432,26 @@ public class CodeEditUtil { } } + public static void disablePostponedFormatting(@NotNull final ASTNode node) { + markToReformat(node, false); + markToReformatBefore(node, false); + node.putUserData(DISABLE_POSTPONED_REFORMAT_KEY, true); + } + + public static void enablePostponedFormattingInTree(@NotNull ASTNode root) { + ((TreeElement)root).acceptTree(new RecursiveTreeElementVisitor() { + protected boolean visitNode(TreeElement element) { + element.putUserData(DISABLE_POSTPONED_REFORMAT_KEY, null); + return true; + } + }); + + } + + public static boolean isPostponedFormattingDisabled(@NotNull final ASTNode node) { + return node.getUserData(DISABLE_POSTPONED_REFORMAT_KEY) != null; + } + /** * We allow to mark particular {@link ASTNode AST nodes} to be reformatted later (e.g. we may want method definition and calls * to be reformatted when we perform 'change method signature' refactoring. Hence, we mark corresponding expressions diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java index 868ab97bc056..b89a486980e7 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java @@ -22,6 +22,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.util.Trinity; +import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.util.ProcessingContext; import com.intellij.util.SmartList; @@ -52,9 +53,16 @@ public class ReferenceProvidersRegistry { return o2.getThird().compareTo(o1.getThird()); } }; + public final static PsiReferenceProvider NULL_REFERENCE_PROVIDER = new PsiReferenceProvider() { + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { + return PsiReference.EMPTY_ARRAY; + } + }; @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"}) - private final static Map ourRegistrars = new FactoryMap() { + private final Map myRegistrars = new FactoryMap() { @Override protected PsiReferenceRegistrarImpl create(Language language) { PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl(); @@ -70,8 +78,36 @@ public class ReferenceProvidersRegistry { return ServiceManager.getService(ReferenceProvidersRegistry.class); } - public PsiReferenceRegistrar getRegistrar(Language language) { - return ourRegistrars.get(language); + public ReferenceProvidersRegistry() { + + PsiReferenceRegistrarImpl registrar = getRegistrar(Language.ANY); + for (final PsiReferenceProviderBean providerBean : PsiReferenceProviderBean.EP_NAME.getExtensions()) { + final ElementPattern pattern = providerBean.createElementPattern(); + if (pattern != null) { + registrar.registerReferenceProvider(pattern, new PsiReferenceProvider() { + + PsiReferenceProvider myProvider; + + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { + if (myProvider == null) { + + myProvider = providerBean.instantiate(); + if (myProvider == null) { + myProvider = NULL_REFERENCE_PROVIDER; + } + } + return myProvider.getReferencesByElement(element, context); + } + }); + } + } + + } + + public PsiReferenceRegistrarImpl getRegistrar(Language language) { + return myRegistrars.get(language); } @Deprecated @@ -83,10 +119,11 @@ public class ReferenceProvidersRegistry { ProgressManager.checkCanceled(); assert context.isValid() : "Invalid context: " + context; - PsiReferenceRegistrarImpl registrar = ourRegistrars.get(context.getLanguage()); + ReferenceProvidersRegistry registry = getInstance(); + PsiReferenceRegistrarImpl registrar = registry.getRegistrar(context.getLanguage()); SmartList> providers = new SmartList>(); providers.addAll(registrar.getPairsByElement(context, hints)); - providers.addAll(ourRegistrars.get(Language.ANY).getPairsByElement(context, hints)); + providers.addAll(registry.getRegistrar(Language.ANY).getPairsByElement(context, hints)); if (providers.isEmpty()) { return PsiReference.EMPTY_ARRAY; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java index d21f7a81da56..d7acb0d738cb 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java @@ -50,7 +50,7 @@ public class AstBufferUtil { if (composite instanceof LazyParseableElement) { LazyParseableElement lpe = (LazyParseableElement)composite; int lpeResult = lpe.copyTo(buffer, result[0]); - if (lpeResult > 0) { + if (lpeResult >= 0) { result[0] = lpeResult; return; } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/EscapeHandler.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/EscapeHandler.java index 8cf30f26a15e..8751f9339ae2 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/EscapeHandler.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/EscapeHandler.java @@ -30,7 +30,7 @@ public class EscapeHandler extends EditorActionHandler { public void execute(Editor editor, DataContext dataContext) { Project project = PlatformDataKeys.PROJECT.getData(dataContext); - if (project == null || !HintManagerImpl.getInstanceImpl().hideHints(HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.HIDE_BY_ANY_KEY, true, false)) { + if (project == null || !HintManagerImpl.getInstanceImpl().hideHints(HintManager.HIDE_BY_ESCAPE | HintManager.HIDE_BY_ANY_KEY, true, false)) { myOriginalHandler.execute(editor, dataContext); } } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java index d0a16fcd3c0f..10355f027d52 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java @@ -405,7 +405,9 @@ public class HintManagerImpl extends HintManager implements Disposable { LOG.assertTrue(SwingUtilities.isEventDispatchThread()); List hints = new ArrayList(myHintsStack); for (HintInfo info : hints) { - info.hint.hide(); + if (!info.hint.vetoesHiding()) { + info.hint.hide(); + } } cleanup(); } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java b/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java index 8b2d47a7deb1..684e2fa4c27a 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java @@ -16,10 +16,12 @@ package com.intellij.ide.actions; import com.intellij.ide.IdeBundle; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.actions.TextComponentEditorAction; import com.intellij.openapi.project.DumbAware; @@ -27,7 +29,6 @@ import com.intellij.openapi.project.DumbAware; public class SelectAllAction extends TextComponentEditorAction implements DumbAware { public SelectAllAction() { super(new Handler()); - setEnabledInModalContext(true); } private static class Handler extends EditorActionHandler { diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurable.java b/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurable.java index fde991032105..ecccce03f888 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurable.java @@ -55,7 +55,7 @@ public class StatisticsConfigurable implements SearchableConfigurable { @Nullable @NonNls public String getHelpTopic() { - return null; + return "preferences.usage.statictics"; } public JComponent createComponent() { diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.form b/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.form index a0f299834ab9..abc0308b4aaf 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.form +++ b/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.form @@ -14,7 +14,7 @@ - + diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.java b/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.java index d723b8717e61..0d4f1057eb0d 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/configurable/StatisticsConfigurationComponent.java @@ -16,6 +16,7 @@ package com.intellij.internal.statistic.configurable; import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent; +import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.ui.ex.MultiLineLabel; import javax.swing.*; @@ -32,6 +33,7 @@ public class StatisticsConfigurationComponent { private JLabel myLabel; public StatisticsConfigurationComponent() { + myTitle.setText("Help improve "+ ApplicationNamesInfo.getInstance().getFullProductName() + " by sending anonymous usage statistics to JetBrains"); myLabel.setText("We're asking your permission to send information about your plugins configuration (what is enabled and what is not)
and feature usage statistics (e.g. how frequently you're using code completion).
This data is anonymous, does not contain any personal information, collected for use only by JetBrains
and will never be transmitted to any third party."); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java index 6ffff109d4b5..e6c3422b4bb0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler; public class EscapeAction extends EditorAction { public EscapeAction() { super(new Handler()); + setInjectedContext(true); } private static class Handler extends EditorActionHandler { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/TabAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/TabAction.java index a590a220f588..26651392f4f7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/TabAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/TabAction.java @@ -42,6 +42,7 @@ import com.intellij.openapi.vfs.VirtualFile; public class TabAction extends EditorAction { public TabAction() { super(new Handler()); + setInjectedContext(true); } private static class Handler extends EditorWriteActionHandler { @@ -89,7 +90,7 @@ public class TabAction extends EditorAction { EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, "\t", false); } else { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(spacesToAddCount); for(int i=0; i or VFile[] @@ -206,7 +206,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { if (!isUnder) { if (!allowed.isEmpty()) { - assert false : "File accessed outside project: " + child +"; project roots: "+new ArrayList(allowed); + //assert false : "File accessed outside project: " + child +"; project roots: "+new ArrayList(allowed); } } } diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 618d12942776..f372113e7992 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -120,6 +120,7 @@ action.EditorKillToWordEnd.text=Kill to Word End action.EditorKillRegion.text=Kill Selected Region action.EditorKillRingSave.text=Save to Kill Ring action.EditorDuplicate.text=Duplicate Line or Block +action.EditorDuplicateLines.text=Duplicate Lines action.EditorSelectWord.text=Select Word at Caret action.EditorUnSelectWord.text=Unselect Word at Caret action.EditorToggleInsertState.text=Toggle Insert/Overwrite diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index ac366c2adff5..6a88f3bb4493 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -397,8 +397,6 @@ - - diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index 6ea6291bff64..3690ce20398f 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -354,12 +354,18 @@ public class FileUtil { @NotNull public static File createTempFile(@NonNls final File dir, @NotNull @NonNls String prefix, @NonNls String suffix, final boolean create) throws IOException{ + return createTempFile(dir, prefix, suffix, create, true); + } + + public static File createTempFile(@NonNls final File dir, @NotNull @NonNls String prefix, @NonNls String suffix, final boolean create, boolean removeOnExit) throws IOException { File file = doCreateTempFile(prefix, suffix, dir); file.delete(); if (create) { file.createNewFile(); } - file.deleteOnExit(); + if (removeOnExit) { + file.deleteOnExit(); + } return file; } diff --git a/platform/util/src/com/intellij/util/xmlb/annotations/Collection.java b/platform/util/src/com/intellij/util/xmlb/annotations/Collection.java deleted file mode 100644 index 97888bb29ec4..000000000000 --- a/platform/util/src/com/intellij/util/xmlb/annotations/Collection.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2000-2009 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.util.xmlb.annotations; - -public @interface Collection { -} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java index ef9e619d0eb3..676d44110f1b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java @@ -270,4 +270,9 @@ public class XBreakpointBase, P extends XBreakpointP return new XBreakpointBase>(type, breakpointManager, this); } } + + @Override + public String toString() { + return "XBreakpointBase(type=" + myType + ")"; + } } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java index 78d865875057..d90f47a4a4c2 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,19 +49,6 @@ public class ReplaceForEachLoopWithIteratorForLoopIntention extends Intention { if (iteratedValue == null) { return; } - final PsiType type = iteratedValue.getType(); - final PsiType iteratedValueParameterType; - if (type instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)type; - final PsiType[] parameterTypes = classType.getParameters(); - if (parameterTypes.length == 0) { - iteratedValueParameterType = null; - } else { - iteratedValueParameterType = parameterTypes[0]; - } - } else { - iteratedValueParameterType = null; - } @NonNls final StringBuilder newStatement = new StringBuilder(); final PsiParameter iterationParameter = statement.getIterationParameter(); @@ -71,13 +58,9 @@ public class ReplaceForEachLoopWithIteratorForLoopIntention extends Intention { statement, true); final String typeText = parameterType.getCanonicalText(); newStatement.append("for(java.util.Iterator"); - if (iteratedValueParameterType == null) { - newStatement.append(' '); - } else { - newStatement.append('<'); - newStatement.append(iteratedValueParameterType.getCanonicalText()); - newStatement.append("> "); - } + newStatement.append('<'); + newStatement.append(typeText); + newStatement.append("> "); newStatement.append(iterator); newStatement.append(" = "); if (iteratedValue instanceof PsiTypeCastExpression) { @@ -99,12 +82,6 @@ public class ReplaceForEachLoopWithIteratorForLoopIntention extends Intention { newStatement.append(' '); newStatement.append(iterationParameter.getName()); newStatement.append(" = "); - if (iteratedValueParameterType == null && ! - "java.lang.Object".equals(typeText)) { - newStatement.append('('); - newStatement.append(typeText); - newStatement.append(')'); - } newStatement.append(iterator); newStatement.append(".next();"); final PsiStatement body = statement.getBody(); diff --git a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java index f6939e289a44..58260620f5f4 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java +++ b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java @@ -51,6 +51,9 @@ import git4idea.commands.*; import git4idea.config.GitVcsSettings; import git4idea.i18n.GitBundle; import git4idea.rebase.GitRebaser; +import git4idea.stash.GitChangesSaver; +import git4idea.stash.GitShelveChangesSaver; +import git4idea.stash.GitStashChangesSaver; import git4idea.ui.GitUIUtil; import git4idea.update.*; import org.jetbrains.annotations.NotNull; diff --git a/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java b/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java index f0616594052a..c44a1deeafbb 100644 --- a/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java +++ b/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java @@ -44,8 +44,8 @@ import git4idea.checkout.branches.GitBranchConfigurations.BranchChanges; import git4idea.checkout.branches.GitBranchConfigurations.ChangeInfo; import git4idea.checkout.branches.GitBranchConfigurations.ChangeListInfo; import git4idea.commands.*; +import git4idea.stash.GitShelveUtils; import git4idea.ui.GitUIUtil; -import git4idea.update.GitStashUtils; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -591,52 +591,53 @@ public class GitCheckoutProcess { }; continuation.addExceptionHandler(VcsException.class, exceptionConsumer); final GatheringContinuationContext initContext = new GatheringContinuationContext(); - GitStashUtils.doSystemUnshelve(myProject, shelve, myShelveManager, new Runnable() { - @Override - public void run() { - final HashMap, String> parsedChanges = new HashMap, String>(); - for (ChangeInfo changeInfo : changes.CHANGES) { - String before = changeInfo.BEFORE_PATH; - String after = changeInfo.AFTER_PATH; - parsedChanges.put(Pair.create(before, after), changeInfo.CHANGE_LIST_NAME); - } - try { - HashMap lists = new HashMap(); - final List existedChangeLists = myChangeManager.getChangeLists(); - for (LocalChangeList localChangeList : existedChangeLists) { - lists.put(localChangeList.getName(), localChangeList); - } - LocalChangeList defaultList = myChangeManager.getDefaultChangeList(); - for (ChangeListInfo changeListInfo : changes.CHANGE_LISTS) { - LocalChangeList changeList = lists.get(changeListInfo.NAME); - if (changeList == null) { - changeList = myChangeManager.addChangeList(changeListInfo.NAME, changeListInfo.COMMENT); - lists.put(changeListInfo.NAME, changeList); - } - if (changeListInfo.IS_DEFAULT) { - myChangeManager.setDefaultChangeList(changeList); - } - } - for (Change change : defaultList.getChanges()) { - ContentRevision beforeRevision = change.getBeforeRevision(); - String before = beforeRevision == null ? null : beforeRevision.getFile().getPath(); - ContentRevision afterRevision = change.getAfterRevision(); - String after = afterRevision == null ? null : afterRevision.getFile().getPath(); - Pair key = Pair.create(before, after); - String listName = parsedChanges.get(key); - assert listName != null : "List name should be found: " + key; - if (!listName.equals(defaultList.getName())) { - LocalChangeList changeList = lists.get(listName); - assert changeList != null : "Change List should be found: " + listName; - myChangeManager.moveChangesTo(changeList, new Change[]{change}); - } - } - } - catch (Throwable t) { - exceptionConsumer.consume(new VcsException(t)); - } - } - }, initContext); + GitShelveUtils.doSystemUnshelve(myProject, shelve, myShelveManager, new Runnable() { + @Override + public void run() { + final HashMap, String> parsedChanges = + new HashMap, String>(); + for (ChangeInfo changeInfo : changes.CHANGES) { + String before = changeInfo.BEFORE_PATH; + String after = changeInfo.AFTER_PATH; + parsedChanges.put(Pair.create(before, after), changeInfo.CHANGE_LIST_NAME); + } + try { + HashMap lists = new HashMap(); + final List existedChangeLists = myChangeManager.getChangeLists(); + for (LocalChangeList localChangeList : existedChangeLists) { + lists.put(localChangeList.getName(), localChangeList); + } + LocalChangeList defaultList = myChangeManager.getDefaultChangeList(); + for (ChangeListInfo changeListInfo : changes.CHANGE_LISTS) { + LocalChangeList changeList = lists.get(changeListInfo.NAME); + if (changeList == null) { + changeList = myChangeManager.addChangeList(changeListInfo.NAME, changeListInfo.COMMENT); + lists.put(changeListInfo.NAME, changeList); + } + if (changeListInfo.IS_DEFAULT) { + myChangeManager.setDefaultChangeList(changeList); + } + } + for (Change change : defaultList.getChanges()) { + ContentRevision beforeRevision = change.getBeforeRevision(); + String before = beforeRevision == null ? null : beforeRevision.getFile().getPath(); + ContentRevision afterRevision = change.getAfterRevision(); + String after = afterRevision == null ? null : afterRevision.getFile().getPath(); + Pair key = Pair.create(before, after); + String listName = parsedChanges.get(key); + assert listName != null : "List name should be found: " + key; + if (!listName.equals(defaultList.getName())) { + LocalChangeList changeList = lists.get(listName); + assert changeList != null : "Change List should be found: " + listName; + myChangeManager.moveChangesTo(changeList, new Change[]{change}); + } + } + } + catch (Throwable t) { + exceptionConsumer.consume(new VcsException(t)); + } + } + }, initContext); continuation.run(initContext.getList()); } @@ -742,7 +743,7 @@ public class GitCheckoutProcess { if (progress != null) { progress.setText("Creating shelve: " + description); } - ShelvedChangeList shelved = GitStashUtils.shelveChanges(myProject, myShelveManager, toShelve, description, myExceptions); + ShelvedChangeList shelved = GitShelveUtils.shelveChanges(myProject, myShelveManager, toShelve, description, myExceptions); if (shelved == null) { return null; } diff --git a/plugins/git4idea/src/git4idea/commands/GitFileUtils.java b/plugins/git4idea/src/git4idea/commands/GitFileUtils.java index 31d09e596a0a..76f1e4a0ca30 100644 --- a/plugins/git4idea/src/git4idea/commands/GitFileUtils.java +++ b/plugins/git4idea/src/git4idea/commands/GitFileUtils.java @@ -60,15 +60,6 @@ public class GitFileUtils { } } - public static void cherryPick(final Project project, final VirtualFile root, final String hash) throws VcsException { - GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.CHERRY_PICK); - handler.addParameters("-x", "-n", hash); - handler.endOptions(); - //handler.addRelativePaths(new FilePathImpl(root)); - handler.setNoSSH(true); - handler.run(); - } - /** * Delete files * diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 2f1b90faec3a..dd00d82b163a 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -35,20 +35,14 @@ import git4idea.config.GitVcsSettings; import git4idea.config.GitVersionSpecialty; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.git4idea.ssh.GitSSHHandler; import org.jetbrains.git4idea.ssh.GitSSHService; import java.io.File; import java.io.OutputStream; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.LinkedBlockingQueue; /** @@ -635,7 +629,7 @@ public abstract class GitHandler { return myCommandLine.getCommandLineString().length() > VcsFileUtil.FILE_PATH_LIMIT; } - public void runInCurrentThread(Runnable postStartAction) { + public void runInCurrentThread(@Nullable Runnable postStartAction) { final GitVcs vcs = GitVcs.getInstance(myProject); if (vcs == null) { return; } diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 9b9ebca04d64..5760d3b9fd28 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -502,7 +502,7 @@ public class GitHistoryUtils { final String s = parseRefs(refs, currentRefs, locals, remotes, tags); gitCommit = new GitCommit(AbstractHash.create(record.getShortHash()), new SHAHash(record.getHash()), record.getAuthorName(), record.getCommitterName(), - record.getDate(), record.getFullMessage(), + record.getDate(), record.getSubject(), record.getFullMessage(), new HashSet(Arrays.asList(record.getParentsShortHashes())), record.getFilePaths(root), record.getAuthorEmail(), record.getCommitterEmail(), tags, locals, remotes, diff --git a/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java index 43c0486ea12a..9ce3a4615a40 100644 --- a/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java @@ -17,13 +17,13 @@ package git4idea.history.browser; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.vcs.AbstractVcsHelper; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.checkin.CheckinEnvironment; -import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; @@ -31,6 +31,8 @@ import git4idea.GitVcs; import java.util.*; +import static com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier.showOverChangesView; + public class CherryPicker { private final GitVcs myVcs; private final List myCommits; @@ -41,6 +43,7 @@ public class CherryPicker { private final List myDirtyFiles; private final List myMessagesInOrder; private final Map> myFilesToMove; + private boolean myConflictsExist; public CherryPicker(GitVcs vcs, final List commits, LowLevelAccess access) { myVcs = vcs; @@ -90,15 +93,19 @@ public class CherryPicker { } private void showResults() { - if (myExceptions.isEmpty()) { - VcsBalloonProblemNotifier - .showOverChangesView(myVcs.getProject(), "Successful cherry-pick into working tree, please commit changes", MessageType.INFO); + final Project project = myVcs.getProject(); + if (myExceptions.isEmpty() && !myConflictsExist) { + showOverChangesView(project, "Successful cherry-pick into working tree, please commit changes", MessageType.INFO); } else { - VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Errors in cherry-pick", MessageType.ERROR); + if (myExceptions.isEmpty()) { + showOverChangesView(project, "Unresolved conflicts while cherry-picking. Resolve conflicts, then commit changes", MessageType.WARNING); + } else { + showOverChangesView(project, "Errors in cherry-pick", MessageType.ERROR); + } } if ((! myExceptions.isEmpty()) || (! myWarnings.isEmpty())) { myExceptions.addAll(myWarnings); - AbstractVcsHelper.getInstance(myVcs.getProject()).showErrors(myExceptions, "Cherry-pick problems"); + AbstractVcsHelper.getInstance(project).showErrors(myExceptions, "Cherry-pick problems"); } } @@ -129,9 +136,10 @@ public class CherryPicker { private void cherryPickStep(CheckinEnvironment ce, int i) { final GitCommit commit = myCommits.get(i); - final SHAHash hash = commit.getHash(); try { - myAccess.cherryPick(hash); + if (!myAccess.cherryPick(commit)) { + myConflictsExist = true; + } } catch (VcsException e) { myExceptions.add(e); @@ -141,7 +149,7 @@ public class CherryPicker { final Collection paths = ChangesUtil.getPaths(changes); String message = ce.getDefaultMessageFor(paths.toArray(new FilePath[paths.size()])); message = (message == null) ? new StringBuilder().append(commit.getDescription()).append("(cherry picked from commit ") - .append(hash.getValue()).append(")").toString() : message; + .append(commit.getShortHash()).append(")").toString() : message; myMessagesInOrder.add(message); myFilesToMove.put(message, paths); diff --git a/plugins/git4idea/src/git4idea/history/browser/GitCommit.java b/plugins/git4idea/src/git4idea/history/browser/GitCommit.java index 71f2af4485c7..8ecc14275459 100644 --- a/plugins/git4idea/src/git4idea/history/browser/GitCommit.java +++ b/plugins/git4idea/src/git4idea/history/browser/GitCommit.java @@ -31,6 +31,7 @@ public class GitCommit { private final SHAHash myHash; private final String myAuthor; private final String myCommitter; + private final String mySubject; private final String myDescription; private final Date myDate; @@ -60,6 +61,7 @@ public class GitCommit { final String author, final String committer, final Date date, + final String subject, final String description, final Set parentsHashes, final List pathsList, @@ -74,6 +76,7 @@ public class GitCommit { myAuthor = author; myCommitter = committer; myDate = date; + mySubject = subject; myDescription = description; myHash = hash; myParentsHashes = parentsHashes; @@ -223,4 +226,8 @@ public class GitCommit { } }); } + + public String getSubject() { + return mySubject; + } } diff --git a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java index fe88d733ca3f..39959691cf0a 100644 --- a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java +++ b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccess.java @@ -16,7 +16,6 @@ package git4idea.history.browser; import com.intellij.openapi.util.Getter; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.AsynchConsumer; @@ -57,7 +56,14 @@ public interface LowLevelAccess { void loadAllTags(final Collection sink) throws VcsException; - void cherryPick(SHAHash hash) throws VcsException; + /** + * Cherry-picks the specified commit. + * Doesn't autocommit - instead puts the changes into a separate changelist. + * In the case of merge conflict provides the Conflict Resolver dialog. + * @return true if all conflicts were resolved or there were no merge conflicts; false if unresolved files remain. + * @throws VcsException + */ + boolean cherryPick(GitCommit hash) throws VcsException; void loadHashesWithParents(final @NotNull Collection startingPoints, @NotNull final Collection filters, final AsynchConsumer consumer, Getter isCanceled, int useMaxCnt) throws VcsException; List getCommitDetails(final Collection commitIds, SymbolicRefs refs) throws VcsException; diff --git a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java index b2fe33993ac1..8d0ef322c0db 100644 --- a/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java +++ b/plugins/git4idea/src/git4idea/history/browser/LowLevelAccessImpl.java @@ -16,24 +16,37 @@ */ package git4idea.history.browser; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.Key; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; +import com.intellij.openapi.vcs.merge.MergeDialogCustomizer; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.AsynchConsumer; import git4idea.GitBranch; import git4idea.GitTag; -import git4idea.commands.GitFileUtils; +import git4idea.GitVcs; +import git4idea.commands.GitCommand; +import git4idea.commands.GitLineHandler; +import git4idea.commands.GitLineHandlerAdapter; import git4idea.config.GitConfigUtil; import git4idea.history.GitHistoryUtils; import git4idea.history.wholeTree.CommitHashPlusParents; +import git4idea.merge.GitMergeConflictResolver; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.event.HyperlinkEvent; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; public class LowLevelAccessImpl implements LowLevelAccess { private final static Logger LOG = Logger.getInstance("#git4idea.history.browser.LowLevelAccessImpl"); @@ -181,7 +194,94 @@ public class LowLevelAccessImpl implements LowLevelAccess { GitTag.listAsStrings(myProject, myRoot, sink, null); } - public void cherryPick(SHAHash hash) throws VcsException { - GitFileUtils.cherryPick(myProject, myRoot, hash.getValue()); + public boolean cherryPick(GitCommit commit) throws VcsException { + final GitLineHandler handler = new GitLineHandler(myProject, myRoot, GitCommand.CHERRY_PICK); + handler.addParameters("-x", "-n", commit.getHash().getValue()); + handler.endOptions(); + handler.setNoSSH(true); + + final AtomicBoolean conflict = new AtomicBoolean(); + + handler.addLineListener(new GitLineHandlerAdapter() { + public void onLineAvailable(String line, Key outputType) { + if (line.contains("after resolving the conflicts, mark the corrected paths")) { + conflict.set(true); + } + } + }); + handler.runInCurrentThread(null); + + if (conflict.get()) { + boolean allConflictsResolved = new CherryPickConflictResolver(myProject, commit.getShortHash().getString(), commit.getAuthor(), commit.getSubject()).merge(Collections.singleton(myRoot)); + return allConflictsResolved; + } else { + final List errors = handler.errors(); + if (!errors.isEmpty()) { + throw errors.get(0); + } else { // no conflicts, no errors + return true; + } + } } + + private static class CherryPickConflictResolver extends GitMergeConflictResolver { + + private String myCommitHash; + private String myCommitAuthor; + private String myCommitMessage; + + public CherryPickConflictResolver(Project project, String commitHash, String commitAuthor, String commitMessage) { + super(project, false, new CherryPickMergeDialogCustomizer(commitHash, commitAuthor, commitMessage), "Cherry-picked with conflicts", ""); + myCommitHash = commitHash; + myCommitAuthor = commitAuthor; + myCommitMessage = commitMessage; + } + + @Override + protected void notifyUnresolvedRemain(final Collection roots) { + Notifications.Bus.notify(new Notification(GitVcs.IMPORTANT_ERROR_NOTIFICATION, "Conflicts were not resolved during cherry-pick", + "Cherry-pick is not complete, you have unresolved merges in your working tree
" + + "Resolve conflicts.", + NotificationType.WARNING, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + if (event.getDescription().equals("resolve")) { + new CherryPickConflictResolver(myProject, myCommitHash, myCommitAuthor, myCommitMessage).justMerge(roots); + } + } + } + })); + } + } + + private static class CherryPickMergeDialogCustomizer extends MergeDialogCustomizer { + + private String myCommitHash; + private String myCommitAuthor; + private String myCommitMessage; + + public CherryPickMergeDialogCustomizer(String commitHash, String commitAuthor, String commitMessage) { + myCommitHash = commitHash; + myCommitAuthor = commitAuthor; + myCommitMessage = commitMessage; + } + + @Override + public String getMultipleFileMergeDescription(Collection files) { + return "Conflicts during cherry-picking commit " + myCommitHash + " made by " + myCommitAuthor + "
" + + "\"" + myCommitMessage + "\""; + } + + @Override + public String getLeftPanelTitle(VirtualFile file) { + return "Local changes"; + } + + @Override + public String getRightPanelTitle(VirtualFile file, VcsRevisionNumber lastRevisionNumber) { + return "Changes from cherry-pick " + myCommitHash + ""; + } + } + } diff --git a/plugins/git4idea/src/git4idea/history/wholeTree/DetailsLoaderImpl.java b/plugins/git4idea/src/git4idea/history/wholeTree/DetailsLoaderImpl.java index 0293f3462cb0..a3fbe82972d1 100644 --- a/plugins/git4idea/src/git4idea/history/wholeTree/DetailsLoaderImpl.java +++ b/plugins/git4idea/src/git4idea/history/wholeTree/DetailsLoaderImpl.java @@ -194,7 +194,7 @@ public class DetailsLoaderImpl implements DetailsLoader { private GitCommit createNotLoadedCommit(AbstractHash shortHash) { final String notKnown = "Can not load"; - return new GitCommit(shortHash, SHAHash.emulate(shortHash), notKnown, notKnown, new Date(0), + return new GitCommit(shortHash, SHAHash.emulate(shortHash), notKnown, notKnown, new Date(0), notKnown, "Can not load details", Collections.emptySet(), Collections.emptyList(), notKnown, notKnown, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), 0); diff --git a/plugins/git4idea/src/git4idea/merge/GitMergeConflictResolver.java b/plugins/git4idea/src/git4idea/merge/GitMergeConflictResolver.java index faf90fe1c310..834249d06afc 100644 --- a/plugins/git4idea/src/git4idea/merge/GitMergeConflictResolver.java +++ b/plugins/git4idea/src/git4idea/merge/GitMergeConflictResolver.java @@ -42,7 +42,7 @@ import java.util.Collection; public class GitMergeConflictResolver { private static final Logger LOG = Logger.getInstance(GitMergeConflictResolver.class); - private final @NotNull Project myProject; + protected final @NotNull Project myProject; private final boolean myReverseMerge; private final @NotNull String myErrorNotificationTitle; private final @NotNull String myErrorNotificationAdditionalDescription; diff --git a/plugins/git4idea/src/git4idea/update/GitChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java similarity index 99% rename from plugins/git4idea/src/git4idea/update/GitChangesSaver.java rename to plugins/git4idea/src/git4idea/stash/GitChangesSaver.java index cd275d55b89a..69cbdf1c7fb0 100644 --- a/plugins/git4idea/src/git4idea/update/GitChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package git4idea.update; +package git4idea.stash; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; diff --git a/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java similarity index 94% rename from plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java rename to plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java index 57000d3eebad..0dd56f9d70ab 100644 --- a/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package git4idea.update; +package git4idea.stash; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; @@ -62,7 +62,7 @@ public class GitShelveChangesSaver extends GitChangesSaver { String oldProgressTitle = myProgressIndicator.getText(); myProgressIndicator.setText(GitBundle.getString("update.shelving.changes")); List exceptions = new ArrayList(1); - myShelvedChangeList = GitStashUtils.shelveChanges(myProject, myShelveManager, changes, myStashMessage, exceptions); + myShelvedChangeList = GitShelveUtils.shelveChanges(myProject, myShelveManager, changes, myStashMessage, exceptions); myProgressIndicator.setText(oldProgressTitle); if (!exceptions.isEmpty()) { LOG.info("save " + exceptions, exceptions.get(0)); @@ -77,7 +77,7 @@ public class GitShelveChangesSaver extends GitChangesSaver { String oldProgressTitle = myProgressIndicator.getText(); myProgressIndicator.setText(GitBundle.getString("update.unshelving.changes")); if (myShelvedChangeList != null) { - GitStashUtils.doSystemUnshelve(myProject, myShelvedChangeList, myShelveManager, restoreListsRunnable, context); + GitShelveUtils.doSystemUnshelve(myProject, myShelvedChangeList, myShelveManager, restoreListsRunnable, context); } myProgressIndicator.setText(oldProgressTitle); } diff --git a/plugins/git4idea/src/git4idea/update/GitStashUtils.java b/plugins/git4idea/src/git4idea/stash/GitShelveUtils.java similarity index 74% rename from plugins/git4idea/src/git4idea/update/GitStashUtils.java rename to plugins/git4idea/src/git4idea/stash/GitShelveUtils.java index 2c42bf58ff1c..6a9f76655236 100644 --- a/plugins/git4idea/src/git4idea/update/GitStashUtils.java +++ b/plugins/git4idea/src/git4idea/stash/GitShelveUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package git4idea.update; +package git4idea.stash; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; @@ -33,21 +33,13 @@ import com.intellij.openapi.vcs.changes.shelf.ShelvedChange; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.continuation.TaskDescriptor; import com.intellij.util.continuation.Where; import com.intellij.vcsUtil.VcsUtil; import git4idea.GitUtil; import git4idea.GitVcs; -import git4idea.commands.GitCommand; import git4idea.commands.GitFileUtils; -import git4idea.commands.GitSimpleHandler; -import git4idea.commands.StringScanner; -import git4idea.config.GitConfigUtil; -import git4idea.config.GitVersion; -import git4idea.ui.GitUIUtil; -import git4idea.ui.StashInfo; import git4idea.vfs.GitVFSListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,61 +47,13 @@ import org.jetbrains.annotations.Nullable; import javax.swing.event.ChangeEvent; import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; import java.util.*; /** - * The class contains utilities for creating and removing stashes. + * @author Kirill Likhodedov */ -public class GitStashUtils { - /** - * The version when quiet stash supported - */ - private final static GitVersion QUIET_STASH_SUPPORTED = new GitVersion(1, 6, 4, 0); - private static final Logger LOG = Logger.getInstance(GitStashUtils.class.getName()); - - private GitStashUtils() { - } - - /** - * Create stash for later use - * - * @param project the project to use - * @param root the root - * @param message the message for the stash - * @return true if the stash was created, false otherwise - */ - public static boolean saveStash(@NotNull Project project, @NotNull VirtualFile root, final String message) throws VcsException { - GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.STASH); - handler.setNoSSH(true); - handler.addParameters("save", message); - String output = handler.run(); - return !output.startsWith("No local changes to save"); - } - - public static void loadStashStack(@NotNull Project project, @NotNull VirtualFile root, Consumer consumer) { - loadStashStack(project, root, Charset.forName(GitConfigUtil.getLogEncoding(project, root)), consumer); - } - - public static void loadStashStack(@NotNull Project project, @NotNull VirtualFile root, final Charset charset, - final Consumer consumer) { - GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH); - h.setSilent(true); - h.setNoSSH(true); - h.addParameters("list"); - String out; - try { - h.setCharset(charset); - out = h.run(); - } - catch (VcsException e) { - GitUIUtil.showOperationError(project, e, h.printableCommandLine()); - return; - } - for (StringScanner s = new StringScanner(out); s.hasMoreData();) { - consumer.consume(new StashInfo(s.boundedToken(':'), s.boundedToken(':'), s.line().trim())); - } - } +public class GitShelveUtils { + private static final Logger LOG = Logger.getInstance(GitShelveUtils.class.getName()); /** * Perform system level unshelve operation @@ -165,9 +109,9 @@ public class GitStashUtils { }); } - private static void addFilesAfterUnshelve(Project project, - ShelvedChangeList shelvedChangeList, - String projectPath, ContinuationContext context) { + public static void addFilesAfterUnshelve(Project project, + ShelvedChangeList shelvedChangeList, + String projectPath, ContinuationContext context) { Collection paths = new ArrayList(); for (ShelvedChange c : shelvedChangeList.getChanges()) { if (c.getBeforePath() == null || !c.getBeforePath().equals(c.getAfterPath()) || c.getFileStatus() == FileStatus.ADDED) { @@ -195,7 +139,7 @@ public class GitStashUtils { } } - private static void refreshFilesBeforeUnshelve(ShelvedChangeList shelvedChangeList, String projectPath) { + public static void refreshFilesBeforeUnshelve(ShelvedChangeList shelvedChangeList, String projectPath) { HashSet filesToRefresh = new HashSet(); for (ShelvedChange c : shelvedChangeList.getChanges()) { if (c.getBeforePath() != null) { diff --git a/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java similarity index 93% rename from plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java rename to plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java index e9b323e94d77..736f9c5a8eef 100644 --- a/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package git4idea.update; +package git4idea.stash; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; @@ -176,7 +176,7 @@ public class GitStashChangesSaver extends GitChangesSaver { boolean conflictsResolved = new UnstashConflictResolver().merge(Collections.singleton(root)); if (conflictsResolved) { LOG.info("loadRoot " + root + " conflicts resolved, dropping stash"); - dropStash(root); + GitStashUtils.dropStash(myProject, root); } } else { LOG.info("unstash failed " + handler.errors()); @@ -185,22 +185,6 @@ public class GitStashChangesSaver extends GitChangesSaver { } } - // drops stash (after completing conflicting merge during unstashing), shows a warning in case of error - private void dropStash(VirtualFile root) { - final GitSimpleHandler handler = new GitSimpleHandler(myProject, root, GitCommand.STASH); - handler.setNoSSH(true); - handler.addParameters("drop"); - String output = null; - try { - output = handler.run(); - } catch (VcsException e) { - LOG.info("dropStash " + output, e); - GitUIUtil.notifyMessage(myProject, "Couldn't drop stash", - "Couldn't drop stash after resolving conflicts.
Please drop stash manually.", - WARNING, false, handler.errors()); - } - } - // Sort changes from myChangesLists by their git roots. // And use only supplied roots, ignoring changes from other roots. private Map> groupChangesByRoots(Collection rootsToSave) { diff --git a/plugins/git4idea/src/git4idea/stash/GitStashUtils.java b/plugins/git4idea/src/git4idea/stash/GitStashUtils.java new file mode 100644 index 000000000000..53945b065656 --- /dev/null +++ b/plugins/git4idea/src/git4idea/stash/GitStashUtils.java @@ -0,0 +1,101 @@ +/* + * Copyright 2000-2009 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 git4idea.stash; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; +import git4idea.commands.GitCommand; +import git4idea.commands.GitSimpleHandler; +import git4idea.commands.StringScanner; +import git4idea.config.GitConfigUtil; +import git4idea.ui.GitUIUtil; +import git4idea.ui.StashInfo; +import org.jetbrains.annotations.NotNull; + +import java.nio.charset.Charset; + +import static com.intellij.notification.NotificationType.WARNING; + +/** + * The class contains utilities for creating and removing stashes. + */ +public class GitStashUtils { + + private static final Logger LOG = Logger.getInstance(GitStashUtils.class); + + private GitStashUtils() { + } + + /** + * Create stash for later use + * + * @param project the project to use + * @param root the root + * @param message the message for the stash + * @return true if the stash was created, false otherwise + */ + public static boolean saveStash(@NotNull Project project, @NotNull VirtualFile root, final String message) throws VcsException { + GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.STASH); + handler.setNoSSH(true); + handler.addParameters("save", message); + String output = handler.run(); + return !output.startsWith("No local changes to save"); + } + + public static void loadStashStack(@NotNull Project project, @NotNull VirtualFile root, Consumer consumer) { + loadStashStack(project, root, Charset.forName(GitConfigUtil.getLogEncoding(project, root)), consumer); + } + + public static void loadStashStack(@NotNull Project project, @NotNull VirtualFile root, final Charset charset, + final Consumer consumer) { + GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH); + h.setSilent(true); + h.setNoSSH(true); + h.addParameters("list"); + String out; + try { + h.setCharset(charset); + out = h.run(); + } + catch (VcsException e) { + GitUIUtil.showOperationError(project, e, h.printableCommandLine()); + return; + } + for (StringScanner s = new StringScanner(out); s.hasMoreData();) { + consumer.consume(new StashInfo(s.boundedToken(':'), s.boundedToken(':'), s.line().trim())); + } + } + + // drops stash (after completing conflicting merge during unstashing), shows a warning in case of error + public static void dropStash(Project project, VirtualFile root) { + final GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.STASH); + handler.setNoSSH(true); + handler.addParameters("drop"); + String output = null; + try { + output = handler.run(); + } catch (VcsException e) { + LOG.info("dropStash " + output, e); + GitUIUtil.notifyMessage(project, "Couldn't drop stash", + "Couldn't drop stash after resolving conflicts.
Please drop stash manually.", + WARNING, false, handler.errors()); + } + } + +} diff --git a/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java b/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java index 36865fd50fdb..ba8d723cdcdc 100644 --- a/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java +++ b/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java @@ -15,6 +15,11 @@ */ package git4idea.ui; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -23,6 +28,8 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; +import com.intellij.openapi.vcs.merge.MergeDialogCustomizer; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.DocumentAdapter; import com.intellij.util.Consumer; @@ -33,19 +40,19 @@ import git4idea.actions.GitShowAllSubmittedFilesAction; import git4idea.commands.*; import git4idea.config.GitVersionSpecialty; import git4idea.i18n.GitBundle; -import git4idea.update.GitStashUtils; +import git4idea.merge.GitMergeConflictResolver; +import git4idea.stash.GitStashUtils; import git4idea.validators.GitBranchNameValidator; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.DocumentEvent; +import javax.swing.event.HyperlinkEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -102,6 +109,7 @@ public class GitUnstashDialog extends DialogWrapper { */ private final Project myProject; private GitVcs myVcs; + private static final Logger LOG = Logger.getInstance(GitUnstashDialog.class); /** * A constructor @@ -406,10 +414,14 @@ public class GitUnstashDialog extends DialogWrapper { affectedRoots.add(d.getGitRoot()); GitLineHandler h = d.handler(false); final AtomicBoolean needToEscapedBraces = new AtomicBoolean(false); + final AtomicBoolean conflict = new AtomicBoolean(); + h.addLineListener(new GitLineHandlerAdapter() { public void onLineAvailable(String line, Key outputType) { if (line.startsWith("fatal: Needed a single revision")) { needToEscapedBraces.set(true); + } else if (line.contains("Merge conflict")) { + conflict.set(true); } } }); @@ -418,8 +430,66 @@ public class GitUnstashDialog extends DialogWrapper { h = d.handler(true); rc = GitHandlerUtil.doSynchronously(h, GitBundle.getString("unstash.unstashing"), h.printableCommandLine(), false); } - if (rc != 0) { + + if (conflict.get()) { + VirtualFile root = d.getGitRoot(); + boolean conflictsResolved = new UnstashConflictResolver(project, d.getSelectedStash()).merge(Collections.singleton(root)); + if (conflictsResolved) { + LOG.info("loadRoot " + root + " conflicts resolved, dropping stash"); + GitStashUtils.dropStash(project, root); + } + } else if (rc != 0) { GitUIUtil.showOperationErrors(project, h.errors(), h.printableCommandLine()); } } + + private static class UnstashConflictResolver extends GitMergeConflictResolver { + private StashInfo myStashInfo; + + public UnstashConflictResolver(Project project, StashInfo stashInfo) { + super(project, false, new UnstashMergeDialogCustomizer(stashInfo), "Unstashed with conflicts", ""); + myStashInfo = stashInfo; + } + + @Override + protected void notifyUnresolvedRemain(final Collection roots) { + Notifications.Bus.notify(new Notification(GitVcs.IMPORTANT_ERROR_NOTIFICATION, "Conflicts were not resolved during unstash", + "Unstash is not complete, you have unresolved merges in your working tree
" + + "Resolve conflicts.", + NotificationType.WARNING, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + if (event.getDescription().equals("resolve")) { + new UnstashConflictResolver(myProject, myStashInfo).justMerge(roots); + } + } + } + })); + } + } + + private static class UnstashMergeDialogCustomizer extends MergeDialogCustomizer { + + private final StashInfo myStashInfo; + + public UnstashMergeDialogCustomizer(StashInfo stashInfo) { + myStashInfo = stashInfo; + } + + @Override + public String getMultipleFileMergeDescription(Collection files) { + return "Conflicts during unstashing " + myStashInfo.getStash() + "\"" + myStashInfo.getMessage() + "\""; + } + + @Override + public String getLeftPanelTitle(VirtualFile file) { + return "Local changes"; + } + + @Override + public String getRightPanelTitle(VirtualFile file, VcsRevisionNumber lastRevisionNumber) { + return "Changes from stash"; + } + } } diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 1b5a53be66b2..ab4dba37129d 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -35,6 +35,7 @@ import git4idea.merge.GitMergeConflictResolver; import git4idea.merge.GitMergeUtil; import git4idea.merge.GitMerger; import git4idea.rebase.GitRebaser; +import git4idea.stash.GitChangesSaver; import git4idea.ui.GitUIUtil; import org.jetbrains.annotations.NotNull; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrAliasedImportedElementSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrAliasedImportedElementSearcher.java index 5f5e7bbeda39..1cfa50c98c8c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrAliasedImportedElementSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrAliasedImportedElementSearcher.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.findUsages; import com.intellij.openapi.application.QueryExecutorBase; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.*; import com.intellij.psi.search.searches.ReferencesSearch; @@ -42,7 +43,7 @@ public class GrAliasedImportedElementSearcher extends QueryExecutorBase { @Nullable public PsiType fun(GrReferenceExpressionImpl refExpr) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 8a2318319fbd..12ccc64c8c3b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -1128,7 +1128,7 @@ public class PsiUtil { return ((GrListOrMap)firstArg).getNamedArguments(); } - public static boolean seemsToBeQualifiedClassName(@Nullable GrExpression qualifier) { + private static boolean seemsToBeQualifiedClassName(@Nullable GrExpression qualifier) { if (qualifier == null) return false; while (qualifier instanceof GrReferenceExpression) { final PsiElement nameElement = ((GrReferenceExpression)qualifier).getReferenceNameElement();