diff --git a/platform/analysis-impl/resources/META-INF/AnalysisImpl.xml b/platform/analysis-impl/resources/META-INF/AnalysisImpl.xml index 93d3d5b91e08..0f93f587b8f6 100644 --- a/platform/analysis-impl/resources/META-INF/AnalysisImpl.xml +++ b/platform/analysis-impl/resources/META-INF/AnalysisImpl.xml @@ -17,6 +17,8 @@ + ) { + myApiCompletionProcess = parameters.process as CompletionProcessEx + try { + super.performCompletion(parameters, consumer) + } + finally { + myApiCompletionProcess = null + } + } + + override fun createResultSet(parameters: CompletionParameters, + consumer: Consumer, + contributor: CompletionContributor, + matcher: PrefixMatcher): CompletionResultSet { + return BaseCompletionResultSet(consumer, matcher, contributor, parameters, defaultSorter(parameters, matcher), null) + } + + override fun suggestPrefix(parameters: CompletionParameters): String { + val position = parameters.position + val offset = parameters.offset + val range = position.textRange + assert(range.containsOffset(offset)) { "$position; $offset not in $range" } + @Suppress("DEPRECATION") + return CompletionData.findPrefixStatic(position, offset) + } + + override fun createMatcher(prefix: String, typoTolerant: Boolean): PrefixMatcher = createMatcher(prefix, true, typoTolerant) + + override fun getCurrentCompletion(): CompletionProcess? = myApiCompletionProcess + + override fun defaultSorter(parameters: CompletionParameters?, matcher: PrefixMatcher?): CompletionSorterImpl { + val location = CompletionLocation(parameters) + + var sorter = emptySorter() + sorter = addWeighersBefore(sorter) + //sorter = sorter.withClassifier(CompletionSorterImpl.weighingFactory(LiveTemplateWeigher())) + sorter = sorter.withClassifier(CompletionSorterImpl.weighingFactory(PreferStartMatching())) + + for (weigher in WeighingService.getWeighers(RELEVANCE_KEY)) { + val id = weigher.toString() + sorter = when (id) { + "prefix" -> { + sorter.withClassifier(CompletionSorterImpl.weighingFactory(RealPrefixMatchingWeigher())) + } + "stats" -> { + processStatsWeigher(sorter, weigher, location) + } + else -> { + sorter.weigh(object : LookupElementWeigher(id, true, false) { + override fun weigh(element: LookupElement): Comparable<*>? { + return weigher.weigh(element, location) + } + }) + } + } + } + + return sorter.withClassifier("priority", true, object : ClassifierFactory("liftShorter") { + override fun createClassifier(next: Classifier): Classifier { + return LiftShorterItemsClassifier("liftShorter", next, LiftingCondition(), false) + } + }) + } + + protected open fun addWeighersBefore(sorter: CompletionSorterImpl): CompletionSorterImpl = sorter + + protected open fun processStatsWeigher(sorter: CompletionSorterImpl, + weigher: Weigher, + location: CompletionLocation): CompletionSorterImpl = sorter + + override fun emptySorter(): CompletionSorterImpl = CompletionSorterImpl(listOf()) + + protected open class BaseCompletionResultSet(consumer: Consumer, + matcher: PrefixMatcher, + contributor: CompletionContributor, + @JvmField protected val myParameters: CompletionParameters, + @JvmField protected val mySorter: CompletionSorterImpl, + @JvmField protected val myOriginal: BaseCompletionResultSet?) : + CompletionResultSet(matcher, consumer, contributor) { + override fun addElement(element: LookupElement) { + ProgressManager.checkCanceled() + if (!element.isValid) { + LOG.error("Invalid lookup element: " + element + " of " + element.javaClass + + " in " + myParameters.originalFile + " of " + myParameters.originalFile.javaClass) + return + } + + val matched = CompletionResult.wrap(element, prefixMatcher, mySorter) + matched?.let { passResult(it) } + } + + override fun withPrefixMatcher(matcher: PrefixMatcher): CompletionResultSet = + if (matcher == prefixMatcher) this + else BaseCompletionResultSet(consumer, matcher, myContributor, myParameters, mySorter, this) + + override fun withPrefixMatcher(prefix: String): CompletionResultSet = withPrefixMatcher(prefixMatcher.cloneWithPrefix(prefix)) + + override fun stopHere() { + if (LOG.isTraceEnabled) { + LOG.trace("Completion stopped\n" + DebugUtil.currentStackTrace()) + } + super.stopHere() + myOriginal?.stopHere() + } + + override fun withRelevanceSorter(sorter: CompletionSorter): CompletionResultSet = + BaseCompletionResultSet(consumer, prefixMatcher, myContributor, myParameters, sorter as CompletionSorterImpl, this) + + override fun addLookupAdvertisement(text: String) { + (getCompletionService().currentCompletion as CompletionProcessEx?)?.addAdvertisement(text, null) + } + + override fun caseInsensitive(): CompletionResultSet { + val matcher = prefixMatcher + val typoTolerant = matcher is CamelHumpMatcher && matcher.isTypoTolerant + return withPrefixMatcher(createMatcher(matcher.prefix, false, typoTolerant)) + } + + override fun restartCompletionOnPrefixChange(prefixCondition: ElementPattern?) { + } + + override fun restartCompletionWhenNothingMatches() { + } + } + + companion object { + private val LOG = logger() + + private fun createMatcher(prefix: String, caseSensitive: Boolean, typoTolerant: Boolean): CamelHumpMatcher { + return CamelHumpMatcher(prefix, caseSensitive, typoTolerant) + } + } +} \ No newline at end of file diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java b/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java index 8cc0281f8914..206599f5e95a 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java @@ -65,7 +65,8 @@ public class CamelHumpMatcher extends PrefixMatcher { return false; } - boolean isTypoTolerant() { + @ApiStatus.Internal + public boolean isTypoTolerant() { return myTypoTolerant; } diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java b/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java index 8a87de201f09..bfabb9cd4e4d 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java @@ -1,23 +1,10 @@ -/* - * 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. - */ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.completion.impl; import com.intellij.codeInsight.completion.CompletionSorter; import com.intellij.codeInsight.lookup.*; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -30,7 +17,8 @@ public class CompletionSorterImpl extends CompletionSorter { private final List> myMembers; private final int myHashCode; - CompletionSorterImpl(List> members) { + @ApiStatus.Internal + public CompletionSorterImpl(List> members) { myMembers = members; myHashCode = myMembers.hashCode(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java index de82d9cc305c..881c72a3ceb3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java @@ -5,38 +5,29 @@ import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.Classifier; import com.intellij.codeInsight.lookup.ClassifierFactory; import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementWeigher; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.TextRange; import com.intellij.patterns.ElementPattern; -import com.intellij.psi.PsiElement; import com.intellij.psi.Weigher; -import com.intellij.psi.WeighingService; -import com.intellij.psi.impl.DebugUtil; import com.intellij.util.Consumer; import com.intellij.util.ExceptionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; - /** * @author peter */ -public final class CompletionServiceImpl extends CompletionService { +public final class CompletionServiceImpl extends BaseCompletionService { private static final Logger LOG = Logger.getInstance(CompletionServiceImpl.class); private static volatile CompletionPhase ourPhase = CompletionPhase.NoCompletion; private static Throwable ourPhaseTrace; - @Nullable private CompletionProcess myApiCompletionProcess; - public CompletionServiceImpl() { + super(); ApplicationManager.getApplication().getMessageBus().connect().subscribe(ProjectManager.TOPIC, new ProjectManagerListener() { @Override public void projectClosing(@NotNull Project project) { @@ -44,27 +35,17 @@ public final class CompletionServiceImpl extends CompletionService { if (indicator != null && indicator.getProject() == project) { indicator.closeAndFinish(true); setCompletionPhase(CompletionPhase.NoCompletion); - } else if (indicator == null) { + } + else if (indicator == null) { setCompletionPhase(CompletionPhase.NoCompletion); } } }); } - @Override - public void performCompletion(final CompletionParameters parameters, final Consumer consumer) { - myApiCompletionProcess = parameters.getProcess(); - try { - super.performCompletion(parameters, consumer); - } - finally { - myApiCompletionProcess = null; - } - } - @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass"}) public static CompletionServiceImpl getCompletionService() { - return (CompletionServiceImpl) CompletionService.getCompletionService(); + return (CompletionServiceImpl)CompletionService.getCompletionService(); } @Override @@ -77,29 +58,10 @@ public final class CompletionServiceImpl extends CompletionService { } @Override - protected String suggestPrefix(CompletionParameters parameters) { - final PsiElement position = parameters.getPosition(); - final int offset = parameters.getOffset(); - TextRange range = position.getTextRange(); - assert range.containsOffset(offset) : position + "; " + offset + " not in " + range; - //noinspection deprecation - return CompletionData.findPrefixStatic(position, offset); - } - - @Override - @NotNull - protected PrefixMatcher createMatcher(String prefix, boolean typoTolerant) { - return createMatcher(prefix, true, typoTolerant); - } - - @NotNull - private static CamelHumpMatcher createMatcher(String prefix, boolean caseSensitive, boolean typoTolerant) { - return new CamelHumpMatcher(prefix, caseSensitive, typoTolerant); - } - - @Override - protected CompletionResultSet createResultSet(CompletionParameters parameters, Consumer consumer, - @NotNull CompletionContributor contributor, PrefixMatcher matcher) { + protected CompletionResultSet createResultSet(@NotNull CompletionParameters parameters, + @NotNull Consumer consumer, + @NotNull CompletionContributor contributor, + @NotNull PrefixMatcher matcher) { return new CompletionResultSetImpl(consumer, matcher, contributor, parameters, defaultSorter(parameters, matcher), null); } @@ -117,19 +79,11 @@ public final class CompletionServiceImpl extends CompletionService { return null; } - private static class CompletionResultSetImpl extends CompletionResultSet { - private final CompletionParameters myParameters; - private final CompletionSorterImpl mySorter; - @Nullable - private final CompletionResultSetImpl myOriginal; - + private static class CompletionResultSetImpl extends BaseCompletionResultSet { CompletionResultSetImpl(Consumer consumer, PrefixMatcher prefixMatcher, CompletionContributor contributor, CompletionParameters parameters, @NotNull CompletionSorterImpl sorter, @Nullable CompletionResultSetImpl original) { - super(prefixMatcher, consumer, contributor); - myParameters = parameters; - mySorter = sorter; - myOriginal = original; + super(consumer, prefixMatcher, contributor, parameters, sorter, original); } @Override @@ -137,52 +91,20 @@ public final class CompletionServiceImpl extends CompletionService { CompletionThreadingBase.withBatchUpdate(() -> super.addAllElements(elements), myParameters.getProcess()); } - @Override - public void addElement(@NotNull final LookupElement element) { - ProgressManager.checkCanceled(); - if (!element.isValid()) { - LOG.error("Invalid lookup element: " + element + " of " + element.getClass() + - " in " + myParameters.getOriginalFile() + " of " + myParameters.getOriginalFile().getClass()); - return; - } - - CompletionResult matched = CompletionResult.wrap(element, getPrefixMatcher(), mySorter); - if (matched != null) { - passResult(matched); - } - } - @Override @NotNull public CompletionResultSet withPrefixMatcher(@NotNull final PrefixMatcher matcher) { if (matcher.equals(getPrefixMatcher())) { return this; } - + return new CompletionResultSetImpl(getConsumer(), matcher, myContributor, myParameters, mySorter, this); } - @Override - public void stopHere() { - if (LOG.isTraceEnabled()) { - LOG.trace("Completion stopped\n" + DebugUtil.currentStackTrace()); - } - super.stopHere(); - if (myOriginal != null) { - myOriginal.stopHere(); - } - } - - @Override - @NotNull - public CompletionResultSet withPrefixMatcher(@NotNull final String prefix) { - return withPrefixMatcher(getPrefixMatcher().cloneWithPrefix(prefix)); - } - @NotNull @Override public CompletionResultSet withRelevanceSorter(@NotNull CompletionSorter sorter) { - return new CompletionResultSetImpl(getConsumer(), getPrefixMatcher(), myContributor, myParameters, (CompletionSorterImpl) sorter, + return new CompletionResultSetImpl(getConsumer(), getPrefixMatcher(), myContributor, myParameters, (CompletionSorterImpl)sorter, this); } @@ -191,19 +113,12 @@ public final class CompletionServiceImpl extends CompletionService { getCompletionService().setAdvertisementText(text); } - @NotNull - @Override - public CompletionResultSet caseInsensitive() { - PrefixMatcher matcher = getPrefixMatcher(); - boolean typoTolerant = matcher instanceof CamelHumpMatcher && ((CamelHumpMatcher)matcher).isTypoTolerant(); - return withPrefixMatcher(createMatcher(matcher.getPrefix(), false, typoTolerant)); - } - @Override public void restartCompletionOnPrefixChange(ElementPattern prefixCondition) { CompletionProcess process = myParameters.getProcess(); if (process instanceof CompletionProgressIndicator) { - ((CompletionProgressIndicator)process).addWatchedPrefix(myParameters.getOffset() - getPrefixMatcher().getPrefix().length(), prefixCondition); + ((CompletionProgressIndicator)process) + .addWatchedPrefix(myParameters.getOffset() - getPrefixMatcher().getPrefix().length(), prefixCondition); } } @@ -239,12 +154,14 @@ public final class CompletionServiceImpl extends CompletionService { CompletionPhase oldPhase = getCompletionPhase(); CompletionProgressIndicator oldIndicator = oldPhase.indicator; if (oldIndicator != null && !(phase instanceof CompletionPhase.BgCalculation)) { - LOG.assertTrue(!oldIndicator.isRunning() || oldIndicator.isCanceled(), "don't change phase during running completion: oldPhase=" + oldPhase); + LOG.assertTrue(!oldIndicator.isRunning() || oldIndicator.isCanceled(), + "don't change phase during running completion: oldPhase=" + oldPhase); } boolean wasCompletionRunning = isRunningPhase(oldPhase); boolean isCompletionRunning = isRunningPhase(phase); if (isCompletionRunning != wasCompletionRunning) { - ApplicationManager.getApplication().getMessageBus().syncPublisher(CompletionPhaseListener.TOPIC).completionPhaseChanged(isCompletionRunning); + ApplicationManager.getApplication().getMessageBus().syncPublisher(CompletionPhaseListener.TOPIC) + .completionPhaseChanged(isCompletionRunning); } Disposer.dispose(oldPhase); @@ -262,46 +179,24 @@ public final class CompletionServiceImpl extends CompletionService { return ourPhase; } + @NotNull @Override - public CompletionSorterImpl defaultSorter(CompletionParameters parameters, final PrefixMatcher matcher) { - final CompletionLocation location = new CompletionLocation(parameters); + protected CompletionSorterImpl addWeighersBefore(@NotNull CompletionSorterImpl sorter) { + CompletionSorterImpl processed = super.addWeighersBefore(sorter); + return processed.withClassifier(CompletionSorterImpl.weighingFactory(new LiveTemplateWeigher())); + } - CompletionSorterImpl sorter = emptySorter(); - sorter = sorter.withClassifier(CompletionSorterImpl.weighingFactory(new LiveTemplateWeigher())); - sorter = sorter.withClassifier(CompletionSorterImpl.weighingFactory(new PreferStartMatching())); - - for (final Weigher weigher : WeighingService.getWeighers(CompletionService.RELEVANCE_KEY)) { - final String id = weigher.toString(); - if ("prefix".equals(id)) { - sorter = sorter.withClassifier(CompletionSorterImpl.weighingFactory(new RealPrefixMatchingWeigher())); - } else if ("stats".equals(id)) { - sorter = sorter.withClassifier(new ClassifierFactory("stats") { - @Override - public Classifier createClassifier(Classifier next) { - return new StatisticsWeigher.LookupStatisticsWeigher(location, next); - } - }); - } else { - sorter = sorter.weigh(new LookupElementWeigher(id, true, false) { - @Override - public Comparable weigh(@NotNull LookupElement element) { - //noinspection unchecked - return weigher.weigh(element, location); - } - }); - } - } - - return sorter.withClassifier("priority", true, new ClassifierFactory("liftShorter") { + @NotNull + @Override + protected CompletionSorterImpl processStatsWeigher(@NotNull CompletionSorterImpl sorter, + @NotNull Weigher weigher, + @NotNull CompletionLocation location) { + CompletionSorterImpl processedSorter = super.processStatsWeigher(sorter, weigher, location); + return processedSorter.withClassifier(new ClassifierFactory("stats") { @Override - public Classifier createClassifier(final Classifier next) { - return new LiftShorterItemsClassifier("liftShorter", next, new LiftShorterItemsClassifier.LiftingCondition(), false); + public Classifier createClassifier(Classifier next) { + return new StatisticsWeigher.LookupStatisticsWeigher(location, next); } }); } - - @Override - public CompletionSorterImpl emptySorter() { - return new CompletionSorterImpl(new ArrayList<>()); - } } diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 19696b707684..e40f0968b819 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -35,7 +35,8 @@ serviceImplementation="com.intellij.psi.stubs.StubIndexImpl" preload="true"/> + serviceImplementation="com.intellij.codeInsight.completion.impl.CompletionServiceImpl" + overrides="true"/>