immutable matcher via MatchedLookupElement

This commit is contained in:
peter
2011-04-18 14:52:41 +02:00
parent 10646035be
commit bae263e8e8
9 changed files with 107 additions and 73 deletions
@@ -34,8 +34,9 @@ public class BasicToClassNameDelegator extends AbstractBasicToClassNameDelegator
@Override
protected void updateProperties(LookupElement lookupElement) {
if (lookupElement instanceof JavaPsiClassReferenceElement) {
((JavaPsiClassReferenceElement)lookupElement).setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
JavaPsiClassReferenceElement classElement = lookupElement.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY);
if (classElement != null) {
classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
}
lookupElement.putUserData(XmlCompletionContributor.WORD_COMPLETION_COMPATIBLE, Boolean.TRUE); //todo think of a less dirty interaction
}
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.lookup.DefaultLookupItemRenderer;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.codeInsight.lookup.impl.JavaElementLookupRenderer;
import com.intellij.openapi.util.ClassConditionKey;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -33,6 +34,7 @@ import org.jetbrains.annotations.Nullable;
* @author peter
*/
public class JavaPsiClassReferenceElement extends LookupItem<Object> {
public static final ClassConditionKey<JavaPsiClassReferenceElement> CLASS_CONDITION_KEY = ClassConditionKey.create(JavaPsiClassReferenceElement.class);
private final Object myClass;
private final String myQualifiedName;
@@ -102,30 +102,6 @@ public abstract class CompletionService {
@Nullable
public abstract CompletionProcess getCurrentCompletion();
/**
* Checks if a lookup element matches a given prefix matcher. If this element has already been matched successfully during this completion,
* returns true. If it was matched successfully during another completion, forget about this and re-match with (possibly) new prefix.
* @param element
* @param matcher
* @return should a lookup element be presented to user based on entered prefix?
*/
public boolean prefixMatches(@NotNull LookupElement element, @NotNull PrefixMatcher matcher) {
final SoftReference<CompletionProcess> data = element.getUserData(INVOLVED_IN_COMPLETION_KEY);
final CompletionProcess currentCompletion = getCurrentCompletion();
if (currentCompletion != null) {
element.putUserData(INVOLVED_IN_COMPLETION_KEY, new SoftReference<CompletionProcess>(currentCompletion));
if (data != null) {
final CompletionProcess oldCompletion = data.get();
if (oldCompletion != null && oldCompletion != currentCompletion) {
return element.setPrefixMatcher(matcher);
}
}
} else {
element.putUserData(INVOLVED_IN_COMPLETION_KEY, null);
}
return element.isPrefixMatched() || element.setPrefixMatcher(matcher);
}
/**
* The main method that is invoked to collect all the completion variants
* @param parameters Parameters specifying current completion environment
@@ -15,7 +15,6 @@
*/
package com.intellij.codeInsight.lookup;
import com.intellij.codeInsight.completion.CompletionService;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.PrefixMatcher;
@@ -35,8 +34,8 @@ public abstract class LookupElementDecorator<T extends LookupElement> extends Lo
myDelegate.copyUserDataTo(this);
final PrefixMatcher matcher = delegate.getPrefixMatcher();
if (matcher != PrefixMatcher.FALSE_MATCHER) {
final boolean prefixStillMatches = CompletionService.getCompletionService().prefixMatches(this, matcher);
assert prefixStillMatches;
assert matcher.prefixMatches(this);
setPrefixMatcher(matcher);
}
}
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
import com.intellij.codeInsight.completion.impl.MatchedLookupElement;
import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler;
import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
@@ -294,7 +295,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
Consumer<LookupElement> consumer = new Consumer<LookupElement>() {
public void consume(final LookupElement lookupElement) {
indicator.addItem(lookupElement);
indicator.addItem((MatchedLookupElement)lookupElement);
}
};
data.set(CompletionService.getCompletionService().performCompletion(parameters, consumer));
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
import com.intellij.codeInsight.completion.impl.CompletionSorterImpl;
import com.intellij.codeInsight.completion.impl.MatchedLookupElement;
import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler;
import com.intellij.codeInsight.hint.EditorHintListener;
import com.intellij.codeInsight.hint.HintManager;
@@ -190,12 +191,8 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
}
public void setItemSorter(LookupElement element, CompletionSorterImpl sorter) {
myItemSorters.putIfAbsent(element, sorter);
}
@NotNull
public CompletionSorterImpl getSorter(LookupElement element) {
CompletionSorterImpl getSorter(LookupElement element) {
return myItemSorters.get(element);
}
@@ -215,15 +212,16 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
if (isOutdated()) return; //tests?
final List<CompletionContributor> list = ApplicationManager.getApplication().runReadAction(new Computable<List<CompletionContributor>>() {
public List<CompletionContributor> compute() {
if (isOutdated()) {
return Collections.emptyList();
}
final List<CompletionContributor> list =
ApplicationManager.getApplication().runReadAction(new Computable<List<CompletionContributor>>() {
public List<CompletionContributor> compute() {
if (isOutdated()) {
return Collections.emptyList();
}
return CompletionContributor.forParameters(myParameters);
}
});
return CompletionContributor.forParameters(myParameters);
}
});
for (final CompletionContributor contributor : list) {
if (myLookup.getAdvertisementText() != null) return;
if (!myLookup.isCalculating() && !myLookup.isVisible()) return;
@@ -243,20 +241,20 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
if (s != null) {
myLookup.setAdvertisementText(s);
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (isAutopopupCompletion() && !myLookup.isShown()) {
return;
}
if (!CompletionServiceImpl.isPhase(CompletionPhase.BgCalculation.class, CompletionPhase.ItemsCalculated.class)) {
return;
}
if (CompletionServiceImpl.getCompletionPhase().indicator != CompletionProgressIndicator.this) {
return;
}
public void run() {
if (isAutopopupCompletion() && !myLookup.isShown()) {
return;
}
if (!CompletionServiceImpl.isPhase(CompletionPhase.BgCalculation.class, CompletionPhase.ItemsCalculated.class)) {
return;
}
if (CompletionServiceImpl.getCompletionPhase().indicator != CompletionProgressIndicator.this) {
return;
}
updateLookup();
}
}, myQueue.getModalityState());
updateLookup();
}
}, myQueue.getModalityState());
return;
}
}
@@ -293,7 +291,8 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
final CompletionPhase phase = CompletionServiceImpl.getCompletionPhase();
if (phase instanceof CompletionPhase.BgCalculation) {
((CompletionPhase.BgCalculation)phase).modifiersChanged = true;
} else if (phase instanceof CompletionPhase.InsertedSingleItem) {
}
else if (phase instanceof CompletionPhase.InsertedSingleItem) {
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
}
}
@@ -360,8 +359,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
return myOffsetMap.getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET);
}
public synchronized void addItem(final LookupElement item) {
public synchronized void addItem(final MatchedLookupElement item) {
if (!isRunning()) return;
ProgressManager.checkCanceled();
@@ -372,7 +370,9 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
LOG.assertTrue(myParameters.getPosition().isValid());
myLookup.addItem(item);
LookupElement delegate = item.getDelegate();
myItemSorters.put(delegate, item.getSorter());
myLookup.addItem(delegate);
myCount++;
if (unitTestMode) return;
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.completion.impl.MatchedLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.template.impl.LiveTemplateLookupElement;
import com.intellij.patterns.PatternCondition;
@@ -33,27 +34,27 @@ public class RelaxedMatchingContributor extends CompletionContributor {
@Override
public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet result) {
final Set<LookupElement> elements = new HashSet<LookupElement>();
final Set<MatchedLookupElement> elements = new HashSet<MatchedLookupElement>();
result.runRemainingContributors(parameters, new Consumer<LookupElement>() {
@Override
public void consume(LookupElement element) {
elements.add(element);
elements.add((MatchedLookupElement)element);
result.addElement(element);
}
});
if (!elements.isEmpty() && parameters.getInvocationCount() == 0) {
Set<String> prefixes = new HashSet<String>();
for (LookupElement element : elements) {
prefixes.add(element.getPrefixMatcher().getPrefix());
for (MatchedLookupElement element : elements) {
prefixes.add(element.getMatcher().getPrefix());
}
for (String prefix : prefixes) {
result.withPrefixMatcher(prefix)
.restartCompletionOnPrefixChange(StandardPatterns.string().with(new PatternCondition<String>("noneMatch") {
@Override
public boolean accepts(@NotNull String s, ProcessingContext context) {
for (LookupElement element : elements) {
if (element.getPrefixMatcher().cloneWithPrefix(s).prefixMatches(element)) {
for (MatchedLookupElement element : elements) {
if (element.getMatcher().cloneWithPrefix(s).prefixMatches(element)) {
return false;
}
}
@@ -64,7 +65,7 @@ public class RelaxedMatchingContributor extends CompletionContributor {
}
CompletionParameters relaxed;
if (parameters.getInvocationCount() == 0 && (elements.isEmpty() || elements.size() == 1 && elements.iterator().next() instanceof LiveTemplateLookupElement)) {
if (parameters.getInvocationCount() == 0 && (elements.isEmpty() || elements.size() == 1 && elements.iterator().next().as(LiveTemplateLookupElement.class) != null)) {
relaxed = parameters.withRelaxedMatching();
}
else if (parameters.getInvocationCount() >= 2) {
@@ -16,10 +16,7 @@
package com.intellij.codeInsight.completion.impl;
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.codeInsight.lookup.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -133,9 +130,21 @@ public class CompletionServiceImpl extends CompletionService{
}
public void addElement(@NotNull final LookupElement element) {
if (myCompletionService.prefixMatches(element, getPrefixMatcher())) {
myProcess.setItemSorter(element, mySorter);
if (element instanceof MatchedLookupElement) {
getConsumer().consume(element);
return;
}
MatchedLookupElement matched = element.as(MatchedLookupElement.CLASS_CONDITION_KEY);
if (matched != null) {
getConsumer().consume(new MatchedLookupElement(element, matched.getMatcher(), matched.getSorter()));
return;
}
PrefixMatcher matcher = getPrefixMatcher();
if (matcher.prefixMatches(element)) {
element.setPrefixMatcher(matcher);
getConsumer().consume(new MatchedLookupElement(element, matcher, mySorter));
}
}
@@ -0,0 +1,45 @@
/*
* 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.
*/
package com.intellij.codeInsight.completion.impl;
import com.intellij.codeInsight.completion.PrefixMatcher;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.openapi.util.ClassConditionKey;
/**
* @author peter
*/
public class MatchedLookupElement extends LookupElementDecorator<LookupElement> {
public static final ClassConditionKey<MatchedLookupElement> CLASS_CONDITION_KEY = ClassConditionKey.create(MatchedLookupElement.class);
private final PrefixMatcher myMatcher;
private final CompletionSorterImpl mySorter;
MatchedLookupElement(LookupElement delegate, PrefixMatcher matcher, CompletionSorterImpl sorter) {
super(delegate);
myMatcher = matcher;
mySorter = sorter;
}
public PrefixMatcher getMatcher() {
return myMatcher;
}
public CompletionSorterImpl getSorter() {
return mySorter;
}
}