diff --git a/platform/lang-api/src/com/intellij/codeInsight/lookup/Lookup.java b/platform/lang-api/src/com/intellij/codeInsight/lookup/Lookup.java index 540ea901560b..1c136c3265c6 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/lookup/Lookup.java +++ b/platform/lang-api/src/com/intellij/codeInsight/lookup/Lookup.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.*; @@ -61,7 +62,9 @@ public interface Lookup { boolean isFocused(); + @NotNull String itemPattern(LookupElement element); + @NotNull PrefixMatcher itemMatcher(LookupElement item); } diff --git a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElement.java b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElement.java index 4896b18a2b62..251607ec9adc 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElement.java +++ b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElement.java @@ -16,7 +16,6 @@ package com.intellij.codeInsight.lookup; import com.intellij.codeInsight.completion.InsertionContext; -import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.openapi.util.ClassConditionKey; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.psi.PsiElement; @@ -35,7 +34,6 @@ import java.util.Set; */ public abstract class LookupElement extends UserDataHolderBase { public static final LookupElement[] EMPTY_ARRAY = new LookupElement[0]; - private PrefixMatcher myPrefixMatcher = PrefixMatcher.FALSE_MATCHER; @NotNull public abstract String getLookupString(); @@ -44,16 +42,6 @@ public abstract class LookupElement extends UserDataHolderBase { return Collections.singleton(getLookupString()); } - public boolean setPrefixMatcher(@NotNull final PrefixMatcher matcher) { - myPrefixMatcher = matcher; - return myPrefixMatcher.prefixMatches(this); - } - - @NotNull - public final PrefixMatcher getPrefixMatcher() { - return myPrefixMatcher; - } - @NotNull public Object getObject() { return this; diff --git a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementDecorator.java b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementDecorator.java index dc6012405198..00505b70d5ed 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementDecorator.java +++ b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementDecorator.java @@ -17,7 +17,6 @@ package com.intellij.codeInsight.lookup; import com.intellij.codeInsight.completion.InsertHandler; import com.intellij.codeInsight.completion.InsertionContext; -import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.openapi.util.ClassConditionKey; import org.jetbrains.annotations.NotNull; @@ -32,23 +31,12 @@ public abstract class LookupElementDecorator extends Lo protected LookupElementDecorator(T delegate) { myDelegate = delegate; myDelegate.copyUserDataTo(this); - final PrefixMatcher matcher = delegate.getPrefixMatcher(); - if (matcher != PrefixMatcher.FALSE_MATCHER) { - assert matcher.prefixMatches(this); - setPrefixMatcher(matcher); - } } public T getDelegate() { return myDelegate; } - @Override - public boolean setPrefixMatcher(@NotNull PrefixMatcher matcher) { - myDelegate.setPrefixMatcher(matcher); - return super.setPrefixMatcher(matcher); - } - @NotNull public String getLookupString() { return myDelegate.getLookupString(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index fd083c3c6f09..ffbe17b86dba 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -29,11 +29,9 @@ import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.Result; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -49,7 +47,6 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; @@ -67,7 +64,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -291,12 +287,16 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { indicator.duringCompletion(initContext); ProgressManager.checkCanceled(); + final List items = new ArrayList(); Consumer consumer = new Consumer() { public void consume(final LookupElement lookupElement) { - indicator.addItem((MatchedLookupElement)lookupElement); + MatchedLookupElement matched = (MatchedLookupElement)lookupElement; + indicator.addItem(matched); + items.add(matched.getDelegate()); } }; - data.set(CompletionService.getCompletionService().performCompletion(parameters, consumer)); + CompletionService.getCompletionService().performCompletion(parameters, consumer); + data.set(items.toArray(new LookupElement[items.size()])); } }); } @@ -423,12 +423,10 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { } } else if (decision instanceof AutoCompletionDecision.InsertItem) { - final LookupElement item = ((AutoCompletionDecision.InsertItem)decision).getElement(); - indicator.closeAndFinish(true); final Runnable restorePrefix = rememberDocumentState(indicator.getEditor()); - indicator.getOffsetMap() - .addOffset(CompletionInitializationContext.START_OFFSET, (offset1 - indicator.getLookup().itemPattern(item).length())); - handleSingleItem(offset2, indicator, items, item.getLookupString(), item); + + final LookupElement item = ((AutoCompletionDecision.InsertItem)decision).getElement(); + indicator.getLookup().finishLookup(Lookup.AUTO_INSERT_SELECT_CHAR, item); // the insert handler may have started a live template with completion if (CompletionService.getCompletionService().getCurrentCompletion() == null && @@ -438,37 +436,6 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { } } - protected static void handleSingleItem(final int offset2, final CompletionProgressIndicator context, final LookupElement[] items, final String _uniqueText, final LookupElement item) { - new WriteCommandAction(context.getProject()) { - protected void run(Result result) throws Throwable { - String uniqueText = _uniqueText; - - if (item.getObject() instanceof DeferredUserLookupValue && item.as(LookupItem.CLASS_CONDITION_KEY) != null) { - if (!((DeferredUserLookupValue)item.getObject()).handleUserSelection(item.as(LookupItem.CLASS_CONDITION_KEY), context.getProject())) { - return; - } - - uniqueText = item.getLookupString(); // text may be not ready yet - } - - if (!StringUtil.startsWithIgnoreCase(uniqueText, context.getLookup().itemPattern(item))) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CAMEL_HUMPS); - } - - insertLookupString(offset2, uniqueText, context.getEditor(), context.getOffsetMap()); - context.getEditor().getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - - lookupItemSelected(context, item, Lookup.AUTO_INSERT_SELECT_CHAR, Arrays.asList(items)); - } - }.execute(); - } - - private static void insertLookupString(final int currentOffset, final String newText, final Editor editor, final OffsetMap offsetMap) { - editor.getDocument().replaceString(offsetMap.getOffset(CompletionInitializationContext.START_OFFSET), currentOffset, newText); - editor.getCaretModel().moveToOffset(offsetMap.getOffset(CompletionInitializationContext.START_OFFSET) + newText.length()); - editor.getSelectionModel().removeSelection(); - } - protected static void selectLookupItem(final LookupElement item, final char completionChar, final CompletionProgressIndicator context, final List items) { final int caretOffset = context.getEditor().getCaretModel().getOffset(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index 7adcd775e881..43573f76a2cc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -370,9 +370,8 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement LOG.assertTrue(myParameters.getPosition().isValid()); - LookupElement delegate = item.getDelegate(); - myItemSorters.put(delegate, item.getSorter()); - myLookup.addItem(delegate); + myItemSorters.put(item.getDelegate(), item.getSorter()); + myLookup.addItem(item.getDelegate(), item.getPrefixMatcher()); myCount++; if (unitTestMode) return; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/RelaxedMatchingContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/RelaxedMatchingContributor.java index 5102e157e808..46c980b95ec4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/RelaxedMatchingContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/RelaxedMatchingContributor.java @@ -46,7 +46,7 @@ public class RelaxedMatchingContributor extends CompletionContributor { if (!elements.isEmpty() && parameters.getInvocationCount() == 0) { Set prefixes = new HashSet(); for (MatchedLookupElement element : elements) { - prefixes.add(element.getMatcher().getPrefix()); + prefixes.add(element.getPrefixMatcher().getPrefix()); } for (String prefix : prefixes) { result.withPrefixMatcher(prefix) @@ -54,7 +54,7 @@ public class RelaxedMatchingContributor extends CompletionContributor { @Override public boolean accepts(@NotNull String s, ProcessingContext context) { for (MatchedLookupElement element : elements) { - if (element.getMatcher().cloneWithPrefix(s).prefixMatches(element)) { + if (element.getPrefixMatcher().cloneWithPrefix(s).prefixMatches(element)) { return false; } } 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 d61d26575bca..80a5e08b133b 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 @@ -142,13 +142,12 @@ public class CompletionServiceImpl extends CompletionService{ MatchedLookupElement matched = element.as(MatchedLookupElement.CLASS_CONDITION_KEY); if (matched != null) { - getConsumer().consume(new MatchedLookupElement(element, matched.getMatcher(), matched.getSorter())); + getConsumer().consume(new MatchedLookupElement(element, matched.getPrefixMatcher(), matched.getSorter())); return; } PrefixMatcher matcher = getPrefixMatcher(); if (matcher.prefixMatches(element)) { - element.setPrefixMatcher(matcher); getConsumer().consume(new MatchedLookupElement(element, matcher, mySorter)); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/MatchedLookupElement.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/MatchedLookupElement.java index 396e846aa4af..e707a3493548 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/MatchedLookupElement.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/MatchedLookupElement.java @@ -15,15 +15,10 @@ */ package com.intellij.codeInsight.completion.impl; -import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementDecorator; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.ClassConditionKey; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiDocumentManager; -import org.jetbrains.annotations.NotNull; /** * @author peter @@ -39,7 +34,7 @@ public class MatchedLookupElement extends LookupElementDecorator mySorter = sorter; } - public PrefixMatcher getMatcher() { + public PrefixMatcher getPrefixMatcher() { return myMatcher; } @@ -47,50 +42,4 @@ public class MatchedLookupElement extends LookupElementDecorator return mySorter; } - @Override - public void handleInsert(InsertionContext context) { - if (!isCaseSensitive()) { - if (!myMatcher.prefixMatches(this)) { - return; - } - - final String prefix = myMatcher.getPrefix(); - final String oldLookupString = getLookupString(); - if (StringUtil.startsWithIgnoreCase(oldLookupString, prefix)) { - final String newLookupString = handleCaseInsensitiveVariant(prefix, oldLookupString); - if (!newLookupString.equals(oldLookupString)) { - final Document document = context.getEditor().getDocument(); - int startOffset = context.getStartOffset(); - int tailOffset = context.getTailOffset(); - - assert startOffset >= 0 : "stale startOffset"; - assert tailOffset >= 0 : "stale tailOffset"; - - document.replaceString(startOffset, tailOffset, newLookupString); - PsiDocumentManager.getInstance(context.getProject()).commitDocument(document); - } - } - - } - super.handleInsert(context); - } - - private static String handleCaseInsensitiveVariant(final String prefix, @NotNull final String lookupString) { - final int length = prefix.length(); - if (length == 0) return lookupString; - boolean isAllLower = true; - boolean isAllUpper = true; - boolean sameCase = true; - for (int i = 0; i < length && (isAllLower || isAllUpper || sameCase); i++) { - final char c = prefix.charAt(i); - isAllLower = isAllLower && Character.isLowerCase(c); - isAllUpper = isAllUpper && Character.isUpperCase(c); - sameCase = sameCase && Character.isLowerCase(c) == Character.isLowerCase(lookupString.charAt(i)); - } - if (sameCase) return lookupString; - if (isAllLower) return lookupString.toLowerCase(); - if (isAllUpper) return lookupString.toUpperCase(); - return lookupString; - } - } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index 2a0d5195e491..01f912266f42 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.lookup.impl; import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.completion.CodeCompletionFeatures; import com.intellij.codeInsight.completion.CompletionLookupArranger; import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; @@ -40,6 +41,7 @@ import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Pair; @@ -76,6 +78,7 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.*; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; public class LookupImpl extends LightweightHint implements LookupEx, Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.lookup.impl.LookupImpl"); @@ -120,6 +123,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable private boolean myReused; private boolean myChangeGuard; private LookupModel myModel = new LookupModel(); + private final Map myMatchers = new ConcurrentHashMap(); private LookupHint myElementHint = null; private Alarm myHintAlarm = new Alarm(); private JLabel mySortingLabel; @@ -253,14 +257,15 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable final List items = myModel.getItems(); myModel.clearItems(); for (final LookupElement item : items) { - addItem(item); + addItem(item, itemMatcher(item)); } checkReused(); updateList(); ensureSelectionVisible(); } - public void addItem(LookupElement item) { + public void addItem(LookupElement item, PrefixMatcher matcher) { + myMatchers.put(item, matcher); myModel.addItem(item); updateLookupWidth(item); @@ -495,7 +500,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable private void addEmptyItem(DefaultListModel model) { LookupItem item = new EmptyLookupItem(myCalculating ? " " : LangBundle.message("completion.no.suggestions")); - item.setPrefixMatcher(new CamelHumpMatcher("")); + myMatchers.put(item, new CamelHumpMatcher("")); if (!myCalculating) { myList.setFixedCellWidth(Math.max(myCellRenderer.updateMaximumWidth(renderItemApproximately(item)), myLookupTextWidth)); } @@ -560,6 +565,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable return ContainerUtil.flatten(classifier.classify(better)); } + @NotNull @Override public String itemPattern(LookupElement element) { return itemMatcher(element).getPrefix() + myAdditionalPrefix; @@ -587,8 +593,13 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable } @Override + @NotNull public PrefixMatcher itemMatcher(LookupElement item) { - return item.getPrefixMatcher(); + PrefixMatcher matcher = myMatchers.get(item); + if (matcher == null) { + throw new AssertionError("Item not in lookup: item=" + item + "; lookup items=" + getItems()); + } + return matcher; } /** @@ -645,7 +656,10 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable } public void finishLookup(final char completionChar) { - final LookupElement item = (LookupElement)myList.getSelectedValue(); + finishLookup(completionChar, (LookupElement)myList.getSelectedValue()); + } + + public void finishLookup(char completionChar, @Nullable final LookupElement item) { doHide(false, true); if (item == null || item instanceof EmptyLookupItem || @@ -662,30 +676,63 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable return; } + final String prefix = itemPattern(item); + boolean plainMatch = ContainerUtil.or(item.getAllLookupStrings(), new Condition() { + @Override + public boolean value(String s) { + return StringUtil.startsWithIgnoreCase(s, prefix); + } + }); + if (!plainMatch) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CAMEL_HUMPS); + } + ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { - EditorModificationUtil.deleteSelectedText(myEditor); - final int caretOffset = myEditor.getCaretModel().getOffset(); - final String prefix = itemPattern(item); - int lookupStart = caretOffset - prefix.length(); - - final String lookupString = item.getLookupString(); - if (!lookupString.startsWith(prefix)) { //todo another lookup string may match the prefix - FeatureUsageTracker.getInstance().triggerFeatureUsed("editing.completion.camelHumps"); - } - - myEditor.getDocument().replaceString(lookupStart, caretOffset, lookupString); - - int offset = lookupStart + lookupString.length(); - myEditor.getCaretModel().moveToOffset(offset); - myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - myEditor.getSelectionModel().removeSelection(); + insertLookupString(item, prefix); } }); fireItemSelected(item, completionChar); } + private void insertLookupString(LookupElement item, final String prefix) { + PrefixMatcher matcher = itemMatcher(item); + + String lookupString = item.getLookupString(); + if (!item.isCaseSensitive() && matcher.prefixMatches(item) && StringUtil.startsWithIgnoreCase(lookupString, prefix)) { + lookupString = handleCaseInsensitiveVariant(prefix, lookupString); + } + + EditorModificationUtil.deleteSelectedText(myEditor); + final int caretOffset = myEditor.getCaretModel().getOffset(); + int lookupStart = caretOffset - prefix.length(); + myEditor.getDocument().replaceString(lookupStart, caretOffset, lookupString); + + int offset = lookupStart + lookupString.length(); + myEditor.getCaretModel().moveToOffset(offset); + myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + myEditor.getSelectionModel().removeSelection(); + } + + private static String handleCaseInsensitiveVariant(final String prefix, @NotNull final String lookupString) { + final int length = prefix.length(); + if (length == 0) return lookupString; + boolean isAllLower = true; + boolean isAllUpper = true; + boolean sameCase = true; + for (int i = 0; i < length && (isAllLower || isAllUpper || sameCase); i++) { + final char c = prefix.charAt(i); + isAllLower = isAllLower && Character.isLowerCase(c); + isAllUpper = isAllUpper && Character.isUpperCase(c); + sameCase = sameCase && Character.isLowerCase(c) == Character.isLowerCase(lookupString.charAt(i)); + } + if (sameCase) return lookupString; + if (isAllLower) return lookupString.toLowerCase(); + if (isAllUpper) return lookupString.toUpperCase(); + return lookupString; + } + public int getLookupStart() { LOG.assertTrue(myLookupStartMarker.isValid()); return myLookupStartMarker.getStartOffset(); @@ -900,7 +947,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable return itmBounds; } - public void fireItemSelected(final LookupElement item, char completionChar){ + public void fireItemSelected(@Nullable final LookupElement item, char completionChar){ PsiDocumentManager.getInstance(myProject).commitAllDocuments(); if (item != null) { @@ -1039,7 +1086,11 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable myEditor.getDocument().insertString(offset, afterCaret); final String newPrefix = presentPrefix + afterCaret; - myModel.retainMatchingItems(newPrefix, this); + + Map newItems = myModel.retainMatchingItems(newPrefix, this); + myMatchers.clear(); + myMatchers.putAll(newItems); + myAdditionalPrefix = ""; offset += afterCaret.length(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java index 3fe10f028dcb..a8a1219a590f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java @@ -200,12 +200,10 @@ public class LookupManagerImpl extends LookupManager { } }); + CamelHumpMatcher matcher = new CamelHumpMatcher(prefix == null ? "" : prefix); if (items.length > 0) { for (final LookupElement item : items) { - if (prefix != null) { - item.setPrefixMatcher(new CamelHumpMatcher(prefix)); - } - myActiveLookup.addItem(item); + myActiveLookup.addItem(item, matcher); } myActiveLookup.refreshUi(); } else { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupModel.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupModel.java index 403ee8be98dc..5ad129346f43 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupModel.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupModel.java @@ -15,14 +15,14 @@ */ package com.intellij.codeInsight.lookup.impl; +import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.codeInsight.lookup.*; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.SortedList; import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -111,23 +111,27 @@ public class LookupModel { } } - void retainMatchingItems(final String newPrefix, final LookupImpl lookup) { + @Nullable + Map retainMatchingItems(final String newPrefix, final LookupImpl lookup) { synchronized (lock) { - final List newItems = ContainerUtil.findAll(myItems, new Condition() { - @Override - public boolean value(LookupElement item) { - return item.isValid() && item.setPrefixMatcher(lookup.itemMatcher(item).cloneWithPrefix(newPrefix)); + LinkedHashMap map = new LinkedHashMap(); + for (LookupElement item : myItems) { + if (item.isValid()) { + PrefixMatcher matcher = lookup.itemMatcher(item).cloneWithPrefix(newPrefix); + if (matcher.prefixMatches(item)) { + map.put(item, matcher); + } } - }); - - if (newItems.size() == myItems.size()) { - return; } - clearItems(); - for (LookupElement newItem : newItems) { - addItem(newItem); + if (map.size() != myItems.size()) { + clearItems(); + for (LookupElement newItem : map.keySet()) { + addItem(newItem); + } } + + return map; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java index 80d1f915b936..5caeb7421e0d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java @@ -89,17 +89,12 @@ public class ListTemplatesHandler implements CodeInsightActionHandler { } public static void showTemplatesLookup(final Project project, final Editor editor, Map template2Argument) { - ArrayList array = new ArrayList(); + final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(project).createLookup(editor, LookupElement.EMPTY_ARRAY, null, LookupArranger.DEFAULT); for (TemplateImpl template : template2Argument.keySet()) { - String argument = template2Argument.get(template); - String prefix = computePrefix(template, argument); - LookupItem item = new LookupItem(template, prefix); - item.setPrefixMatcher(new CamelHumpMatcher(prefix)); - array.add(item); + String prefix = computePrefix(template, template2Argument.get(template)); + lookup.addItem(new LookupItem(template, prefix), new CamelHumpMatcher(prefix)); } - LookupElement[] items = array.toArray(new LookupElement[array.size()]); - final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(project).createLookup(editor, items, null, LookupArranger.DEFAULT); lookup.addLookupListener(new MyLookupAdapter(project, editor, template2Argument)); lookup.show(); }