/*
* Copyright 2000-2013 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.codeInsight.completion.impl;
import com.intellij.codeInsight.completion.CompletionResult;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.PrefixMatcher;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.util.containers.FList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public class BetterPrefixMatcher extends PrefixMatcher {
private final PrefixMatcher myOriginal;
@Nullable private final CamelHumpMatcher myHumpMatcher;
private final int myMinMatchingDegree;
public BetterPrefixMatcher(PrefixMatcher original, int minMatchingDegree) {
super(original.getPrefix());
myOriginal = original;
myHumpMatcher = original instanceof CamelHumpMatcher ? (CamelHumpMatcher)original : null;
myMinMatchingDegree = minMatchingDegree;
}
@NotNull
public BetterPrefixMatcher improve(CompletionResult result) {
int degree = RealPrefixMatchingWeigher.getBestMatchingDegree(result.getLookupElement(), result.getPrefixMatcher());
if (degree <= myMinMatchingDegree) return this;
return createCopy(myOriginal, degree);
}
@NotNull
protected BetterPrefixMatcher createCopy(PrefixMatcher original, int degree) {
return new BetterPrefixMatcher(original, degree);
}
@Override
public boolean prefixMatches(@NotNull String name) {
return prefixMatchesEx(name) == MatchingOutcome.BETTER_MATCH;
}
protected MatchingOutcome prefixMatchesEx(String name) {
return myHumpMatcher != null ? matchOptimized(name, myHumpMatcher) : matchGeneric(name);
}
private MatchingOutcome matchGeneric(String name) {
if (!myOriginal.prefixMatches(name)) return MatchingOutcome.NON_MATCH;
if (!myOriginal.isStartMatch(name)) return MatchingOutcome.WORSE_MATCH;
return myOriginal.matchingDegree(name) >= myMinMatchingDegree ? MatchingOutcome.BETTER_MATCH : MatchingOutcome.WORSE_MATCH;
}
private MatchingOutcome matchOptimized(String name, CamelHumpMatcher matcher) {
FList<TextRange> fragments = matcher.matchingFragments(name);
if (fragments == null) return MatchingOutcome.NON_MATCH;
if (!MinusculeMatcher.isStartMatch(fragments)) return MatchingOutcome.WORSE_MATCH;
return matcher.matchingDegree(name, fragments) >= myMinMatchingDegree ? MatchingOutcome.BETTER_MATCH : MatchingOutcome.WORSE_MATCH;
}
protected enum MatchingOutcome {
NON_MATCH, WORSE_MATCH, BETTER_MATCH
}
@Override
public boolean isStartMatch(String name) {
return myOriginal.isStartMatch(name);
}
@Override
public int matchingDegree(String string) {
return myOriginal.matchingDegree(string);
}
@NotNull
@Override
public PrefixMatcher cloneWithPrefix(@NotNull String prefix) {
return createCopy(myOriginal.cloneWithPrefix(prefix), myMinMatchingDegree);
}
public static class AutoRestarting extends BetterPrefixMatcher {
private final CompletionResultSet myResult;
public AutoRestarting(@NotNull CompletionResultSet result) {
this(result, result.getPrefixMatcher(), Integer.MIN_VALUE);
}
private AutoRestarting(CompletionResultSet result, PrefixMatcher original, int minMatchingDegree) {
super(original, minMatchingDegree);
myResult = result;
}
@NotNull
@Override
protected BetterPrefixMatcher createCopy(PrefixMatcher original, int degree) {
return new AutoRestarting(myResult, original, degree);
}
@Override
protected MatchingOutcome prefixMatchesEx(String name) {
MatchingOutcome outcome = super.prefixMatchesEx(name);
if (outcome == MatchingOutcome.WORSE_MATCH) {
myResult.restartCompletionOnAnyPrefixChange();
}
return outcome;
}
}
}