introduce LookupArranger to support different sorting strategies in lookups

This commit is contained in:
Peter Gromov
2009-09-11 11:31:44 +04:00
parent 7e8dc61712
commit 5df9f57409
29 changed files with 448 additions and 425 deletions
@@ -11,12 +11,11 @@ import com.intellij.psi.*;
import com.intellij.psi.statistics.StatisticsManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public class SkipAbstractExpectedTypeWeigher extends CompletionWeigher {
public class SkipAbstractExpectedTypeWeigher extends CompletionPreselectSkipper {
enum Result {
NON_DEFAULT,
@@ -25,8 +24,9 @@ public class SkipAbstractExpectedTypeWeigher extends CompletionWeigher {
ACCEPT
}
public Comparable weigh(@NotNull final LookupElement item, final CompletionLocation location) {
return getSkippingStatus(item, location);
@Override
public boolean skipElement(LookupElement element, CompletionLocation location) {
return getSkippingStatus(element, location) != Result.ACCEPT;
}
public static Result getSkippingStatus(final LookupElement item, final CompletionLocation location) {
@@ -374,7 +374,7 @@ public class ChangeSignatureDialog extends RefactoringDialog {
LookupElement[] lookupItems = set.toArray(new LookupElement[set.size()]);
editor.getCaretModel().moveToOffset(prefix.length());
editor.getSelectionModel().removeSelection();
LookupManager.getInstance(myProject).showLookup(editor, lookupItems, prefix, null);
LookupManager.getInstance(myProject).showLookup(editor, lookupItems, prefix);
}
private JComponent createSignaturePanel() {
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2009 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;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.extensions.ExtensionPointName;
/**
* @author peter
*/
public abstract class CompletionPreselectSkipper {
public static final ExtensionPointName<CompletionPreselectSkipper> EP_NAME = ExtensionPointName.create("com.intellij.completion.skip");
public abstract boolean skipElement(LookupElement element, CompletionLocation location);
}
@@ -32,11 +32,6 @@ public abstract class CompletionService {
* A "weigher" extension key (see {@link Weigher}) to sort completion items.
*/
public static final Key<CompletionWeigher> WEIGHER_KEY = Key.create("completion");
/**
* A "weigher" extension key (see {@link Weigher}) to skip some of the top lookup items that shouldn't be selected, but should still be at the top
* (so {@link #WEIGHER_KEY} is not applicable).
*/
public static final Key<CompletionWeigher> PRESELECT_KEY = Key.create("preferredCompletionItem");
public static CompletionService getCompletionService() {
return ServiceManager.getService(CompletionService.class);
@@ -13,8 +13,8 @@ import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
@@ -28,8 +28,8 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
@@ -50,6 +50,9 @@ import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Arrays;
public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.CodeCompletionHandlerBase");
private final CompletionType myCompletionType;
@@ -277,7 +280,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
insertLookupString(context, offset2, uniqueText);
context.editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
lookupItemSelected(context, item, Lookup.AUTO_INSERT_SELECT_CHAR, items);
lookupItemSelected(context, item, Lookup.AUTO_INSERT_SELECT_CHAR, Arrays.asList(items));
}
}.execute();
}
@@ -289,7 +292,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
editor.getSelectionModel().removeSelection();
}
protected static void selectLookupItem(final LookupElement item, final char completionChar, final CompletionContext context, final LookupElement[] items) {
protected static void selectLookupItem(final LookupElement item, final char completionChar, final CompletionContext context, final List<LookupElement> items) {
final int caretOffset = context.editor.getCaretModel().getOffset();
context.setSelectionEndOffset(caretOffset);
@@ -413,10 +416,10 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
}
private static void lookupItemSelected(final CompletionContext context, @NotNull final LookupElement item, final char completionChar,
final LookupElement[] items) {
final List<LookupElement> items) {
final Editor editor = context.editor;
final PsiFile file = context.file;
final InsertionContext context1 = new InsertionContext(context.getOffsetMap(), completionChar, items, file, editor);
final InsertionContext context1 = new InsertionContext(context.getOffsetMap(), completionChar, items.toArray(new LookupElement[items.size()]), file, editor);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
final int idEndOffset = context.getOffsetMap().getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET);
@@ -0,0 +1,153 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.codeInsight.lookup.LookupArranger;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.lookup.impl.LookupItemWeightComparable;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.WeighingService;
import com.intellij.psi.statistics.StatisticsInfo;
import com.intellij.psi.statistics.StatisticsManager;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import org.jetbrains.annotations.NonNls;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CompletionLookupArranger extends LookupArranger {
public static final Key<LookupItemWeightComparable> RELEVANCE_KEY = Key.create("RELEVANCE_KEY");
@NonNls public static final String SELECTED = "selected";
@NonNls public static final String IGNORED = "ignored";
private final CompletionLocation myLocation;
public static final Key<Comparable[]> WEIGHT = Key.create("WEIGHT");
public CompletionLookupArranger(final CompletionParameters parameters) {
myLocation = new CompletionLocation(parameters);
}
@Override
public void sortItems(List<LookupElement> items) {
final PsiProximityComparator proximityComparator = new PsiProximityComparator(myLocation.getCompletionParameters().getPosition());
Collections.sort(items, new Comparator<LookupElement>() {
public int compare(LookupElement o1, LookupElement o2) {
LookupElement c1 = getCoreElement(o1);
LookupElement c2 = getCoreElement(o2);
if (c1 instanceof LookupItem && c2 instanceof LookupItem) {
double priority1 = ((LookupItem)c1).getPriority();
double priority2 = ((LookupItem)c2).getPriority();
if (priority1 > priority2) return -1;
if (priority2 > priority1) return 1;
}
int grouping1 = c1.getGrouping();
int grouping2 = c2.getGrouping();
if (grouping1 > grouping2) return -1;
if (grouping2 > grouping1) return 1;
int stringCompare = o1.getLookupString().compareToIgnoreCase(o2.getLookupString());
if (stringCompare != 0) return stringCompare;
return proximityComparator.compare(o1.getObject(), o2.getObject());
}
});
}
private static LookupElement getCoreElement(LookupElement element) {
while (element instanceof LookupElementDecorator) {
element = ((LookupElementDecorator) element).getDelegate();
}
return element;
}
public void itemSelected(LookupElement item, final Lookup lookup) {
final StatisticsManager manager = StatisticsManager.getInstance();
manager.incUseCount(CompletionService.STATISTICS_KEY, item, myLocation);
final List<LookupElement> items = lookup.getItems();
final LookupImpl lookupImpl = (LookupImpl)lookup;
final int count = Math.min(lookupImpl.getPreferredItemsCount(), lookupImpl.getList().getSelectedIndex());
for (int i = 0; i < count; i++) {
final LookupElement element = items.get(i);
StatisticsInfo info = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, element, myLocation);
if (info != null && info != StatisticsInfo.EMPTY && manager.getUseCount(info) == 0) {
manager.incUseCount(new StatisticsInfo(composeContextWithValue(info), item == element ? SELECTED : IGNORED));
}
}
}
public int suggestPreselectedItem(List<LookupElement> sorted) {
final CompletionPreselectSkipper[] skippers = CompletionPreselectSkipper.EP_NAME.getExtensions();
nextItem: for (int i = 0; i < sorted.size(); i++){
LookupElement item = sorted.get(i);
final Object obj = item.getObject();
if (obj instanceof PsiElement && !((PsiElement)obj).isValid()) continue;
for (final CompletionPreselectSkipper skipper : skippers) {
if (skipper.skipElement(item, myLocation)) {
continue nextItem;
}
}
return i;
}
return sorted.size() - 1;
}
public static String composeContextWithValue(final StatisticsInfo info) {
return info.getContext() + "###" + info.getValue();
}
public Comparable[] getWeight(final LookupElement item) {
if (item.getUserData(WEIGHT) != null) return item.getUserData(WEIGHT);
final Comparable[] result = new Comparable[]{WeighingService.weigh(CompletionService.WEIGHER_KEY, item, myLocation)};
item.putUserData(WEIGHT, result);
return result;
}
public static int doCompare(final double priority1, final double priority2, final Comparable[] weight1, final Comparable[] weight2) {
if (priority1 != priority2) {
final double v = priority1 - priority2;
if (v > 0) return -1;
if (v < 0) return 1;
}
for (int i = 0; i < weight1.length; i++) {
final Comparable w1 = weight1[i];
final Comparable w2 = weight2[i];
if (w1 != null || w2 != null) {
if (w1 == null) return 1;
if (w2 == null) return -1;
//noinspection unchecked
final int res = w1.compareTo(w2);
if (res != 0) return -res;
}
}
return 0;
}
@Override
public LookupItemWeightComparable getRelevance(LookupElement item) {
if (item.getUserData(RELEVANCE_KEY) != null) return item.getUserData(RELEVANCE_KEY);
final double priority = item instanceof LookupItem ? ((LookupItem)item).getPriority() : 0;
final LookupItemWeightComparable result = new LookupItemWeightComparable(priority, getWeight(item));
item.putUserData(RELEVANCE_KEY, result);
return result;
}
}
@@ -1,100 +0,0 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.codeInsight.lookup.LookupItemPreferencePolicy;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.openapi.util.Key;
import com.intellij.psi.WeighingComparable;
import com.intellij.psi.WeighingService;
import com.intellij.psi.statistics.StatisticsInfo;
import com.intellij.psi.statistics.StatisticsManager;
import org.jetbrains.annotations.NonNls;
import javax.swing.*;
public class CompletionPreferencePolicy implements LookupItemPreferencePolicy{
public static final Key<WeighingComparable<LookupElement, CompletionLocation>> PRESELECT_WEIGHT = Key.create("PRESELECT_WEIGHT");
@NonNls public static final String SELECTED = "selected";
@NonNls public static final String IGNORED = "ignored";
private final CompletionLocation myLocation;
public CompletionPreferencePolicy(final CompletionParameters parameters) {
myLocation = new CompletionLocation(parameters);
}
public void itemSelected(LookupElement item, final Lookup lookup) {
final StatisticsManager manager = StatisticsManager.getInstance();
manager.incUseCount(CompletionService.STATISTICS_KEY, item, myLocation);
final LookupImpl lookupImpl = (LookupImpl)lookup;
final ListModel model = lookupImpl.getList().getModel();
final int count = Math.min(lookupImpl.getPreferredItemsCount(), lookupImpl.getList().getSelectedIndex());
for (int i = 0; i < count; i++) {
final LookupElement element = (LookupElement)model.getElementAt(i);
StatisticsInfo info = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, element, myLocation);
if (info != null && info != StatisticsInfo.EMPTY && manager.getUseCount(info) == 0) {
manager.incUseCount(new StatisticsInfo(composeContextWithValue(info), item == element ? SELECTED : IGNORED));
}
}
}
public static String composeContextWithValue(final StatisticsInfo info) {
return info.getContext() + "###" + info.getValue();
}
public Comparable[] getWeight(final LookupElement item) {
if (item.getUserData(LookupItem.WEIGHT) != null) return item.getUserData(LookupItem.WEIGHT);
final Comparable[] result = new Comparable[]{WeighingService.weigh(CompletionService.WEIGHER_KEY, item, myLocation)};
item.putUserData(LookupItem.WEIGHT, result);
return result;
}
public int compare(final LookupElement item1, final LookupElement item2) {
if (item1 == item2) return 0;
if (item1 instanceof LookupItem && item2 instanceof LookupItem) {
double priority1 = ((LookupItem)item1).getPriority();
double priority2 = ((LookupItem)item2).getPriority();
if (priority1 > priority2) return -1;
if (priority1 < priority2) return 1;
}
return preselectWeigh(item2).compareTo(preselectWeigh(item1));
}
private WeighingComparable<LookupElement, CompletionLocation> preselectWeigh(final LookupElement item) {
WeighingComparable<LookupElement, CompletionLocation> data = item.getUserData(PRESELECT_WEIGHT);
if (data == null) {
item.putUserData(PRESELECT_WEIGHT, data = WeighingService.weigh(CompletionService.PRESELECT_KEY, item, myLocation));
}
return data;
}
public static int doCompare(final double priority1, final double priority2, final Comparable[] weight1, final Comparable[] weight2) {
if (priority1 != priority2) {
final double v = priority1 - priority2;
if (v > 0) return -1;
if (v < 0) return 1;
}
for (int i = 0; i < weight1.length; i++) {
final Comparable w1 = weight1[i];
final Comparable w2 = weight2[i];
if (w1 != null || w2 != null) {
if (w1 == null) return 1;
if (w2 == null) return -1;
final int res = w1.compareTo(w2);
if (res != 0) return -res;
}
}
return 0;
}
}
@@ -74,8 +74,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
myContextOriginal = contextOriginal;
myFreezeSemaphore = freezeSemaphore;
myLookup = (LookupImpl)LookupManager.getInstance(editor.getProject()).createLookup(editor, new LookupItem[0], "", new CompletionPreferencePolicy(
parameters));
myLookup = (LookupImpl)LookupManager.getInstance(editor.getProject()).createLookup(editor, LookupElement.EMPTY_ARRAY, "", new CompletionLookupArranger(parameters));
myLookup.addLookupListener(new LookupAdapter() {
public void itemSelected(LookupEvent event) {
@@ -19,7 +19,7 @@ public class NegativeStatisticsWeigher extends CompletionWeigher {
final StatisticsInfo info = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, item, location);
if (info == null || info == StatisticsInfo.EMPTY) return 0;
final StatisticsInfo ignoreInfo = new StatisticsInfo(CompletionPreferencePolicy.composeContextWithValue(info), CompletionPreferencePolicy.IGNORED);
final StatisticsInfo ignoreInfo = new StatisticsInfo(CompletionLookupArranger.composeContextWithValue(info), CompletionLookupArranger.IGNORED);
final int count = manager.getUseCount(ignoreInfo);
if (count >= StatisticsManager.OBLIVION_THRESHOLD - 1) {
return -1;
@@ -7,6 +7,7 @@ import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.*;
public interface Lookup extends UserDataHolder{
char NORMAL_SELECT_CHAR = '\n';
@@ -40,4 +41,6 @@ public interface Lookup extends UserDataHolder{
PsiFile getPsiFile();
boolean isCompletion();
java.util.List<LookupElement> getItems();
}
@@ -0,0 +1,30 @@
package com.intellij.codeInsight.lookup;
import java.util.List;
/**
* @author peter
*/
public abstract class LookupArranger {
public static final LookupArranger DEFAULT = new LookupArranger() {
@Override
public Comparable getRelevance(LookupElement element) {
return 0;
}
@Override
public void sortItems(List<LookupElement> items) {
}
};
public abstract Comparable getRelevance(LookupElement element);
public void itemSelected(LookupElement item, final Lookup lookup) {
}
public int suggestPreselectedItem(List<LookupElement> sorted) {
return 0;
}
public abstract void sortItems(List<LookupElement> items);
}
@@ -44,8 +44,6 @@ public class LookupItem<T> extends MutableLookupElement<T> implements Comparable
public static final Object INDICATE_ANONYMOUS = Key.create("INDICATE ANONYMOUS");
public static final Key<Object> DEPRECATED_ATTR = Key.create("DEPRECATED");
public static final Key<Comparable[]> WEIGHT = Key.create("WEIGHT");
public static final Object CASE_INSENSITIVE = Key.create("CASE_INSENSITIVE");
public static final Key<TailType> TAIL_TYPE_ATTR = Key.create("myTailType"); // one of constants defined in SimpleTailType interface
@@ -3,6 +3,7 @@ package com.intellij.codeInsight.lookup;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.beans.PropertyChangeListener;
@@ -20,13 +21,16 @@ public abstract class LookupManager {
return getInstance(project).getActiveLookup();
}
public abstract Lookup showLookup(Editor editor, LookupElement[] items, LookupItemPreferencePolicy itemPreferencePolicy);
@Deprecated
public abstract Lookup showLookup(Editor editor, LookupElement[] items, LookupItemPreferencePolicy itemPreferencePolicy, @Nullable String bottomText);
public abstract Lookup showLookup(Editor editor, LookupElement[] items, String prefix, LookupItemPreferencePolicy itemPreferencePolicy);
@Deprecated
public abstract Lookup showLookup(Editor editor, LookupElement[] items, String prefix, LookupItemPreferencePolicy itemPreferencePolicy,
@Nullable String bottomText);
public Lookup showLookup(Editor editor, @NotNull LookupElement... items) {
return showLookup(editor, items, "", LookupArranger.DEFAULT);
}
public Lookup showLookup(Editor editor, @NotNull LookupElement[] items, String prefix) {
return showLookup(editor, items, prefix, LookupArranger.DEFAULT);
}
public abstract Lookup showLookup(Editor editor, @NotNull LookupElement[] items, String prefix, @NotNull LookupArranger arranger);
public abstract void hideActiveLookup();
public abstract Lookup getActiveLookup();
@@ -37,9 +41,6 @@ public abstract class LookupManager {
public abstract boolean isDisposed();
public abstract Lookup createLookup(Editor editor, LookupElement[] items, final String prefix, LookupItemPreferencePolicy itemPreferencePolicy);
public abstract Lookup createLookup(Editor editor, @NotNull LookupElement[] items, final String prefix, LookupArranger arranger);
@Deprecated
public abstract Lookup createLookup(Editor editor, LookupElement[] items, final String prefix, LookupItemPreferencePolicy itemPreferencePolicy,
@Nullable String bottomText);
}
@@ -1,6 +1,6 @@
package com.intellij.codeInsight.lookup.impl;
import com.intellij.codeInsight.completion.CompletionPreferencePolicy;
import com.intellij.codeInsight.completion.CompletionLookupArranger;
import com.intellij.codeInsight.completion.PrefixMatcher;
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.codeInsight.hint.HintManagerImpl;
@@ -22,7 +22,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.ui.LightweightHint;
import com.intellij.ui.ListScrollingUtil;
import com.intellij.ui.plaf.beg.BegPopupMenuBorder;
@@ -33,6 +32,7 @@ import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.containers.SortedList;
import com.intellij.util.ui.AsyncProcessIcon;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
@@ -53,8 +53,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
private final Project myProject;
private final Editor myEditor;
private final SortedList<LookupElement> myItems;
private final SortedMap<LookupItemWeightComparable, SortedList<LookupElement>> myItemsMap;
private final Map<LookupElement, Collection<LookupElementAction>> myItemActions = new ConcurrentHashMap<LookupElement, Collection<LookupElementAction>>();
private int myMinPrefixLength;
private int myPreferredItemsCount;
@@ -62,7 +61,9 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
private RangeMarker myInitialSelection;
private long myShownStamp = -1;
private String myInitialPrefix;
@Nullable private final LookupItemPreferencePolicy myItemPreferencePolicy;
private final LookupArranger myArranger;
private final ArrayList<LookupElement> myItems;
@Nullable private List<LookupElement> mySortedItems;
private RangeMarker myLookupStartMarker;
private int myOldLookupStartOffset;
@@ -81,63 +82,28 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
private LookupElement myPreselectedItem = EMPTY_LOOKUP_ITEM;
private boolean myDirty;
private String myAdditionalPrefix = "";
private final PsiElement myElement;
private final AsyncProcessIcon myProcessIcon;
private final Comparator<LookupElement> myComparator;
private volatile boolean myCalculating;
private final JLabel myAdComponent;
private volatile String myAdText;
private volatile int myLookupWidth = 50;
private static final int LOOKUP_HEIGHT = Integer.getInteger("idea.lookup.height", 11).intValue();
public LookupImpl(Project project, Editor editor, LookupElement[] items, @Nullable LookupItemPreferencePolicy itemPreferencePolicy){
public LookupImpl(Project project, Editor editor, @NotNull LookupArranger arranger){
super(new JPanel(new BorderLayout()));
myProject = project;
myEditor = editor;
myItemPreferencePolicy = itemPreferencePolicy;
myArranger = arranger;
myItems = new ArrayList<LookupElement>();
setInitialOffset(myEditor.getCaretModel().getOffset(), myEditor.getSelectionModel().getSelectionStart(), myEditor.getSelectionModel().getSelectionEnd());
final Document document = myEditor.getDocument();
final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
myElement = psiFile == null ? null : psiFile.findElementAt(myEditor.getCaretModel().getOffset());
final PsiProximityComparator proximityComparator = new PsiProximityComparator(myElement == null ? psiFile : myElement);
myComparator = new Comparator<LookupElement>() {
public int compare(LookupElement o1, LookupElement o2) {
LookupElement c1 = getCoreElement(o1);
LookupElement c2 = getCoreElement(o2);
if (c1 instanceof LookupItem && c2 instanceof LookupItem) {
double priority1 = ((LookupItem)c1).getPriority();
double priority2 = ((LookupItem)c2).getPriority();
if (priority1 > priority2) return -1;
if (priority2 > priority1) return 1;
}
int grouping1 = c1.getGrouping();
int grouping2 = c2.getGrouping();
if (grouping1 > grouping2) return -1;
if (grouping2 > grouping1) return 1;
int stringCompare = o1.getLookupString().compareToIgnoreCase(o2.getLookupString());
if (stringCompare != 0) return stringCompare;
return proximityComparator.compare(o1.getObject(), o2.getObject());
}
};
myItems = new SortedList<LookupElement>(myComparator);
myItemsMap = new TreeMap<LookupItemWeightComparable, SortedList<LookupElement>>();
myProcessIcon = new AsyncProcessIcon("Completion progress");
myProcessIcon.setVisible(false);
myList = new JList(new DefaultListModel());
myCellRenderer = new LookupCellRenderer(this);
myList.setCellRenderer(myCellRenderer);
for (final LookupElement item : items) {
addItem(item);
}
myList.setFocusable(false);
myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -156,15 +122,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
getComponent().add(bottomPanel, BorderLayout.SOUTH);
getComponent().setBorder(new BegPopupMenuBorder());
updateList();
selectMostPreferableItem();
}
private LookupElement getCoreElement(LookupElement element) {
while (element instanceof LookupElementDecorator) {
element = ((LookupElementDecorator) element).getDelegate();
}
return element;
updateListBounds();
}
public AsyncProcessIcon getProcessIcon() {
@@ -190,11 +148,14 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
@TestOnly
public void resort() {
final ArrayList<LookupElement> items = new ArrayList<LookupElement>(myItems);
myDirty = false;
myPreselectedItem = EMPTY_LOOKUP_ITEM;
myItemsMap.clear();
myItems.clear();
final ArrayList<LookupElement> items;
synchronized (myItems) {
items = new ArrayList<LookupElement>(myItems);
myItems.clear();
mySortedItems = null;
}
for (final LookupElement item : items) {
addItem(item);
}
@@ -202,27 +163,19 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
}
public void addItem(LookupElement item) {
final double priority = item instanceof LookupItem ? ((LookupItem)item).getPriority() : 0;
final Comparable[] weight = getWeight(myItemPreferencePolicy, myElement, item);
final LookupItemWeightComparable comparable = new LookupItemWeightComparable(priority, weight);
final CollectConsumer<LookupElementAction> consumer = new CollectConsumer<LookupElementAction>();
for (LookupActionProvider provider : LookupActionProvider.EP_NAME.getExtensions()) {
provider.fillActions(item, this, consumer);
}
myItemActions.put(item, consumer.getResult());
synchronized (myItems) {
myItems.add(item);
SortedList<LookupElement> list = myItemsMap.get(comparable);
if (list == null) {
myItemsMap.put(comparable, list = new SortedList<LookupElement>(myComparator));
}
list.add(item);
}
int maxWidth = myCellRenderer.updateMaximumWidth(item);
myLookupWidth = Math.max(maxWidth, myLookupWidth);
synchronized (myItems) {
myItems.add(item);
mySortedItems = null;
}
}
public Collection<LookupElementAction> getActionsFor(LookupElement element) {
@@ -230,23 +183,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
return collection == null ? Collections.<LookupElementAction>emptyList() : collection;
}
@Nullable
public LookupItemPreferencePolicy getItemPreferencePolicy() {
return myItemPreferencePolicy;
}
private static Comparable[] getWeight(final LookupItemPreferencePolicy itemPreferencePolicy, final PsiElement context,
final LookupElement item) {
if (itemPreferencePolicy instanceof CompletionPreferencePolicy) {
return ((CompletionPreferencePolicy)itemPreferencePolicy).getWeight(item);
}
Comparable i = null;
if (item.getObject() instanceof PsiElement) {
i = PsiProximityComparator.getProximity((PsiElement)item.getObject(), context);
}
return new Comparable[]{i};
}
public int getMinPrefixLength() {
return myMinPrefixLength;
}
@@ -255,12 +191,32 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
return myList;
}
public LookupElement[] getItems(){
@NotNull
private List<LookupElement> getSortedItems() {
synchronized (myItems) {
return myItems.toArray(new LookupElement[myItems.size()]);
List<LookupElement> sortedItems = mySortedItems;
if (sortedItems == null) {
myArranger.sortItems(sortedItems = new ArrayList<LookupElement>(myItems));
mySortedItems = sortedItems;
}
return sortedItems;
}
}
public List<LookupElement> getItems() {
final ArrayList<LookupElement> result = new ArrayList<LookupElement>();
final Object[] objects;
synchronized (myList) {
objects = ((DefaultListModel)myList.getModel()).toArray();
}
for (final Object object : objects) {
if (!(object instanceof EmptyLookupItem)) {
result.add((LookupElement) object);
}
}
return result;
}
public void setAdvertisementText(@Nullable String text) {
myAdText = text;
}
@@ -282,69 +238,80 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
}
private void updateList() {
synchronized (myItems) {
int minPrefixLength = myItems.isEmpty() ? 0 : Integer.MAX_VALUE;
for (final LookupElement item : myItems) {
minPrefixLength = Math.min(item.getPrefixMatcher().getPrefix().length(), minPrefixLength);
}
if (myMinPrefixLength != minPrefixLength) {
myLookupStartMarker = null;
myOldLookupStartOffset = -1;
}
myMinPrefixLength = minPrefixLength;
final List<LookupElement> items = getSortedItems();
SortedMap<Comparable, List<LookupElement>> itemsMap = new TreeMap<Comparable, List<LookupElement>>();
int minPrefixLength = items.isEmpty() ? 0 : Integer.MAX_VALUE;
for (final LookupElement item : items) {
minPrefixLength = Math.min(item.getPrefixMatcher().getPrefix().length(), minPrefixLength);
Object oldSelected = !myDirty ? null : myList.getSelectedValue();
final Comparable relevance = myArranger.getRelevance(item);
List<LookupElement> list = itemsMap.get(relevance);
if (list == null) {
itemsMap.put(relevance, list = new ArrayList<LookupElement>());
}
list.add(item);
}
if (myMinPrefixLength != minPrefixLength) {
myLookupStartMarker = null;
myOldLookupStartOffset = -1;
}
myMinPrefixLength = minPrefixLength;
Object oldSelected = !myDirty ? null : myList.getSelectedValue();
boolean hasExactPrefixes;
final boolean hasPreselectedItem;
synchronized (myList) {
DefaultListModel model = (DefaultListModel)myList.getModel();
model.clear();
Set<LookupElement> firstItems = new THashSet<LookupElement>();
addExactPrefixItems(model, firstItems);
boolean hasExactPrefixes = !firstItems.isEmpty();
addMostRelevantItems(model, firstItems);
final boolean hasPreselectedItem = addPreselectedItem(model, firstItems);
hasExactPrefixes = addExactPrefixItems(model, firstItems, items);
addMostRelevantItems(model, firstItems, itemsMap.values());
hasPreselectedItem = addPreselectedItem(model, firstItems);
myPreferredItemsCount = firstItems.size();
addRemainingItemsLexicographically(model, firstItems);
addRemainingItemsLexicographically(model, firstItems, items);
}
boolean isEmpty = model.getSize() == 0;
if (isEmpty) {
addEmptyItem(model);
} else {
myList.setFixedCellWidth(myLookupWidth);
updateListBounds();
myAdComponent.setText(myAdText);
if (myList.getModel().getSize() > 0) {
if (oldSelected != null) {
if (hasExactPrefixes || !ListScrollingUtil.selectItem(myList, oldSelected)) {
selectMostPreferableItem();
}
}
myList.setFixedCellHeight(myCellRenderer.getListCellRendererComponent(myList, myList.getModel().getElementAt(0), 0, false, false).getPreferredSize().height);
myList.setVisibleRowCount(Math.min(myList.getModel().getSize(), LOOKUP_HEIGHT));
myAdComponent.setText(myAdText);
if (!isEmpty) {
if (oldSelected != null) {
if (hasExactPrefixes || !ListScrollingUtil.selectItem(myList, oldSelected)) {
selectMostPreferableItem();
}
else {
if (myPreselectedItem == EMPTY_LOOKUP_ITEM) {
selectMostPreferableItem();
myPreselectedItem = getCurrentItem();
}
else if (hasPreselectedItem && !hasExactPrefixes) {
ListScrollingUtil.selectItem(myList, myPreselectedItem);
}
else {
if (myPreselectedItem == EMPTY_LOOKUP_ITEM) {
selectMostPreferableItem();
myPreselectedItem = getCurrentItem();
}
else if (hasPreselectedItem && !hasExactPrefixes) {
ListScrollingUtil.selectItem(myList, myPreselectedItem);
}
else {
selectMostPreferableItem();
}
selectMostPreferableItem();
}
}
}
}
private void updateListBounds() {
final ListModel model = myList.getModel();
if (model.getSize() == 0) {
addEmptyItem((DefaultListModel)model);
} else {
myList.setFixedCellWidth(myLookupWidth);
}
myList.setFixedCellHeight(myCellRenderer.getListCellRendererComponent(myList, model.getElementAt(0), 0, false, false).getPreferredSize().height);
myList.setVisibleRowCount(Math.min(model.getSize(), LOOKUP_HEIGHT));
}
private void addEmptyItem(DefaultListModel model) {
LookupItem<String> item = new EmptyLookupItem(myCalculating ? " " : LangBundle.message("completion.no.suggestions"));
item.setPrefixMatcher(new CamelHumpMatcher(""));
@@ -356,7 +323,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
model.addElement(item);
}
private void addRemainingItemsLexicographically(DefaultListModel model, Set<LookupElement> firstItems) {
private void addRemainingItemsLexicographically(DefaultListModel model, Set<LookupElement> firstItems, List<LookupElement> myItems) {
for (LookupElement item : myItems) {
if (!firstItems.contains(item) && prefixMatches(item)) {
model.addElement(item);
@@ -373,10 +340,10 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
return hasPreselectedItem;
}
private void addMostRelevantItems(DefaultListModel model, Set<LookupElement> firstItems) {
for (final LookupItemWeightComparable comparable : myItemsMap.keySet()) {
private void addMostRelevantItems(DefaultListModel model, Set<LookupElement> firstItems, final Collection<List<LookupElement>> sortedItems) {
for (final List<LookupElement> elements : sortedItems) {
final List<LookupElement> suitable = new SmartList<LookupElement>();
for (final LookupElement item : myItemsMap.get(comparable)) {
for (final LookupElement item : elements) {
if (!firstItems.contains(item) && prefixMatches(item)) {
suitable.add(item);
}
@@ -390,15 +357,29 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
}
}
private void addExactPrefixItems(DefaultListModel model, Set<LookupElement> firstItems) {
for (final LookupItemWeightComparable comparable : myItemsMap.keySet()) {
for (final LookupElement item : myItemsMap.get(comparable)) {
if (isExactPrefixItem(item)) {
model.addElement(item);
firstItems.add(item);
}
private boolean addExactPrefixItems(DefaultListModel model, Set<LookupElement> firstItems, final List<LookupElement> elements) {
List<LookupElement> sorted = new SortedList<LookupElement>(new Comparator<LookupElement>() {
public int compare(LookupElement o1, LookupElement o2) {
//noinspection unchecked
return myArranger.getRelevance(o1).compareTo(myArranger.getRelevance(o2));
}
});
for (final LookupElement item : elements) {
if (isExactPrefixItem(item)) {
sorted.add(item);
}
}
for (final LookupElement item : sorted) {
model.addElement(item);
firstItems.add(item);
}
return !firstItems.isEmpty();
}
private boolean isExactPrefixItem(LookupElement item) {
return item.getAllLookupStrings().contains(item.getPrefixMatcher().getPrefix() + myAdditionalPrefix);
}
private boolean prefixMatches(final LookupElement item) {
@@ -424,9 +405,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
JComponent internalComponent = myEditor.getContentComponent();
final JRootPane rootPane = editorComponent.getRootPane();
if (rootPane == null) {
synchronized (myItems) {
LOG.assertTrue(false, myItems);
}
LOG.assertTrue(false, myArranger);
}
JLayeredPane layeredPane = rootPane.getLayeredPane();
Point layeredPanePoint=SwingUtilities.convertPoint(internalComponent,location, layeredPane);
@@ -621,14 +600,15 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
return Math.max(offset - myMinPrefixLength, 0);
}
private void selectMostPreferableItem(){
final int index = doSelectMostPreferableItem(((DefaultListModel)myList.getModel()).toArray());
private void selectMostPreferableItem() {
final List<LookupElement> sortedItems = getItems();
final int index = doSelectMostPreferableItem(sortedItems);
myList.setSelectedIndex(index);
if (index >= 0 && index < myList.getModel().getSize()){
ListScrollingUtil.selectItem(myList, index);
}
else if (!myItems.isEmpty()) {
else if (!sortedItems.isEmpty()) {
ListScrollingUtil.selectItem(myList, 0);
}
}
@@ -666,8 +646,8 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
public void fireItemSelected(final LookupElement item, char completionChar){
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
if (item != null && myItemPreferencePolicy != null){
myItemPreferencePolicy.itemSelected(item, this);
if (item != null) {
myArranger.itemSelected(item, this);
}
if (!myListeners.isEmpty()){
@@ -787,14 +767,16 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
final String newPrefix = presentPrefix + afterCaret;
synchronized (myItems) {
for (Iterator<LookupElement> it = myItems.iterator(); it.hasNext();) {
LookupElement item = it.next();
for (Iterator<LookupElement> iterator = myItems.iterator(); iterator.hasNext();) {
LookupElement item = iterator.next();
if (!item.setPrefixMatcher(item.getPrefixMatcher().cloneWithPrefix(newPrefix))) {
it.remove();
iterator.remove();
mySortedItems = null;
}
}
myAdditionalPrefix = "";
}
myAdditionalPrefix = "";
myAdditionalPrefix = "";
updateList();
offset += afterCaret.length();
@@ -813,7 +795,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
}
public boolean isCompletion() {
return myItemPreferencePolicy instanceof CompletionPreferencePolicy;
return myArranger instanceof CompletionLookupArranger;
}
public PsiElement getPsiElement() {
@@ -877,36 +859,25 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
}
}
private int doSelectMostPreferableItem(Object[] items) {
if (myItemPreferencePolicy == null){
private int doSelectMostPreferableItem(List<LookupElement> items) {
if (items.isEmpty()) {
return -1;
}
int prefItemIndex = -1;
if (items.size() == 1) {
return 0;
}
for(int i = 0; i < items.length; i++){
LookupElement item = (LookupElement)items[i];
final Object obj = item.getObject();
if (obj instanceof PsiElement && !((PsiElement)obj).isValid()) continue;
if (prefItemIndex == -1) {
prefItemIndex = i;
}
else {
int d = myItemPreferencePolicy.compare(item, (LookupElement)items[prefItemIndex]);
if (d < 0) {
prefItemIndex = i;
}
}
for (int i = 0; i < items.size(); i++) {
LookupElement item = items.get(i);
if (isExactPrefixItem(item)) {
break;
return i;
}
}
return prefItemIndex;
}
private boolean isExactPrefixItem(LookupElement item) {
return item.getAllLookupStrings().contains(item.getPrefixMatcher().getPrefix() + myAdditionalPrefix);
final int index = myArranger.suggestPreselectedItem(items);
assert index >= 0 && index < items.size();
return index;
}
public void refreshUi() {
@@ -925,12 +896,8 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
}
}
public LookupElement[] getSortedItems() {
synchronized (myItems) {
final LookupElement[] result = new LookupElement[myList.getModel().getSize()];
((DefaultListModel)myList.getModel()).copyInto(result);
return result;
}
@TestOnly
public LookupArranger getLookupModel() {
return myArranger;
}
}
@@ -3,7 +3,7 @@
*/
package com.intellij.codeInsight.lookup.impl;
import com.intellij.codeInsight.completion.CompletionPreferencePolicy;
import com.intellij.codeInsight.completion.CompletionLookupArranger;
import java.util.Arrays;
@@ -20,7 +20,7 @@ public class LookupItemWeightComparable implements Comparable<LookupItemWeightCo
}
public int compareTo(final LookupItemWeightComparable o) {
return CompletionPreferencePolicy.doCompare(myPriority, o.myPriority, myWeight, o.myWeight);
return CompletionLookupArranger.doCompare(myPriority, o.myPriority, myWeight, o.myWeight);
}
public String toString() {
@@ -21,7 +21,6 @@ import com.intellij.ui.LightweightHint;
import com.intellij.util.Alarm;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
@@ -96,36 +95,13 @@ public class LookupManagerImpl extends LookupManager implements ProjectComponent
myIsDisposed = true;
}
public Lookup showLookup(final Editor editor, LookupElement[] items, LookupItemPreferencePolicy itemPreferencePolicy) {
return showLookup(editor, items, "", itemPreferencePolicy);
}
public Lookup showLookup(Editor editor,
LookupElement[] items,
LookupItemPreferencePolicy itemPreferencePolicy,
@Nullable String bottomText) {
return showLookup(editor, items, itemPreferencePolicy);
}
public Lookup showLookup(final Editor editor, final LookupElement[] items, final String prefix, final LookupItemPreferencePolicy itemPreferencePolicy) {
final LookupImpl lookup = createLookup(editor, items, prefix, itemPreferencePolicy);
public Lookup showLookup(final Editor editor, @NotNull LookupElement[] items, final String prefix, @NotNull final LookupArranger arranger) {
final LookupImpl lookup = createLookup(editor, items, prefix, arranger);
lookup.show();
return lookup;
}
public Lookup showLookup(Editor editor,
LookupElement[] items,
String prefix,
LookupItemPreferencePolicy itemPreferencePolicy,
@Nullable String bottomText) {
return showLookup(editor, items, prefix, itemPreferencePolicy);
}
public LookupImpl createLookup(final Editor editor, final LookupElement[] items, final String prefix, final LookupItemPreferencePolicy itemPreferencePolicy) {
return createLookup(editor, items, prefix, itemPreferencePolicy, null);
}
public LookupImpl createLookup(final Editor editor, LookupElement[] items, String prefix, LookupItemPreferencePolicy itemPreferencePolicy, @Nullable String bottomText) {
public LookupImpl createLookup(final Editor editor, @NotNull LookupElement[] items, final String prefix, @NotNull final LookupArranger arranger) {
hideActiveLookup();
final CodeInsightSettings settings = CodeInsightSettings.getInstance();
@@ -146,10 +122,7 @@ public class LookupManagerImpl extends LookupManager implements ProjectComponent
if (daemonCodeAnalyzer != null) {
daemonCodeAnalyzer.setUpdateByTimerEnabled(false);
}
for (final LookupElement item : items) {
item.setPrefixMatcher(new CamelHumpMatcher(prefix));
}
myActiveLookup = new LookupImpl(myProject, editor, items, itemPreferencePolicy);
myActiveLookup = new LookupImpl(myProject, editor, arranger);
myActiveLookupEditor = editor;
myActiveLookup.addLookupListener(
new LookupAdapter(){
@@ -182,6 +155,15 @@ public class LookupManagerImpl extends LookupManager implements ProjectComponent
}
}
);
if (items.length > 0) {
for (final LookupElement item : items) {
item.setPrefixMatcher(new CamelHumpMatcher(prefix));
myActiveLookup.addItem(item);
}
myActiveLookup.refreshUi();
}
myPropertyChangeSupport.firePropertyChange(PROP_ACTIVE_LOOKUP, null, myActiveLookup);
return myActiveLookup;
}
@@ -1,10 +1,6 @@
package com.intellij.codeInsight.lookup.impl;
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupItemPreferencePolicy;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.MessageBus;
@@ -16,28 +12,13 @@ import com.intellij.util.messages.MessageBus;
* To change this template use Options | File Templates.
*/
public class TestLookupManager extends LookupManagerImpl{
private final Project myProject;
public TestLookupManager(Project project, MessageBus bus){
super(project, bus);
myProject = project;
}
public Lookup showLookup(final Editor editor, LookupElement[] items, LookupItemPreferencePolicy itemPreferencePolicy) {
hideActiveLookup();
for (final LookupElement item : items) {
item.setPrefixMatcher(new CamelHumpMatcher(""));
}
myActiveLookup = new LookupImpl(myProject, editor, items, itemPreferencePolicy);
myActiveLookupEditor = editor;
myActiveLookup.show();
return myActiveLookup;
}
public void forceSelection(char completion, int index){
if(myActiveLookup == null) throw new RuntimeException("There are no items in this lookup");
final LookupElement[] items = myActiveLookup.getItems();
final LookupElement lookupItem = items[index];
final LookupElement lookupItem = myActiveLookup.getItems().get(index);
myActiveLookup.setCurrentItem(lookupItem);
myActiveLookup.finishLookup(completion);
}
@@ -54,7 +35,4 @@ public class TestLookupManager extends LookupManagerImpl{
}
}
public LookupElement[] getItems(){
return myActiveLookup != null ? myActiveLookup.getItems() : null;
}
}
@@ -44,7 +44,7 @@ public class ListTemplatesHandler implements CodeInsightActionHandler{
return;
}
final LookupImpl lookup = (LookupImpl) LookupManager.getInstance(project).createLookup(editor, items, prefix, null);
final LookupImpl lookup = (LookupImpl) LookupManager.getInstance(project).createLookup(editor, items, prefix, LookupArranger.DEFAULT);
lookup.addLookupListener(
new LookupAdapter() {
public void itemSelected(LookupEvent event) {
@@ -1,7 +1,9 @@
package com.intellij.codeInsight.template.impl;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.completion.CompletionInitializationContext;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.OffsetMap;
import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.template.*;
import com.intellij.lang.LanguageLiteralEscapers;
@@ -23,8 +25,8 @@ import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -400,9 +402,6 @@ public class TemplateState implements Disposable {
EditorModificationUtil.insertStringAtCaret(myEditor, s);
itemSelected(lookupItems[0], psiFile, currentSegmentNumber, ' ', lookupItems);
} else {
if (lookupItems[0] instanceof LookupItem) {
((LookupItem)lookupItems[0]).setPriority(Integer.MAX_VALUE);
}
runLookup(currentSegmentNumber, lookupItems, psiFile);
}
}
@@ -422,9 +421,7 @@ public class TemplateState implements Disposable {
final LookupManager lookupManager = LookupManager.getInstance(myProject);
if (lookupManager.isDisposed()) return;
final CompletionParameters parameters =
new CompletionParameters(psiFile, psiFile, CompletionType.BASIC, myEditor.getCaretModel().getOffset(), 1);
final Lookup lookup = lookupManager.showLookup(myEditor, lookupItems, new CompletionPreferencePolicy(parameters));
final Lookup lookup = lookupManager.showLookup(myEditor, lookupItems);
toProcessTab = false;
lookup.addLookupListener(new LookupAdapter() {
public void lookupCanceled(LookupEvent event) {
@@ -1,9 +1,9 @@
package com.intellij.internal;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.completion.CompletionLookupArranger;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.DumbAware;
@@ -33,7 +33,7 @@ public class DumpLookupElementWeights extends AnAction implements DumbAware {
final int count = lookup.getPreferredItemsCount();
for (int i = 0; i < model.getSize(); i++) {
final LookupElement item = (LookupElement)model.getElementAt(i);
System.out.println(item.getLookupString() + Arrays.toString(item.getUserData(LookupItem.WEIGHT)));
System.out.println(item.getLookupString() + Arrays.toString(item.getUserData(CompletionLookupArranger.WEIGHT)));
if (i == count - 1) {
System.out.println("------------");
}
@@ -143,7 +143,7 @@ public class RenameDialog extends RefactoringDialog {
final LookupElement[] lookupItems = items.toArray(new LookupElement[items.size()]);
editor.getCaretModel().moveToOffset(prefix.length());
editor.getSelectionModel().removeSelection();
LookupManager.getInstance(myProject).showLookup(editor, lookupItems, prefix, null);
LookupManager.getInstance(myProject).showLookup(editor, lookupItems, prefix);
}
}
@@ -78,7 +78,7 @@ public class TextFieldWithAutoCompletion extends EditorTextField {
assert editor != null;
editor.getSelectionModel().removeSelection();
LookupManager.getInstance(getProject()).showLookup(editor, calcLookupItems(getPrefix()), getPrefix(), null);
LookupManager.getInstance(getProject()).showLookup(editor, calcLookupItems(getPrefix()), getPrefix());
}
}
@@ -245,6 +245,7 @@
<extensionPoint name="statistician" interface="com.intellij.psi.statistics.StatisticsExtensionPoint"/>
<extensionPoint name="weigher" interface="com.intellij.psi.WeigherExtensionPoint"/>
<extensionPoint name="completion.contributor" interface="com.intellij.codeInsight.completion.CompletionContributorEP"/>
<extensionPoint name="completion.skip" interface="com.intellij.codeInsight.completion.CompletionPreselectSkipper"/>
<extensionPoint name="lookup.charFilter" interface="com.intellij.codeInsight.lookup.CharFilter"/>
<extensionPoint name="lookup.actionProvider" interface="com.intellij.codeInsight.lookup.LookupActionProvider"/>
@@ -712,7 +712,8 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
return myEmptyLookup ? LookupElement.EMPTY_ARRAY : null;
}
else {
return lookup.getSortedItems();
final List<LookupElement> list = lookup.getItems();
return list.toArray(new LookupElement[list.size()]);
}
}
@@ -8,6 +8,9 @@ import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.lookup.impl.TestLookupManager;
import com.intellij.openapi.application.PluginPathManager;
import com.intellij.testFramework.LightCodeInsightTestCase;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class AntCompletionTest extends LightCodeInsightTestCase {
@@ -83,9 +86,6 @@ public class AntCompletionTest extends LightCodeInsightTestCase {
public void testInsertion1() throws Exception {
configureByFile("test8.xml");
performNormalCompletion();
if (getItems() != null) {
select();
}
checkResultByFile("/test8-out.xml");
}
@@ -93,18 +93,12 @@ public class AntCompletionTest extends LightCodeInsightTestCase {
public void testInsertion2() throws Exception {
configureByFile("test9.xml");
performNormalCompletion();
if (getItems() != null) {
select();
}
checkResultByFile("/test8-out.xml");
}
public void testTargetCompletion() throws Exception {
configureByFile("targetCompletion.xml");
performNormalCompletion();
if (getItems() != null) {
select();
}
checkResultByFile("/targetCompletion-out.xml");
}
@@ -115,18 +109,13 @@ public class AntCompletionTest extends LightCodeInsightTestCase {
AntSupport.markFileAsAntFile(myVFile, myFile.getViewProvider(), true);
performNormalCompletion();
if (getItems() != null) {
select();
}
select();
checkResultByFile("/targetCompletion2-out.xml");
}
public void testEntityCompletion() throws Exception {
configureByFile("EntityCompletion.xml");
performNormalCompletion();
if (getItems() != null) {
select();
}
checkResultByFile("EntityCompletion-out.xml");
}
@@ -174,32 +163,32 @@ public class AntCompletionTest extends LightCodeInsightTestCase {
checkResultByFile(testName + "-out.xml");
}
private void select() {
private static void select() {
select(Lookup.NORMAL_SELECT_CHAR, getSelected());
}
private void performNormalCompletion() {
private static void performNormalCompletion() {
new CodeCompletionHandlerBase(CompletionType.BASIC).invoke(getProject(), getEditor(), AntSupport.getAntFile(myFile));
}
private void select(char completionChar, LookupElement item) {
private static void select(char completionChar, LookupElement item) {
((TestLookupManager)LookupManager.getInstance(getProject())).forceSelection(completionChar, item);
}
private LookupElement getSelected() {
return LookupManager.getInstance(getProject()).getActiveLookup().getCurrentItem();
private static LookupElement getSelected() {
final Lookup lookup = LookupManager.getInstance(getProject()).getActiveLookup();
return lookup.getCurrentItem();
}
private LookupElement[] getItems() {
return ((TestLookupManager)LookupManager.getInstance(getProject())).getItems();
@NotNull
private static LookupElement[] getItems() {
final List<LookupElement> list = LookupManager.getInstance(getProject()).getActiveLookup().getItems();
return list.toArray(new LookupElement[list.size()]);
}
protected void tearDown() throws Exception {
if (getItems() != null) LookupManager.getInstance(getProject()).hideActiveLookup();
LookupManager.getInstance(getProject()).hideActiveLookup();
super.tearDown();
}
//public static void main(String[] args) {
// new TestRunner().doRun(new TestSuite(AntCompletionTest.class));
//}
}
@@ -62,12 +62,8 @@ public final class CompleteWordFromDictionaryAction extends AnAction {
lookupItems.add(LookupElementBuilder.create(variant));
}
LookupElement[] items = new LookupElement[lookupItems.size()];
items = lookupItems.toArray(items);
LookupManager lookupManager = LookupManager.getInstance(project);
lookupManager.showLookup(editor, items, prefix, null);
/*AnnotationHolder.createInfoAnnotation(TextRange.from(0, prefix.length()), "test");*/
LookupElement[] items = lookupItems.toArray(new LookupElement[lookupItems.size()]);
LookupManager.getInstance(project).showLookup(editor, items, prefix);
}
}
}
@@ -73,7 +73,7 @@ public class ChangeTo implements SpellCheckerQuickFix {
LookupElement[] items = new LookupElement[lookupItems.size()];
items = lookupItems.toArray(items);
LookupManager lookupManager = LookupManager.getInstance(project);
lookupManager.showLookup(editor, items, null);
lookupManager.showLookup(editor, items);
}
+2 -2
View File
@@ -746,8 +746,8 @@
<weigher key="completion" implementationClass="com.intellij.codeInsight.completion.PreferShorterWeigher" id="shorter"
order="after fieldsAndGetters"/>
<weigher key="preferredCompletionItem" implementationClass="com.intellij.codeInsight.completion.SkipAbstractExpectedTypeWeigher"
id="skipAbstract"/>
<completion.skip implementation="com.intellij.codeInsight.completion.SkipAbstractExpectedTypeWeigher" id="skipAbstract"/>
<extendWordSelectionHandler implementation="com.intellij.codeInsight.editorActions.wordSelection.LiteralSelectioner"/>
<extendWordSelectionHandler implementation="com.intellij.codeInsight.editorActions.wordSelection.DocCommentSelectioner"/>
@@ -116,7 +116,7 @@ public class XmlTagRenameDialog extends RefactoringDialog {
LookupElement[] lookupItems = set.toArray(new LookupElement[set.size()]);
editor.getCaretModel().moveToOffset(prefix.length());
editor.getSelectionModel().removeSelection();
LookupManager.getInstance(getProject()).showLookup(editor, lookupItems, prefix, null);
LookupManager.getInstance(getProject()).showLookup(editor, lookupItems, prefix);
}
}