diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index f08e4072b3d8..56a061a95da7 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -20,12 +20,11 @@ import com.intellij.Patches; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.CopyReferenceAction; import com.intellij.ide.ui.UISettings; -import com.intellij.ide.util.gotoByName.matchers.DefaultMatcher; -import com.intellij.ide.util.gotoByName.matchers.EntityMatcher; import com.intellij.openapi.MnemonicHelper; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.keymap.KeymapManager; @@ -33,15 +32,19 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.psi.PsiElement; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.statistics.StatisticsInfo; import com.intellij.psi.statistics.StatisticsManager; +import com.intellij.psi.util.proximity.PsiProximityComparator; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.ListScrollingUtil; import com.intellij.ui.ScrollPaneFactory; @@ -49,6 +52,9 @@ import com.intellij.ui.components.JBList; import com.intellij.ui.popup.PopupOwner; import com.intellij.ui.popup.PopupUpdateProcessor; import com.intellij.util.Alarm; +import com.intellij.util.Function; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.diff.Diff; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; @@ -62,14 +68,19 @@ import javax.swing.event.ListSelectionListener; import javax.swing.text.DefaultEditorKit; import java.awt.*; import java.awt.event.*; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.util.*; import java.util.List; public abstract class ChooseByNameBase { + private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ChooseByNameBase"); + protected final Project myProject; protected final ChooseByNameModel myModel; protected final String myInitialText; private boolean myPreselectInitialText; + private final Reference myContext; protected Component myPreviouslyFocusedComponent; @@ -104,14 +115,10 @@ public abstract class ChooseByNameBase { private static int VISIBLE_LIST_SIZE_LIMIT = 10; private static final int MAXIMUM_LIST_SIZE_LIMIT = 30; private int myMaximumListSizeLimit = MAXIMUM_LIST_SIZE_LIMIT; - @NonNls - private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib"; - @NonNls - private static final String NOT_FOUND_CARD = "nfound"; - @NonNls - private static final String CHECK_BOX_CARD = "chkbox"; - @NonNls - private static final String SEARCHING_CARD = "searching"; + @NonNls private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib"; + @NonNls private static final String NOT_FOUND_CARD = "nfound"; + @NonNls private static final String CHECK_BOX_CARD = "chkbox"; + @NonNls private static final String SEARCHING_CARD = "searching"; private static final int REBUILD_DELAY = 300; private final Alarm myHideAlarm = new Alarm(); @@ -119,26 +126,32 @@ public abstract class ChooseByNameBase { protected JBPopup myTextPopup; protected JBPopup myDropdownPopup; - private EntityMatcher myMatcher; + private static class MatchesComparator implements Comparator { + private final String myOriginalPattern; + + private MatchesComparator(final String originalPattern) { + myOriginalPattern = originalPattern.trim(); + } + + public int compare(final String a, final String b) { + boolean aStarts = a.startsWith(myOriginalPattern); + boolean bStarts = b.startsWith(myOriginalPattern); + if (aStarts && bStarts) return a.compareToIgnoreCase(b); + if (aStarts && !bStarts) return -1; + if (bStarts && !aStarts) return 1; + return a.compareToIgnoreCase(b); + } + } /** * @param initialText initial text which will be in the lookup text field * @param context */ protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, final PsiElement context) { - this(project, model, initialText); - myMatcher = new DefaultMatcher(model, context); - } - - protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, EntityMatcher matcher) { - this(project, model, initialText); - myMatcher = matcher; - } - - private ChooseByNameBase(Project project, ChooseByNameModel model, String initialText) { myProject = project; myModel = model; myInitialText = initialText; + myContext = new WeakReference(context); } public boolean isPreselectInitialText() { @@ -259,7 +272,7 @@ public abstract class ChooseByNameBase { /** * @param callback - * @param modalityState - if not null rebuilds list in given {@link com.intellij.openapi.application.ModalityState} + * @param modalityState - if not null rebuilds list in given {@link ModalityState} * @param allowMultipleSelection */ protected void initUI(final ChooseByNamePopupComponent.Callback callback, @@ -284,8 +297,7 @@ public abstract class ChooseByNameBase { GridBagLayout gb = new GridBagLayout(); JPanel eastWrapper = new JPanel(gb); - gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, - new Insets(0, 0, 0, 0), 0, 0)); + gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); eastWrapper.add(hBox); caption2Tools.add(eastWrapper, BorderLayout.CENTER); @@ -435,7 +447,8 @@ public abstract class ChooseByNameBase { myListModel = new DefaultListModel(); myList = new JBList(myListModel); myList.setFocusable(false); - myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION); + myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : + ListSelectionModel.SINGLE_SELECTION); myList.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (!myTextField.hasFocus()) { @@ -577,8 +590,8 @@ public abstract class ChooseByNameBase { final int paneHeight = layeredPane.getHeight(); final int y = paneHeight / 3 - preferredTextFieldPanelSize.height / 2; - VISIBLE_LIST_SIZE_LIMIT = - Math.max(10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1); + VISIBLE_LIST_SIZE_LIMIT = Math.max + (10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1); ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(myTextFieldPanel, myTextField); builder.setCancelCallback(new Computable() { @@ -614,11 +627,9 @@ public abstract class ChooseByNameBase { layeredPane = ((JDialog)parent).getLayeredPane(); } else { - throw new IllegalStateException("cannot find parent window: project=" + - myProject + + throw new IllegalStateException("cannot find parent window: project=" + myProject + (myProject != null ? "; open=" + myProject.isOpen() : "") + - "; window=" + - window); + "; window=" + window); } return layeredPane; } @@ -639,7 +650,8 @@ public abstract class ChooseByNameBase { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { final String text = myTextField.getText(); - if (!canShowListForEmptyPattern() && (text == null || text.trim().length() == 0)) { + if (!canShowListForEmptyPattern() && + (text == null || text.trim().length() == 0)) { myListModel.clear(); hideList(); myCard.show(myCardContainer, CHECK_BOX_CARD); @@ -779,12 +791,17 @@ public abstract class ChooseByNameBase { return "choose_by_name#" + myModel.getPromptText() + "#" + myCheckBox.isSelected() + "#" + myTextField.getText(); } - public String getNamePattern(String pattern) { - return getNamePattern_static(myModel, pattern); + private String getQualifierPattern(String pattern) { + final String[] separators = myModel.getSeparators(); + int lastSeparatorOccurence = 0; + for (String separator : separators) { + lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator)); + } + return pattern.substring(0, lastSeparatorOccurence); } - public static String getNamePattern_static(ChooseByNameModel model, String pattern) { - final String[] separators = model.getSeparators(); + public String getNamePattern(String pattern) { + final String[] separators = myModel.getSeparators(); int lastSeparatorOccurence = 0; for (String separator : separators) { final int idx = pattern.lastIndexOf(separator); @@ -970,7 +987,7 @@ public abstract class ChooseByNameBase { protected void processKeyEvent(KeyEvent e) { final KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e); - + if (myCompletionKeyStroke != null && keyStroke.equals(myCompletionKeyStroke)) { completionKeyStrokeHappened = true; e.consume(); @@ -1021,7 +1038,8 @@ public abstract class ChooseByNameBase { } private void fillInCommonPrefix(final String pattern) { - final List list = getNamesByPattern(pattern, getNames()); + final ArrayList list = new ArrayList(); + getNamesByPattern(myCheckBox.isSelected(), null, list, pattern); if (isComplexPattern(pattern)) return; //TODO: support '*' final String oldText = myTextField.getText(); @@ -1087,34 +1105,6 @@ public abstract class ChooseByNameBase { } } - public List getNamesByPattern(String pattern, String[] names) { - if (pattern.startsWith("@")) { - pattern = pattern.substring(1); - } - - boolean empty = pattern.length() == 0; - if (empty) { - if (!canShowListForEmptyPattern()) return Collections.emptyList(); - return Arrays.asList(names); - } - - ArrayList result = new ArrayList(); - try { - for (String name : names) { - if (myCalcElementsThread.myCancelled) { - break; - } - if (myMatcher.nameMatches(pattern, name)) { - result.add(name); - } - } - } - catch (Exception e) { - // Do nothing. No matches appears valid result for "bad" pattern - } - return result; - } - private static final String EXTRA_ELEM = "..."; private class CalcElementsThread implements Runnable { @@ -1203,31 +1193,55 @@ public abstract class ChooseByNameBase { } private void addElementsByPattern(Set elementsArray, String pattern) { - String[] names = myCheckboxState ? myNames[1] : myNames[0]; String namePattern = getNamePattern(pattern); + String qualifierPattern = getQualifierPattern(pattern); - List namesList = getNamesByPattern(namePattern, names); + boolean empty = namePattern.length() == 0 || namePattern.equals("@"); // TODO[yole]: remove implicit dependency + if (empty && !canShowListForEmptyPattern()) return; + List namesList = new ArrayList(); + getNamesByPattern(myCheckboxState, this, namesList, namePattern); + if (myCancelled) { + throw new ProcessCanceledException(); + } // Here we sort using namePattern to have similar logic with empty qualified patten case Collections.sort(namesList, new MatchesComparator(namePattern)); + boolean overflow = false; + List sameNameElements = new SmartList(); + All: for (String name : namesList) { - Set elems = myMatcher.getElementsByPattern(namePattern, name, myCheckboxState,new Computable() { - public Boolean compute() { - return myCancelled; - } - }); - if (elementsArray.size() + elems.size() <= myMaximumListSizeLimit) { - elementsArray.addAll(elems); + if (myCancelled) { + throw new ProcessCanceledException(); } - else { - Iterator iter = elems.iterator(); - while (elementsArray.size() < myMaximumListSizeLimit) { - elementsArray.add(iter.next()); + final Object[] elements = myModel.getElementsByName(name, myCheckboxState, namePattern); + if (elements.length > 1) { + sameNameElements.clear(); + for (final Object element : elements) { + if (matchesQualifier(element, qualifierPattern)) { + sameNameElements.add(element); + } + } + sortByProximity(sameNameElements); + for (Object element : sameNameElements) { + elementsArray.add(element); + if (elementsArray.size() >= myMaximumListSizeLimit) { + overflow = true; + break All; + } } - elementsArray.add(EXTRA_ELEM); - break; } + else if (elements.length == 1 && matchesQualifier(elements[0], qualifierPattern)) { + elementsArray.add(elements[0]); + if (elementsArray.size() >= myMaximumListSizeLimit) { + overflow = true; + break; + } + } + } + + if (overflow) { + elementsArray.add(EXTRA_ELEM); } } @@ -1238,8 +1252,92 @@ public abstract class ChooseByNameBase { } } - private String[] getNames() { - return myCheckBox.isSelected() ? myNames[1] : myNames[0]; + private void sortByProximity(final List sameNameElements) { + Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get())); + } + + private List split(String s) { + List answer = new ArrayList(); + for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) { + if (token.length() > 0) { + answer.add(token); + } + } + + return answer.isEmpty() ? Collections.singletonList(s) : answer; + } + + private boolean matchesQualifier(final Object element, final String qualifierPattern) { + final String name = myModel.getFullName(element); + if (name == null) return false; + + final List suspects = split(name); + final List> patternsAndMatchers = + ContainerUtil.map2List(split(qualifierPattern), new Function>() { + public Pair fun(String s) { + final String pattern = getNamePattern(s); + final NameUtil.Matcher matcher = buildPatternMatcher(pattern); + + return new Pair(pattern, matcher); + } + }); + + int matchPosition = 0; + + try { + patterns: + for (Pair patternAndMatcher : patternsAndMatchers) { + final String pattern = patternAndMatcher.first; + final NameUtil.Matcher matcher = patternAndMatcher.second; + if (pattern.length() > 0) { + for (int j = matchPosition; j < suspects.size() - 1; j++) { + String suspect = suspects.get(j); + if (matches(pattern, matcher, suspect)) { + matchPosition = j + 1; + continue patterns; + } + } + + return false; + } + } + } + catch (Exception e) { + // Do nothing. No matches appears valid result for "bad" pattern + return false; + } + + return true; + } + + private void getNamesByPattern(final boolean checkboxState, + CalcElementsThread calcElementsThread, + final List list, + String pattern) throws ProcessCanceledException { + if (!canShowListForEmptyPattern()) { + LOG.assertTrue(pattern.length() > 0); + } + + if (pattern.startsWith("@")) { + pattern = pattern.substring(1); + } + + final String[] names = checkboxState ? myNames[1] : myNames[0]; + final NameUtil.Matcher matcher = buildPatternMatcher(pattern); + + try { + for (String name : names) { + if (calcElementsThread != null && calcElementsThread.myCancelled) { + break; + } + if (matches(pattern, matcher, name)) { + list.add(name); + } + } + } + catch (Exception e) { + // Do nothing. No matches appears valid result for "bad" pattern + } } private boolean canShowListForEmptyPattern() { @@ -1247,27 +1345,46 @@ public abstract class ChooseByNameBase { } protected boolean lastKeyStrokeIsCompletion() { - return myTextField.isCompletionKeyStroke(); + return myTextField.isCompletionKeyStroke(); + } + + private boolean matches(String pattern, NameUtil.Matcher matcher, String name) { + boolean matches = false; + if (name != null) { + if (myModel instanceof CustomMatcherModel) { + if (((CustomMatcherModel)myModel).matches(name, pattern)) { + matches = true; + } + } + else if (pattern.length() == 0 || matcher.matches(name)) { + matches = true; + } + } + return matches; + } + + private NameUtil.Matcher buildPatternMatcher(String pattern) { + return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern)); } private interface CalcElementsCallback { void run(Set elements); } - private static class MatchesComparator implements Comparator { - private final String myOriginalPattern; + private static class PathProximityComparator implements Comparator { + private final ChooseByNameModel myModel; + private final PsiProximityComparator myProximityComparator; - private MatchesComparator(final String originalPattern) { - myOriginalPattern = originalPattern.trim(); + private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) { + myModel = model; + myProximityComparator = new PsiProximityComparator(context); } - public int compare(final String a, final String b) { - boolean aStarts = a.startsWith(myOriginalPattern); - boolean bStarts = b.startsWith(myOriginalPattern); - if (aStarts && bStarts) return a.compareToIgnoreCase(b); - if (aStarts && !bStarts) return -1; - if (bStarts && !aStarts) return 1; - return a.compareToIgnoreCase(b); + public int compare(final Object o1, final Object o2) { + int rc = myProximityComparator.compare(o1, o2); + if (rc != 0) return rc; + + return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2)); } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java index 97b892324624..a262d28b8be1 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java @@ -17,7 +17,6 @@ package com.intellij.ide.util.gotoByName; import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.ide.util.gotoByName.matchers.EntityMatcher; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.ComponentPopupBuilder; @@ -43,7 +42,7 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent { +public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent{ private static final Key CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY = new Key("ChooseByNamePopup"); private Component myOldFocusOwner = null; private boolean myShowListForEmptyPattern = false; @@ -59,17 +58,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP } } - private ChooseByNamePopup(final Project project, final ChooseByNameModel model, final ChooseByNamePopup oldPopup, - EntityMatcher matcher,@Nullable final String predefinedText) { - super(project, model, oldPopup != null ? oldPopup.getEnteredText() : predefinedText, matcher); - if (oldPopup == null && predefinedText != null) { - setPreselectInitialText(true); - } - if (oldPopup != null) { //inherit old focus owner - myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent; - } - } - public String getEnteredText() { return myTextField.getText(); } @@ -215,22 +203,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context) { return createPopup(project, model, context, null); } - public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher) { - return createPopup(project, model, matcher, null); - } - - public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher, - @Nullable final String predefinedText) { - final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY); - if (oldPopup != null) { - oldPopup.close(false); - } - ChooseByNamePopup newPopup = new ChooseByNamePopup(project, model, oldPopup, matcher, predefinedText); - - project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup); - return newPopup; - } - public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context, @Nullable final String predefinedText) { final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY); diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/matchers/DefaultMatcher.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/matchers/DefaultMatcher.java deleted file mode 100644 index 3ba89706b309..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/matchers/DefaultMatcher.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2000-2010 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.ide.util.gotoByName.matchers; - -import com.intellij.ide.util.gotoByName.ChooseByNameBase; -import com.intellij.ide.util.gotoByName.ChooseByNameModel; -import com.intellij.ide.util.gotoByName.CustomMatcherModel; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiElement; -import com.intellij.psi.codeStyle.NameUtil; -import com.intellij.psi.util.proximity.PsiProximityComparator; -import com.intellij.util.Function; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; - -import java.lang.ref.WeakReference; -import java.util.*; - -public class DefaultMatcher implements EntityMatcher { - private ChooseByNameModel myModel; - private WeakReference myContext; - - private String myPattern = null; - private NameUtil.Matcher myMatcher = null; - - public DefaultMatcher(ChooseByNameModel model, PsiElement context) { - myModel = model; - myContext = new WeakReference(context); - } - - public boolean nameMatches(String shortPattern, String shortName) { - if (myPattern == null || !myPattern.equals(shortPattern)) { - myMatcher = buildPatternMatcher(shortPattern); - } - - return matches(shortPattern, myMatcher, shortName); - } - - public Set getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable isCancelled) { - String namePattern = getShortNamePattern(fullPattern); - String qualifierPattern = getQualifierPattern(fullPattern); - - //todo this is a code duplicate - remove it - String newPattern = namePattern.startsWith("@") ? namePattern.substring(1) : namePattern; - if (!nameMatches(newPattern, shortName)) return Collections.emptySet(); - - List sameNameElements = new SmartList(); - final Object[] elements = myModel.getElementsByName(shortName, checkboxState, namePattern); - - Set result = new HashSet(); - if (elements.length == 1) { - if (matchesQualifier(elements[0], qualifierPattern)) { - result.add(elements[0]); - } - return result; - } - - sameNameElements.clear(); - for (final Object element : elements) { - if (isCancelled.compute()) return result; - if (matchesQualifier(element, qualifierPattern)) { - sameNameElements.add(element); - } - } - sortByProximity(sameNameElements); - result.addAll(sameNameElements); - return result; - } - - private void sortByProximity(final List sameNameElements) { - Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get())); - } - - private boolean matchesQualifier(final Object element, final String qualifierPattern) { - final String name = myModel.getFullName(element); - if (name == null) return false; - - final List suspects = split(name); - final List> patternsAndMatchers = - ContainerUtil.map2List(split(qualifierPattern), new Function>() { - public Pair fun(String s) { - final String pattern = getShortNamePattern(s); - final NameUtil.Matcher matcher = buildPatternMatcher(pattern); - - return new Pair(pattern, matcher); - } - }); - - int matchPosition = 0; - - try { - patterns: - for (Pair patternAndMatcher : patternsAndMatchers) { - final String pattern = patternAndMatcher.first; - final NameUtil.Matcher matcher = patternAndMatcher.second; - if (pattern.length() > 0) { - for (int j = matchPosition; j < suspects.size() - 1; j++) { - String suspect = suspects.get(j); - if (matches(pattern, matcher, suspect)) { - matchPosition = j + 1; - continue patterns; - } - } - - return false; - } - } - } - catch (Exception e) { - // Do nothing. No matches appears valid result for "bad" pattern - return false; - } - - return true; - } - - public String getShortNamePattern(String s) { - return ChooseByNameBase.getNamePattern_static(myModel, s); - } - - private String getQualifierPattern(String pattern) { - final String[] separators = myModel.getSeparators(); - int lastSeparatorOccurence = 0; - for (String separator : separators) { - lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator)); - } - return pattern.substring(0, lastSeparatorOccurence); - } - - private boolean matches(String pattern, NameUtil.Matcher matcher, String name) { - boolean matches = false; - if (name != null) { - if (myModel instanceof CustomMatcherModel) { - if (((CustomMatcherModel)myModel).matches(name, pattern)) { - matches = true; - } - } - else if (pattern.length() == 0 || matcher.matches(name)) { - matches = true; - } - } - return matches; - } - - private static NameUtil.Matcher buildPatternMatcher(String pattern) { - return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern)); - } - - private List split(String s) { - List answer = new ArrayList(); - for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) { - if (token.length() > 0) { - answer.add(token); - } - } - - return answer.isEmpty() ? Collections.singletonList(s) : answer; - } - - private static class PathProximityComparator implements Comparator { - private final ChooseByNameModel myModel; - private final PsiProximityComparator myProximityComparator; - - private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) { - myModel = model; - myProximityComparator = new PsiProximityComparator(context); - } - - public int compare(final Object o1, final Object o2) { - int rc = myProximityComparator.compare(o1, o2); - if (rc != 0) return rc; - - return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2)); - } - } - -} diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/matchers/EntityMatcher.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/matchers/EntityMatcher.java deleted file mode 100644 index 7a6dbffc809b..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/matchers/EntityMatcher.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2000-2010 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.ide.util.gotoByName.matchers; - -import com.intellij.openapi.util.Computable; - -import java.util.Set; - -public interface EntityMatcher { - boolean nameMatches(String shortPattern, String shortName); - - Set getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable isCancelled); -}