diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index 3aaaf5f32741..2a67c1f71dc7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -16,15 +16,18 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.CodeInsightUtilBase; +import com.intellij.codeInsight.completion.impl.CompletionServiceImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.searches.AllClassesSearch; import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; @@ -146,14 +149,11 @@ public class AllClassesGetter { final Set qnames = new THashSet(); - final GlobalSearchScope scope = filterByScope ? context.getContainingFile().getResolveScope() : GlobalSearchScope.allScope(context.getProject()); + final Project project = context.getProject(); + final GlobalSearchScope scope = filterByScope ? context.getContainingFile().getResolveScope() : GlobalSearchScope.allScope(project); final boolean pkgContext = JavaCompletionUtil.inSomePackage(context); - AllClassesSearch.search(scope, context.getProject(), new Condition() { - public boolean value(String s) { - return prefixMatcher.prefixMatches(s); - } - }).forEach(new Processor() { + final Processor classProcessor = new Processor() { public boolean process(PsiClass psiClass) { assert psiClass != null; if (isSuitable(context, packagePrefix, qnames, psiClass, filterByScope, pkgContext)) { @@ -162,7 +162,31 @@ public class AllClassesGetter { } return true; } - }); + }; + + PsiShortNamesCache shortNamesCache = JavaPsiFacade.getInstance(project).getShortNamesCache(); + + Set words = WordCompletionContributor.getAllWords(context, parameters.getOffset()); + words.add(prefixMatcher.getPrefix()); + for (String s : words) { + for (PsiClass wordMatch : shortNamesCache.getClassesByName(s, scope)) { + classProcessor.process(wordMatch); + } + } + + final CompletionProgressIndicator indicator = CompletionServiceImpl.getCompletionService().getCurrentCompletion(); + if (indicator != null) { + indicator.delayAllowingFocusedLookup(new Runnable() { + @Override + public void run() { + AllClassesSearch.search(scope, project, new Condition() { + public boolean value(String s) { + return prefixMatcher.prefixMatches(s); + } + }).forEach(classProcessor); + } + }); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index cb7e9d9ddebe..21ee6a6279c6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.completion; +import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix; import com.intellij.codeInsight.hint.ShowParameterInfoHandler; @@ -362,7 +363,18 @@ public class JavaCompletionContributor extends CompletionContributor { return false; } - return StringUtil.isCapitalized(result.getPrefixMatcher().getPrefix()) || parameters.isRelaxedMatching(); + return mayStartClassName(result, parameters.isRelaxedMatching()); + } + + public static boolean mayStartClassName(CompletionResultSet result, final boolean relaxedMatching) { + String prefix = result.getPrefixMatcher().getPrefix(); + if (StringUtil.isEmpty(prefix)) { + return false; + } + + return StringUtil.isCapitalized(prefix) || + relaxedMatching || + CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE == CodeInsightSettings.NONE; } private static void completeAnnotationAttributeName(CompletionResultSet result, PsiElement insertedElement, diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/SortSameNamedVariantsByProximity.java b/java/java-tests/testData/codeInsight/completion/normalSorting/SortSameNamedVariantsByProximity.java index 6b1078a9d0b8..dc49a7914cf0 100644 --- a/java/java-tests/testData/codeInsight/completion/normalSorting/SortSameNamedVariantsByProximity.java +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/SortSameNamedVariantsByProximity.java @@ -3,7 +3,7 @@ import sun.swing.BakedArrayList; class Foo { { Object element; - if (element instanceof bar) + if (element instanceof Bar) } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index a863aea56332..7c7df7ceec1c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -34,6 +34,7 @@ import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.LoadingOrder import com.intellij.openapi.progress.ProgressManager import com.intellij.psi.PsiFile +import com.intellij.codeInsight.CodeInsightSettings /** * @author peter @@ -637,8 +638,8 @@ public interface Test { public void testTemplateSelectionByComma() { myFixture.configureByText("a.java", """ class Foo { - int ITER = 2; int itea = 2; + int itera = 2; { it @@ -646,9 +647,9 @@ class Foo { } """) type 'e' - assertOrderedEquals myFixture.lookupElementStrings, "itea" + assertOrderedEquals myFixture.lookupElementStrings, "itea", "itera" type 'r' - assertOrderedEquals myFixture.lookupElementStrings, "iter", "ITER", "Iterable", "Iterator" + assertOrderedEquals myFixture.lookupElementStrings, "iter", "itera" type ',' assert !lookup assert myFixture.editor.document.text.contains('iter,') @@ -670,9 +671,15 @@ class Foo { } public void testNewClassParenthesis() { - myFixture.configureByText("a.java", """ class Foo { { new } } """) - type 'fil(' - assert myFixture.editor.document.text.contains('new File()') + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE + try { + myFixture.configureByText("a.java", """ class Foo { { new } } """) + type 'fil(' + assert myFixture.editor.document.text.contains('new File()') + } + finally { + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER + } } public void testUnknownMethodParenthesis() { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java index 342b74db2250..74a24d879d02 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java @@ -242,7 +242,7 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { myFixture.addClass("package bar; public class Bar {}"); final String path = getTestName(false) + ".java"; myFixture.configureByFile(getTestName(false) + ".java"); - myFixture.complete(CompletionType.BASIC, 2); + myFixture.complete(CompletionType.BASIC); assertPreferredItems(0, "Bar", "Bar"); List items = getLookup().getItems(); assertEquals(((JavaPsiClassReferenceElement)items.get(0)).getQualifiedName(), "Bar"); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index d8ea6563e2fc..bae4f955b378 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -300,11 +300,17 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { indicator.duringCompletion(initContext); ProgressManager.checkCanceled(); - data.set(CompletionService.getCompletionService().performCompletion(parameters, new Consumer() { + final List items = new ArrayList(); + CompletionService.getCompletionService().performCompletion(parameters, new Consumer() { public void consume(final CompletionResult result) { indicator.addItem(result); + items.add(result.getLookupElement()); } - })); + }); + + indicator.processDelayQueue(); + + data.set(items.toArray(new LookupElement[items.size()])); } }); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index 0a5528a308dc..e10eb7c23a54 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -67,6 +67,7 @@ import javax.swing.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -110,6 +111,8 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement }; private volatile int myCount; private final ConcurrentHashMap myItemSorters = new ConcurrentHashMap(TObjectHashingStrategy.IDENTITY); + private final LinkedList myDelayQueue = new LinkedList(); + private volatile boolean myProcessingDelayedActions; public CompletionProgressIndicator(final Editor editor, CompletionParameters parameters, CodeCompletionHandlerBase handler, Semaphore freezeSemaphore, final OffsetMap offsetMap, boolean hasModifiers) { @@ -194,6 +197,17 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } } + public void delayAllowingFocusedLookup(@NotNull Runnable runnable) { + myDelayQueue.addLast(runnable); + } + + public void processDelayQueue() { + myProcessingDelayedActions = true; + while (!myDelayQueue.isEmpty()) { + myDelayQueue.removeFirst().run(); + } + } + @NotNull CompletionSorterImpl getSorter(LookupElement element) { return myItemSorters.get(element); @@ -314,7 +328,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement if (isOutdated()) return; boolean justShown = false; - if (!myLookup.isShown() && (!isAutopopupCompletion() || !myLookup.isCalculating())) { + if (!myLookup.isShown() && shouldShowLookup()) { if (hideAutopopupIfMeaningless()) { return; } @@ -337,6 +351,13 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } } + private boolean shouldShowLookup() { + if (isAutopopupCompletion() && myLookup.isCalculating()) { + return myProcessingDelayedActions; + } + return true; + } + final boolean isInsideIdentifier() { return getIdentifierEndOffset() != getSelectionEndOffset(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java index 44929f78eb80..b677613ecbf7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java @@ -76,6 +76,8 @@ public class WordCompletionContributor extends CompletionContributor implements return false; } + + final PsiFile file = insertedElement.getContainingFile(); final CompletionData data = CompletionUtil.getCompletionDataByElement(insertedElement, file); if (data != null && !(data instanceof SyntaxTableCompletionData)) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 71303735ee3d..b28f8f8ba5bd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -65,7 +65,9 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.refactoring.inline.InlineMethodConflictSolver; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Set; import static com.intellij.patterns.PlatformPatterns.psiElement; import static com.intellij.patterns.PsiJavaPatterns.elementType; @@ -294,7 +296,7 @@ public class GroovyCompletionContributor extends CompletionContributor { GroovySmartCompletionContributor.addExpectedClassMembers(parameters, result); if (!PsiJavaPatterns.psiElement().inside(GrImportStatement.class).accepts(position)) { - if (StringUtil.isCapitalized(result.getPrefixMatcher().getPrefix()) || parameters.isRelaxedMatching()) { + if (JavaCompletionContributor.mayStartClassName(result, parameters.isRelaxedMatching())) { addAllClasses(parameters, result, inheritors); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index c149ac5545b2..f0be2a8facf3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -15,10 +15,11 @@ */ package org.jetbrains.plugins.groovy.completion +import com.intellij.codeInsight.CodeInsightSettings import com.intellij.codeInsight.completion.CompletionAutoPopupTestCase import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.groovy.LightGroovyTestCase /** * @author peter @@ -78,9 +79,15 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { } public void testPossibleClosureParameter2() { - myFixture.configureByText("a.gpp", "{ a, }") - type 'h' - assert !lookup.focused + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE + try { + myFixture.configureByText("a.gpp", "{ a, }") + type 'h' + assert !lookup.focused + } + finally { + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER + } } public void testImpossibleClosureParameter() { @@ -90,9 +97,15 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { } public void testFieldTypeLowercase() { - myFixture.configureByText "a.groovy", "class Foo { }" - type 'aioobe' - assert myFixture.lookupElementStrings == [ArrayIndexOutOfBoundsException.simpleName] + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE + try { + myFixture.configureByText "a.groovy", "class Foo { }" + type 'aioobe' + assert myFixture.lookupElementStrings == [ArrayIndexOutOfBoundsException.simpleName] + } + finally { + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER + } } public void testNoWordCompletionAutoPopup() {