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 dc5145889225..cf15f678bd2f 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 @@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; @@ -74,12 +75,14 @@ import org.jetbrains.plugins.groovy.refactoring.DefaultGroovyVariableNameValidat import org.jetbrains.plugins.groovy.refactoring.GroovyNameSuggestionUtil; import org.jetbrains.plugins.groovy.refactoring.inline.InlineMethodConflictSolver; -import java.util.*; +import java.util.Collections; +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; -import static com.intellij.util.containers.CollectionFactory.arrayList; -import static com.intellij.util.containers.CollectionFactory.hashMap; +import static com.intellij.util.containers.CollectionFactory.*; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.SEPARATORS; import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.WHITE_SPACES_OR_COMMENTS; @@ -328,7 +331,12 @@ public class GroovyCompletionContributor extends CompletionContributor { GroovySmartCompletionContributor.generateInheritorVariants(parameters, result.getPrefixMatcher(), inheritors); } - result.addAllElements(completeReference(parameters, reference, inheritors, result.getPrefixMatcher())); + Runnable addSlowVariants = completeReference(parameters, reference, inheritors, result.getPrefixMatcher(), new Consumer() { + @Override + public void consume(LookupElement lookupElement) { + result.addElement(lookupElement); + } + }); if (reference.getQualifier() == null) { GroovySmartCompletionContributor.addExpectedClassMembers(parameters, result); @@ -342,6 +350,8 @@ public class GroovyCompletionContributor extends CompletionContributor { } } } + + addSlowVariants.run(); } }); @@ -422,27 +432,37 @@ public class GroovyCompletionContributor extends CompletionContributor { super.fillCompletionVariants(parameters, result); } - static LinkedHashSet completeReference(final CompletionParameters parameters, - GrReferenceElement reference, final InheritorsHolder inheritorsHolder, final PrefixMatcher matcher) { + @NotNull + static Runnable completeReference(final CompletionParameters parameters, + GrReferenceElement reference, final InheritorsHolder inheritorsHolder, final PrefixMatcher matcher, final Consumer _consumer) { + final Consumer consumer = new Consumer() { + final Set added = hashSet(); + @Override + public void consume(LookupElement element) { + if (added.add(element)) { + _consumer.consume(element); + } + } + }; + final PsiElement position = parameters.getPosition(); final Map staticMembers = hashMap(); final PsiElement qualifier = reference.getQualifier(); final PsiType qualifierType = qualifier instanceof GrExpression ? ((GrExpression)qualifier).getType() : null; - LinkedHashSet result = new LinkedHashSet(); final Set unresolvedProps; if (reference instanceof GrReferenceExpression && (qualifier instanceof GrExpression || qualifier == null)) { unresolvedProps = CompleteReferenceExpression.getVariantsWithSameQualifier(matcher, (GrExpression)qualifier, (GrReferenceExpression)reference); for (String string : unresolvedProps) { - result.add(LookupElementBuilder.create(string).withItemTextUnderlined(true)); + consumer.consume(LookupElementBuilder.create(string).withItemTextUnderlined(true)); } if (parameters.getInvocationCount() < 2 && qualifier != null && qualifierType == null && !(qualifier instanceof GrReferenceExpression && ((GrReferenceExpression)qualifier).resolve() instanceof PsiPackage)) { if (parameters.getInvocationCount() == 1) { showInfo(); } - return result; + return EmptyRunnable.INSTANCE; } } else { @@ -451,7 +471,7 @@ public class GroovyCompletionContributor extends CompletionContributor { final ElementFilter classFilter = getClassFilter(position); - final List items = arrayList(); + final List zeroPriority = arrayList(); reference.processVariants(matcher, parameters, new Consumer() { public void consume(LookupElement lookupElement) { Object object = lookupElement.getObject(); @@ -481,74 +501,78 @@ public class GroovyCompletionContributor extends CompletionContributor { ((PsiModifierListOwner)object).hasModifierProperty(PsiModifier.STATIC)) { if (lookupElement.getLookupString().equals(((PsiMember)object).getName())) { staticMembers.put(CompletionUtil.getOriginalOrSelf((PsiModifierListOwner)object), lookupElement); - return; } } if (object instanceof PsiClass && !classFilter.isAcceptable(object, position)) { return; } - items.add(lookupElement); + PrioritizedLookupElement prio = lookupElement.as(PrioritizedLookupElement.CLASS_CONDITION_KEY); + if (prio == null || prio.getPriority() == 0) { + zeroPriority.add(lookupElement); + } else { + consumer.consume(lookupElement); + } } }); + for (LookupElement element : zeroPriority) { + consumer.consume(element); + } + if (qualifier == null) { - addStaticMembers(parameters, matcher, staticMembers); + return addStaticMembers(parameters, matcher, staticMembers, consumer); } - items.addAll(staticMembers.values()); - - for (Iterator iterator = items.iterator(); iterator.hasNext(); ) { - LookupElement element = iterator.next(); - PrioritizedLookupElement prio = element.as(PrioritizedLookupElement.CLASS_CONDITION_KEY); - if (prio == null || prio.getPriority() >= 0) { - result.add(element); - iterator.remove(); - } - } - result.addAll(items); - - return result; + return EmptyRunnable.INSTANCE; } - private static void addStaticMembers(CompletionParameters parameters, + private static Runnable addStaticMembers(CompletionParameters parameters, final PrefixMatcher matcher, - final Map staticMembers) { - StaticMemberProcessor processor = completeStaticMembers(parameters); - if (parameters.getInvocationCount() < 2) { - processor.processMembersOfRegisteredClasses(matcher, new PairConsumer() { - @Override - public void consume(PsiMember member, PsiClass psiClass) { - if (member instanceof GrAccessorMethod) { - member = ((GrAccessorMethod)member).getProperty(); - } - member = CompletionUtil.getOriginalOrSelf(member); - if (staticMembers.containsKey(member)) { - return; - } - final String name = member.getName(); - if (name == null || !matcher.prefixMatches(name)) { - staticMembers.remove(member); - return; - } - staticMembers.put(member, createGlobalMemberElement(member, psiClass, true)); + final Map staticMembers, final Consumer consumer) { + final StaticMemberProcessor processor = completeStaticMembers(parameters); + processor.processMembersOfRegisteredClasses(matcher, new PairConsumer() { + @Override + public void consume(PsiMember member, PsiClass psiClass) { + if (member instanceof GrAccessorMethod) { + member = ((GrAccessorMethod)member).getProperty(); } - }); - } else if (StringUtil.isNotEmpty(matcher.getPrefix())) { - processor.processStaticMethodsGlobally(matcher, new Consumer() { - @Override - public void consume(LookupElement element) { - PsiMember member = (PsiMember)element.getObject(); - if (member instanceof GrAccessorMethod) { - member = ((GrAccessorMethod)member).getProperty(); - } - member = CompletionUtil.getOriginalOrSelf(member); - if (staticMembers.containsKey(member)) { - return; - } - staticMembers.put(member, element); + member = CompletionUtil.getOriginalOrSelf(member); + if (staticMembers.containsKey(member)) { + return; } - }); + final String name = member.getName(); + if (name == null || !matcher.prefixMatches(name)) { + staticMembers.remove(member); + return; + } + JavaGlobalMemberLookupElement element = createGlobalMemberElement(member, psiClass, true); + staticMembers.put(member, element); + consumer.consume(element); + } + }); + if (parameters.getInvocationCount() >= 2 && StringUtil.isNotEmpty(matcher.getPrefix())) { + return new Runnable() { + @Override + public void run() { + processor.processStaticMethodsGlobally(matcher, new Consumer() { + @Override + public void consume(LookupElement element) { + PsiMember member = (PsiMember)element.getObject(); + if (member instanceof GrAccessorMethod) { + member = ((GrAccessorMethod)member).getProperty(); + } + member = CompletionUtil.getOriginalOrSelf(member); + if (staticMembers.containsKey(member)) { + return; + } + staticMembers.put(member, element); + consumer.consume(element); + } + }); + } + }; } + return EmptyRunnable.INSTANCE; } private static void showInfo() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java index 3efdb7210d84..f69322d57730 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java @@ -104,15 +104,18 @@ public class GroovyNoVariantsDelegator extends CompletionContributor { GrReferenceElement ref = createMockReference(position, type, base); PsiElement refName = ref.getReferenceNameElement(); assert refName != null; - for (LookupElement element : GroovyCompletionContributor.completeReference( - parameters.withPosition(refName, refName.getTextRange().getStartOffset()), ref, inheritors, result.getPrefixMatcher())) { - qualifiedCollector.addElement(new JavaChainLookupElement(base, element) { - @Override - protected boolean shouldParenthesizeQualifier(PsiFile file, int startOffset, int endOffset) { - return false; - } - }); - } + CompletionParameters newParams = parameters.withPosition(refName, refName.getTextRange().getStartOffset()); + GroovyCompletionContributor.completeReference(newParams, ref, inheritors, result.getPrefixMatcher(), new Consumer() { + @Override + public void consume(LookupElement element) { + qualifiedCollector.addElement(new JavaChainLookupElement(base, element) { + @Override + protected boolean shouldParenthesizeQualifier(PsiFile file, int startOffset, int endOffset) { + return false; + } + }); + } + }); } } } @@ -142,11 +145,14 @@ public class GroovyNoVariantsDelegator extends CompletionContributor { final PrefixMatcher qMatcher = new CamelHumpMatcher(referenceName); final Set variants = new LinkedHashSet(); - for (LookupElement element : GroovyCompletionContributor.completeReference(parameters, qualifier, inheritors, qMatcher)) { - if (qMatcher.prefixMatches(element)) { - variants.add(element); + GroovyCompletionContributor.completeReference(parameters, qualifier, inheritors, qMatcher, new Consumer() { + @Override + public void consume(LookupElement element) { + if (qMatcher.prefixMatches(element)) { + variants.add(element); + } } - } + }); for (PsiClass aClass : PsiShortNamesCache.getInstance(qualifier.getProject()).getClassesByName(referenceName, qualifier.getResolveScope())) { variants.add(GroovyCompletionUtil.createClassLookupItem(aClass));