package com.google.jstestdriver.idea.assertFramework.codeInsight; import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementPresentation; import com.intellij.codeInsight.template.Template; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Ref; import com.intellij.patterns.PlatformPatterns; import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.List; public class FilteringCompletionContributor extends CompletionContributor { public FilteringCompletionContributor() { extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new CompletionProvider<CompletionParameters>() { @Override protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull final CompletionResultSet result) { final List<JsCallTemplateContextProvider> providers = filterContextProviders( result.getPrefixMatcher().getPrefix(), parameters ); final Ref<CompletionSorter> firstSorterRef = Ref.create(null); result.runRemainingContributors(parameters, new Consumer<CompletionResult>() { @Override public void consume(CompletionResult completionResult) { LookupElement element = completionResult.getLookupElement(); if (!canWeDoBetter(element, providers)) { result.passResult(completionResult); if (firstSorterRef.isNull()) { firstSorterRef.set(completionResult.getSorter()); } } } }, true); CompletionSorter firstSorter = firstSorterRef.get(); CompletionResultSet newResult = firstSorter != null ? result.withRelevanceSorter(firstSorter) : result; fillCallTemplateVariants(newResult, providers); } }); } @NotNull private static List<JsCallTemplateContextProvider> filterContextProviders(@NotNull final String prefix, @NotNull final CompletionParameters parameters) { return ContainerUtil.filter(JsCallTemplateContextProvider.EP_NAME.getExtensions(), new Condition<JsCallTemplateContextProvider>() { @Override public boolean value(JsCallTemplateContextProvider contextProvider) { if (!contextProvider.getCalledFunctionName().startsWith(prefix)) { return false; } return contextProvider.isInContext(parameters); } }); } private static boolean canWeDoBetter(@NotNull LookupElement lookupElement, List<JsCallTemplateContextProvider> providers) { final String lookupString = lookupElement.getLookupString(); return ContainerUtil.or(providers, new Condition<JsCallTemplateContextProvider>() { @Override public boolean value(JsCallTemplateContextProvider contextProvider) { return contextProvider.getCalledFunctionName().equals(lookupString); } }); } private static void fillCallTemplateVariants(@NotNull CompletionResultSet result, @NotNull List<JsCallTemplateContextProvider> providers) { for (final JsCallTemplateContextProvider provider : providers) { final String expectedCallFunctionName = provider.getCalledFunctionName(); Template template = provider.getTemplate(); MethodTemplateLookupElement item = new MethodTemplateLookupElement(expectedCallFunctionName, template) { @Override public void renderElement(LookupElementPresentation presentation) { presentation.setItemText(expectedCallFunctionName); presentation.setTailText(provider.getTailText(), true); presentation.setTypeText(provider.getTypeText()); } }; result.addElement(item); } } }