mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
internal API for easier completion statistic collection
This commit is contained in:
+43
-25
@@ -32,10 +32,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.StandardPatterns;
|
||||
@@ -93,7 +90,7 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
myLocation = new CompletionLocation(parameters);
|
||||
}
|
||||
|
||||
private MultiMap<CompletionSorterImpl, LookupElement> groupItemsBySorter(List<LookupElement> source) {
|
||||
private MultiMap<CompletionSorterImpl, LookupElement> groupItemsBySorter(Iterable<LookupElement> source) {
|
||||
MultiMap<CompletionSorterImpl, LookupElement> inputBySorter = MultiMap.createLinked();
|
||||
for (LookupElement element : source) {
|
||||
inputBySorter.putValue(obtainSorter(element), element);
|
||||
@@ -106,28 +103,30 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
return myProcess.getSorter(element);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<LookupElement, StringBuilder> getRelevanceStrings() {
|
||||
final LinkedHashMap<LookupElement,StringBuilder> map = new LinkedHashMap<LookupElement, StringBuilder>();
|
||||
for (LookupElement item : myItems) {
|
||||
map.put(item, new StringBuilder());
|
||||
}
|
||||
final MultiMap<CompletionSorterImpl, LookupElement> inputBySorter = groupItemsBySorter(new ArrayList<LookupElement>(map.keySet()));
|
||||
|
||||
if (inputBySorter.size() > 1) {
|
||||
for (LookupElement element : map.keySet()) {
|
||||
map.get(element).append(obtainSorter(element)).append(": ");
|
||||
}
|
||||
}
|
||||
|
||||
public Map<LookupElement, List<Pair<String, Object>>> getRelevanceObjects(@NotNull Iterable<LookupElement> items,
|
||||
boolean hideSingleValued) {
|
||||
final LinkedHashMap<LookupElement, List<Pair<String, Object>>> map = ContainerUtil.newLinkedHashMap();
|
||||
final MultiMap<CompletionSorterImpl, LookupElement> inputBySorter = groupItemsBySorter(items);
|
||||
int sorterNumber = 0;
|
||||
for (CompletionSorterImpl sorter : inputBySorter.keySet()) {
|
||||
final LinkedHashMap<LookupElement, StringBuilder> subMap = new LinkedHashMap<LookupElement, StringBuilder>();
|
||||
for (LookupElement element : inputBySorter.get(sorter)) {
|
||||
subMap.put(element, map.get(element));
|
||||
sorterNumber++;
|
||||
Collection<LookupElement> thisSorterItems = inputBySorter.get(sorter);
|
||||
for (LookupElement element : thisSorterItems) {
|
||||
map.put(element, ContainerUtil.newArrayList(new Pair<String, Object>("frozen", myFrozenItems.contains(element)),
|
||||
new Pair<String, Object>("sorter", sorterNumber)));
|
||||
}
|
||||
ProcessingContext context = createContext(false);
|
||||
Classifier<LookupElement> classifier = myClassifiers.get(sorter);
|
||||
if (classifier != null) {
|
||||
classifier.describeItems(subMap, createContext(false));
|
||||
while (classifier != null) {
|
||||
List<Pair<LookupElement, Object>> pairs = classifier.getSortingWeights(thisSorterItems, context);
|
||||
if (!hideSingleValued || !haveSameWeights(pairs)) {
|
||||
for (Pair<LookupElement, Object> pair : pairs) {
|
||||
map.get(pair.first).add(Pair.create(classifier.getPresentableName(), pair.second));
|
||||
}
|
||||
}
|
||||
classifier = classifier.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +134,18 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
|
||||
}
|
||||
|
||||
private static boolean haveSameWeights(List<Pair<LookupElement, Object>> pairs) {
|
||||
if (pairs.isEmpty()) return true;
|
||||
|
||||
for (int i = 1; i < pairs.size(); i++) {
|
||||
if (!Comparing.equal(pairs.get(i).second, pairs.get(0).second)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addElement(Lookup lookup, LookupElement element, LookupElementPresentation presentation) {
|
||||
StatisticsWeigher.clearBaseStatisticsInfo(element);
|
||||
@@ -570,12 +581,19 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
private final LookupImpl myLookup;
|
||||
|
||||
private AlphaClassifier(LookupImpl lookup) {
|
||||
super(null);
|
||||
super(null, "alpha");
|
||||
myLookup = lookup;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<LookupElement> classify(Iterable<LookupElement> source, ProcessingContext context) {
|
||||
public List<Pair<LookupElement, Object>> getSortingWeights(@NotNull Iterable<LookupElement> items, @NotNull ProcessingContext context) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<LookupElement> classify(@NotNull Iterable<LookupElement> source, @NotNull ProcessingContext context) {
|
||||
return sortByPresentation(source, myLookup);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.psi.statistics.StatisticsInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class StatisticsComparable implements Comparable<StatisticsComparable> {
|
||||
private final int myScalar;
|
||||
private final StatisticsInfo myStatisticsInfo;
|
||||
|
||||
public StatisticsComparable(int scalar, @NotNull StatisticsInfo statisticsInfo) {
|
||||
myScalar = scalar;
|
||||
myStatisticsInfo = statisticsInfo;
|
||||
}
|
||||
|
||||
public int getScalar() {
|
||||
return myScalar;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StatisticsInfo getStatisticsInfo() {
|
||||
return myStatisticsInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(myScalar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(StatisticsComparable o) {
|
||||
return myScalar < o.myScalar ? -1 : myScalar == o.myScalar ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,10 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.statistics.StatisticsInfo;
|
||||
import com.intellij.psi.statistics.StatisticsManager;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -49,19 +51,19 @@ public class StatisticsWeigher extends CompletionWeigher {
|
||||
|
||||
public static class LookupStatisticsWeigher extends Classifier<LookupElement> {
|
||||
private final CompletionLocation myLocation;
|
||||
private final Map<LookupElement, Integer> myWeights = new IdentityHashMap<LookupElement, Integer>();
|
||||
@SuppressWarnings("unchecked") private final Set<LookupElement> myNoStats = new THashSet<LookupElement>(TObjectHashingStrategy.IDENTITY);
|
||||
private final Map<LookupElement, StatisticsComparable> myWeights = ContainerUtil.newIdentityHashMap();
|
||||
private final Set<LookupElement> myNoStats = ContainerUtil.newIdentityTroveSet();
|
||||
private int myPrefixChanges;
|
||||
|
||||
public LookupStatisticsWeigher(CompletionLocation location, Classifier<LookupElement> next) {
|
||||
super(next);
|
||||
super(next, "stats");
|
||||
myLocation = location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addElement(LookupElement element, ProcessingContext context) {
|
||||
public void addElement(@NotNull LookupElement element, @NotNull ProcessingContext context) {
|
||||
StatisticsInfo baseInfo = getBaseStatisticsInfo(element, myLocation);
|
||||
myWeights.put(element, weigh(element, baseInfo, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)));
|
||||
myWeights.put(element, new StatisticsComparable(weigh(element, baseInfo, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)), baseInfo));
|
||||
if (baseInfo == StatisticsInfo.EMPTY) {
|
||||
myNoStats.add(element);
|
||||
}
|
||||
@@ -76,8 +78,9 @@ public class StatisticsWeigher extends CompletionWeigher {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<LookupElement> classify(Iterable<LookupElement> source, final ProcessingContext context) {
|
||||
public Iterable<LookupElement> classify(@NotNull Iterable<LookupElement> source, @NotNull final ProcessingContext context) {
|
||||
checkPrefixChanged(context);
|
||||
|
||||
final Collection<List<LookupElement>> byWeight = buildMapByWeight(source, context).descendingMap().values();
|
||||
@@ -122,7 +125,7 @@ public class StatisticsWeigher extends CompletionWeigher {
|
||||
private TreeMap<Integer, List<LookupElement>> buildMapByWeight(Iterable<LookupElement> source, ProcessingContext context) {
|
||||
TreeMap<Integer, List<LookupElement>> map = new TreeMap<Integer, List<LookupElement>>();
|
||||
for (LookupElement element : source) {
|
||||
final int weight = getWeight(element, context.get(CompletionLookupArranger.WEIGHING_CONTEXT));
|
||||
final int weight = getWeight(element, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)).getScalar();
|
||||
List<LookupElement> list = map.get(weight);
|
||||
if (list == null) {
|
||||
map.put(weight, list = new SmartList<LookupElement>());
|
||||
@@ -132,10 +135,11 @@ public class StatisticsWeigher extends CompletionWeigher {
|
||||
return map;
|
||||
}
|
||||
|
||||
private int getWeight(LookupElement t, WeighingContext context) {
|
||||
Integer w = myWeights.get(t);
|
||||
private StatisticsComparable getWeight(LookupElement t, WeighingContext context) {
|
||||
StatisticsComparable w = myWeights.get(t);
|
||||
if (w == null) {
|
||||
myWeights.put(t, w = weigh(t, getBaseStatisticsInfo(t, myLocation), context));
|
||||
StatisticsInfo info = getBaseStatisticsInfo(t, myLocation);
|
||||
myWeights.put(t, w = new StatisticsComparable(weigh(t, info, context), info));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
@@ -151,21 +155,20 @@ public class StatisticsWeigher extends CompletionWeigher {
|
||||
return minRecency == Integer.MAX_VALUE ? useCount : 100 - minRecency;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void describeItems(LinkedHashMap<LookupElement, StringBuilder> map, ProcessingContext context) {
|
||||
public List<Pair<LookupElement, Object>> getSortingWeights(@NotNull Iterable<LookupElement> items, @NotNull final ProcessingContext context) {
|
||||
checkPrefixChanged(context);
|
||||
for (LookupElement element : map.keySet()) {
|
||||
StringBuilder builder = map.get(element);
|
||||
if (builder.length() > 0) {
|
||||
builder.append(", ");
|
||||
return ContainerUtil.map(items, new Function<LookupElement, Pair<LookupElement, Object>>() {
|
||||
@Override
|
||||
public Pair<LookupElement, Object> fun(LookupElement lookupElement) {
|
||||
return new Pair<LookupElement, Object>(lookupElement, getWeight(lookupElement, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)));
|
||||
}
|
||||
builder.append("stats=").append(getWeight(element, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)));
|
||||
}
|
||||
super.describeItems(map, context);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeElement(LookupElement element, ProcessingContext context) {
|
||||
public void removeElement(@NotNull LookupElement element, @NotNull ProcessingContext context) {
|
||||
myWeights.remove(element);
|
||||
myNoStats.remove(element);
|
||||
super.removeElement(element, context);
|
||||
|
||||
+15
-18
@@ -19,6 +19,8 @@ import com.intellij.codeInsight.completion.CompletionUtil;
|
||||
import com.intellij.codeInsight.lookup.Classifier;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.*;
|
||||
import gnu.trove.THashSet;
|
||||
@@ -39,20 +41,18 @@ public class LiftShorterItemsClassifier extends Classifier<LookupElement> {
|
||||
private final MultiMap<String, LookupElement> myElements = createMultiMap(false);
|
||||
private final MultiMap<LookupElement, LookupElement> myToLift = createMultiMap(true);
|
||||
private final MultiMap<LookupElement, LookupElement> myReversedToLift = createMultiMap(true);
|
||||
private final String myName;
|
||||
private final LiftingCondition myCondition;
|
||||
private final boolean myLiftBefore;
|
||||
private int myCount = 0;
|
||||
|
||||
public LiftShorterItemsClassifier(String name, Classifier<LookupElement> next, LiftingCondition condition, boolean liftBefore) {
|
||||
super(next);
|
||||
myName = name;
|
||||
super(next, name);
|
||||
myCondition = condition;
|
||||
myLiftBefore = liftBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addElement(LookupElement added, ProcessingContext context) {
|
||||
public void addElement(@NotNull LookupElement added, @NotNull ProcessingContext context) {
|
||||
myCount++;
|
||||
|
||||
for (String string : CompletionUtil.iterateLookupStrings(added)) {
|
||||
@@ -96,8 +96,9 @@ public class LiftShorterItemsClassifier extends Classifier<LookupElement> {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<LookupElement> classify(Iterable<LookupElement> source, ProcessingContext context) {
|
||||
public Iterable<LookupElement> classify(@NotNull Iterable<LookupElement> source, @NotNull ProcessingContext context) {
|
||||
return liftShorterElements(source, null, context);
|
||||
}
|
||||
|
||||
@@ -113,25 +114,21 @@ public class LiftShorterItemsClassifier extends Classifier<LookupElement> {
|
||||
return new LiftingIterable(srcSet, context, source, lifted);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void describeItems(LinkedHashMap<LookupElement, StringBuilder> map, ProcessingContext context) {
|
||||
public List<Pair<LookupElement, Object>> getSortingWeights(@NotNull Iterable<LookupElement> items, @NotNull ProcessingContext context) {
|
||||
final THashSet<LookupElement> lifted = newIdentityTroveSet();
|
||||
liftShorterElements(new ArrayList<LookupElement>(map.keySet()), lifted, context);
|
||||
if (!lifted.isEmpty()) {
|
||||
for (LookupElement element : map.keySet()) {
|
||||
final StringBuilder builder = map.get(element);
|
||||
if (builder.length() > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
|
||||
builder.append(myName).append("=").append(lifted.contains(element));
|
||||
liftShorterElements(ContainerUtil.newArrayList(items), lifted, context);
|
||||
return ContainerUtil.map(items, new Function<LookupElement, Pair<LookupElement, Object>>() {
|
||||
@Override
|
||||
public Pair<LookupElement, Object> fun(LookupElement element) {
|
||||
return new Pair<LookupElement, Object>(element, lifted.contains(element));
|
||||
}
|
||||
}
|
||||
super.describeItems(map, context);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeElement(LookupElement element, ProcessingContext context) {
|
||||
public void removeElement(@NotNull LookupElement element, @NotNull ProcessingContext context) {
|
||||
for (String s : CompletionUtil.iterateLookupStrings(element)) {
|
||||
myElements.remove(s, element);
|
||||
if (myElements.get(s).isEmpty()) {
|
||||
|
||||
+10
-6
@@ -17,13 +17,15 @@ package com.intellij.codeInsight.lookup;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionLookupArranger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.ForceableComparable;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -52,13 +54,14 @@ public class CachingComparingClassifier extends ComparingClassifier<LookupElemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeElement(LookupElement element, ProcessingContext context) {
|
||||
public void removeElement(@NotNull LookupElement element, @NotNull ProcessingContext context) {
|
||||
myWeights.remove(element);
|
||||
super.removeElement(element, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<LookupElement> classify(Iterable<LookupElement> source, ProcessingContext context) {
|
||||
public Iterable<LookupElement> classify(@NotNull Iterable<LookupElement> source, @NotNull ProcessingContext context) {
|
||||
if (!myWeigher.isPrefixDependent() && myPrimitive) {
|
||||
return myNext.classify(source, context);
|
||||
}
|
||||
@@ -75,14 +78,15 @@ public class CachingComparingClassifier extends ComparingClassifier<LookupElemen
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void describeItems(LinkedHashMap<LookupElement, StringBuilder> map, ProcessingContext context) {
|
||||
public List<Pair<LookupElement, Object>> getSortingWeights(@NotNull Iterable<LookupElement> items, @NotNull ProcessingContext context) {
|
||||
checkPrefixChanged(context);
|
||||
super.describeItems(map, context);
|
||||
return super.getSortingWeights(items, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addElement(LookupElement t, ProcessingContext context) {
|
||||
public void addElement(@NotNull LookupElement t, @NotNull ProcessingContext context) {
|
||||
Comparable weight = myWeigher.weigh(t, context.get(CompletionLookupArranger.WEIGHING_CONTEXT));
|
||||
if (weight instanceof ForceableComparable) {
|
||||
((ForceableComparable)weight).force();
|
||||
|
||||
@@ -15,37 +15,55 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.lookup;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class Classifier<T> {
|
||||
protected final Classifier<T> myNext;
|
||||
private final String myName;
|
||||
|
||||
protected Classifier(Classifier<T> next) {
|
||||
protected Classifier(@Nullable Classifier<T> next, String name) {
|
||||
myNext = next;
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public void addElement(T t, ProcessingContext context) {
|
||||
public void addElement(@NotNull T t, @NotNull ProcessingContext context) {
|
||||
if (myNext != null) {
|
||||
myNext.addElement(t, context);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Iterable<T> classify(Iterable<T> source, ProcessingContext context);
|
||||
@NotNull
|
||||
public abstract Iterable<T> classify(@NotNull Iterable<T> source, @NotNull ProcessingContext context);
|
||||
|
||||
public void describeItems(LinkedHashMap<T, StringBuilder> map, ProcessingContext context) {
|
||||
if (myNext != null) {
|
||||
myNext.describeItems(map, context);
|
||||
}
|
||||
/**
|
||||
* @return a mapping from the given items to objects (e.g. Comparable instances) used to sort the items in {@link #classify(Iterable, ProcessingContext)}.
|
||||
* May return an empty list if there are no suitable objects available.
|
||||
* Used for diagnostics and statistic collection.
|
||||
*/
|
||||
@NotNull
|
||||
public abstract List<Pair<T, Object>> getSortingWeights(@NotNull Iterable<T> items, @NotNull ProcessingContext context);
|
||||
|
||||
@Nullable
|
||||
public final Classifier<T> getNext() {
|
||||
return myNext;
|
||||
}
|
||||
|
||||
public void removeElement(T element, ProcessingContext context) {
|
||||
public void removeElement(@NotNull T element, @NotNull ProcessingContext context) {
|
||||
if (myNext != null) {
|
||||
myNext.removeElement(element, context);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final String getPresentableName() {
|
||||
return myName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.lookup;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FlatteningIterator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
@@ -28,24 +30,19 @@ import java.util.*;
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class ComparingClassifier<T> extends Classifier<T> {
|
||||
protected final String myName;
|
||||
private final boolean myNegated;
|
||||
|
||||
public ComparingClassifier(Classifier<T> next, String name) {
|
||||
this(next, name, false);
|
||||
}
|
||||
|
||||
protected ComparingClassifier(Classifier<T> next, String name, boolean negated) {
|
||||
super(next);
|
||||
myName = name;
|
||||
super(next, name);
|
||||
myNegated = negated;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract Comparable getWeight(T t, ProcessingContext context);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<T> classify(final Iterable<T> source, final ProcessingContext context) {
|
||||
public Iterable<T> classify(@NotNull final Iterable<T> source, @NotNull final ProcessingContext context) {
|
||||
List<T> nulls = null;
|
||||
TreeMap<Comparable, List<T>> map = new TreeMap<Comparable, List<T>>();
|
||||
for (T t : source) {
|
||||
@@ -79,21 +76,14 @@ public abstract class ComparingClassifier<T> extends Classifier<T> {
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void describeItems(LinkedHashMap<T, StringBuilder> map, ProcessingContext context) {
|
||||
Map<T, String> weights = new IdentityHashMap<T, String>();
|
||||
for (T t : map.keySet()) {
|
||||
weights.put(t, String.valueOf(getWeight(t, context)));
|
||||
}
|
||||
if (new HashSet<String>(weights.values()).size() > 1 || ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
for (T t : map.keySet()) {
|
||||
final StringBuilder builder = map.get(t);
|
||||
if (builder.length() > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(myName).append("=").append(weights.get(t));
|
||||
public List<Pair<T, Object>> getSortingWeights(@NotNull Iterable<T> items, @NotNull final ProcessingContext context) {
|
||||
return ContainerUtil.map(items, new Function<T, Pair<T, Object>>() {
|
||||
@Override
|
||||
public Pair<T, Object> fun(T t) {
|
||||
return new Pair<T, Object>(t, getWeight(t, context));
|
||||
}
|
||||
}
|
||||
super.describeItems(map, context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,15 @@ public abstract class LookupArranger {
|
||||
return myMatchingItems;
|
||||
}
|
||||
|
||||
public Map<LookupElement,StringBuilder> getRelevanceStrings() {
|
||||
/**
|
||||
* @param items the items to give relevance weight for
|
||||
* @param hideSingleValued whether criteria that gave same values for all items should be skipped
|
||||
* @return for each item, an (ordered) map of criteria used for lookup relevance sorting
|
||||
* along with the objects representing the weights in these criteria
|
||||
*/
|
||||
@NotNull
|
||||
public Map<LookupElement, List<Pair<String, Object>>> getRelevanceObjects(@NotNull Iterable<LookupElement> items,
|
||||
boolean hideSingleValued) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
@@ -67,10 +67,8 @@ import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LookupImpl extends LightweightHint implements LookupEx, Disposable, WeighingContext {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.lookup.impl.LookupImpl");
|
||||
@@ -1153,9 +1151,10 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable,
|
||||
return true;
|
||||
}
|
||||
|
||||
public Map<LookupElement,StringBuilder> getRelevanceStrings() {
|
||||
@NotNull
|
||||
public Map<LookupElement, List<Pair<String, Object>>> getRelevanceObjects(@NotNull Iterable<LookupElement> items, boolean hideSingleValued) {
|
||||
synchronized (myList) {
|
||||
return myPresentableArranger.getRelevanceStrings();
|
||||
return myPresentableArranger.getRelevanceObjects(items, hideSingleValued);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,12 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.ide.CopyPasteManager;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -59,7 +61,7 @@ public class DumpLookupElementWeights extends AnAction implements DumbAware {
|
||||
if (selected != null) {
|
||||
sb += "\nprefix: " + lookup.itemPattern(selected);
|
||||
}
|
||||
sb += "\nweights:\n" + StringUtil.join(getLookupElementWeights(lookup), "\n");
|
||||
sb += "\nweights:\n" + StringUtil.join(getLookupElementWeights(lookup, true), "\n");
|
||||
System.out.println(sb);
|
||||
LOG.info(sb);
|
||||
try {
|
||||
@@ -67,15 +69,18 @@ public class DumpLookupElementWeights extends AnAction implements DumbAware {
|
||||
} catch (Exception ignore){}
|
||||
}
|
||||
|
||||
public static List<String> getLookupElementWeights(LookupImpl lookup) {
|
||||
final Map<LookupElement,StringBuilder> strings = lookup.getRelevanceStrings();
|
||||
List<String> sb = new ArrayList<String>();
|
||||
for (LookupElement item : lookup.getItems()) {
|
||||
StringBuilder builder = strings.get(item);
|
||||
String weight = builder == null ? "null" : builder.toString();
|
||||
final String s = item.getLookupString() + "\t" + weight;
|
||||
sb.add(s);
|
||||
}
|
||||
return sb;
|
||||
public static List<String> getLookupElementWeights(LookupImpl lookup, boolean hideSingleValued) {
|
||||
final Map<LookupElement, List<Pair<String, Object>>> weights = lookup.getRelevanceObjects(lookup.getItems(), hideSingleValued);
|
||||
return ContainerUtil.map(weights.entrySet(), new Function<Map.Entry<LookupElement, List<Pair<String, Object>>>, String>() {
|
||||
@Override
|
||||
public String fun(Map.Entry<LookupElement, List<Pair<String, Object>>> entry) {
|
||||
return entry.getKey().getLookupString() + "\t" + StringUtil.join(entry.getValue(), new Function<Pair<String, Object>, String>() {
|
||||
@Override
|
||||
public String fun(Pair<String, Object> pair) {
|
||||
return pair.first + "=" + pair.second;
|
||||
}
|
||||
}, ", ");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1893,10 +1893,10 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
|
||||
Assert.assertNotNull(strings);
|
||||
final List<String> actual = strings.subList(0, Math.min(expected.length, strings.size()));
|
||||
if (!actual.equals(Arrays.asList(expected))) {
|
||||
UsefulTestCase.assertOrderedEquals(DumpLookupElementWeights.getLookupElementWeights(lookup), expected);
|
||||
UsefulTestCase.assertOrderedEquals(DumpLookupElementWeights.getLookupElementWeights(lookup, false), expected);
|
||||
}
|
||||
if (selected != list.getSelectedIndex()) {
|
||||
System.out.println(DumpLookupElementWeights.getLookupElementWeights(lookup));
|
||||
System.out.println(DumpLookupElementWeights.getLookupElementWeights(lookup, false));
|
||||
}
|
||||
Assert.assertEquals(selected, list.getSelectedIndex());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user