diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index ff39c5131780..e2a985ce89ae 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -85,7 +85,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.ComponentPopupBuilder; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Iconable; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -1962,10 +1965,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private GotoActionItemProvider createActionProvider() { GotoActionModel model = new GotoActionModel(project, myFocusComponent, myEditor, myFile) { @Override - protected MatchMode actionMatches(@NotNull String pattern, @NotNull AnAction anAction) { - String text = anAction.getTemplatePresentation().getText(); - return text != null && NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE) - .matches(text) ? MatchMode.NAME : MatchMode.NONE; + protected MatchMode actionMatches(@NotNull String pattern, MinusculeMatcher matcher, @NotNull AnAction anAction) { + MatchMode mode = super.actionMatches(pattern, matcher, anAction); + return mode == MatchMode.NAME ? mode : MatchMode.NONE; } }; return new GotoActionItemProvider(model); diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java index 70bc7d22248b..725e8b0b21b3 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java @@ -28,11 +28,14 @@ import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.util.CollectConsumer; -import com.intellij.util.Function; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.JBIterable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -65,7 +68,7 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { boolean everywhere, @NotNull ProgressIndicator cancelled, @NotNull final Processor consumer) { - return filterElements(pattern, everywhere, value -> consumer.process(value)); + return filterElements(pattern, everywhere, consumer::process); } public boolean filterElements(String pattern, boolean everywhere, Processor consumer) { @@ -81,20 +84,20 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { } private boolean processAbbreviations(final String pattern, Processor consumer, DataContext context) { - List actions = AbbreviationManager.getInstance().findActions(pattern); - if (actions.isEmpty()) return true; - List wrappers = ContainerUtil.newArrayListWithCapacity(actions.size()); - for (String actionId : actions) { - AnAction action = myActionManager.getAction(actionId); - wrappers.add(new ActionWrapper(action, myModel.myActionGroups.get(action), MatchMode.NAME, context)); - } - return ContainerUtil.process(ContainerUtil.map(wrappers, (Function)w -> new MatchedValue(w, pattern) { - @Nullable - @Override - public String getValueText() { - return pattern; - } - }), consumer); + List actionIds = AbbreviationManager.getInstance().findActions(pattern); + JBIterable wrappers = JBIterable.from(actionIds) + .transform(actionId -> { + AnAction action = myActionManager.getAction(actionId); + ActionWrapper wrapper = new ActionWrapper(action, myModel.myActionGroups.get(action), MatchMode.NAME, context); + return new MatchedValue(wrapper, pattern) { + @Nullable + @Override + public String getValueText() { + return pattern; + } + }; + }); + return processItems(pattern, wrappers, consumer); } private static boolean processTopHits(String pattern, Processor consumer, DataContext dataContext) { @@ -109,14 +112,8 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { } provider.consumeTopHits(pattern, collector, project); } - final Collection result = collector.getResult(); - final List c = new ArrayList(); - for (Object o : result) { - if (o instanceof Comparable) { - c.add((Comparable)o); - } - } - return processItems(pattern, c, consumer); + Collection result = collector.getResult(); + return processItems(pattern, JBIterable.from(result).filter(Comparable.class), consumer); } private boolean processOptions(String pattern, Processor consumer, DataContext dataContext) { @@ -163,49 +160,45 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { } } } - return processItems(pattern, options, consumer); + return processItems(pattern, JBIterable.from(options), consumer); } private boolean processActions(String pattern, boolean everywhere, Processor consumer, DataContext dataContext) { - List actions = ContainerUtil.newArrayList(); + JBIterable actions; if (everywhere) { - for (String id : ((ActionManagerImpl)myActionManager).getActionIds()) { - ProgressManager.checkCanceled(); - ContainerUtil.addIfNotNull(actions, myActionManager.getAction(id)); - } - } else { - actions.addAll(myModel.myActionGroups.keySet()); + Set ids = ((ActionManagerImpl)myActionManager).getActionIds(); + actions = JBIterable.from(ids).transform(myActionManager::getAction).filter(Condition.NOT_NULL); } - - List actionWrappers = ContainerUtil.newArrayList(); - for (AnAction action : actions) { - ProgressManager.checkCanceled(); - MatchMode mode = myModel.actionMatches(pattern, action); - if (mode != MatchMode.NONE) { - actionWrappers.add(new ActionWrapper(action, myModel.myActionGroups.get(action), mode, dataContext)); - } + else { + actions = JBIterable.from(myModel.myActionGroups.keySet()); } + MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); + JBIterable actionWrappers = actions.transform(action -> { + MatchMode mode = myModel.actionMatches(pattern, matcher, action); + if (mode == MatchMode.NONE) return null; + return new ActionWrapper(action, myModel.myActionGroups.get(action), mode, dataContext); + }).filter(Condition.NOT_NULL); return processItems(pattern, actionWrappers, consumer); } private boolean processIntentions(String pattern, Processor consumer, DataContext dataContext) { - List intentions = ContainerUtil.newArrayList(); - for (String intentionText : myModel.myIntentions.keySet()) { - final ApplyIntentionAction intentionAction = myModel.myIntentions.get(intentionText); - if (myModel.actionMatches(pattern, intentionAction) != MatchMode.NONE) { - intentions.add(new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext)); - } - } + MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); + JBIterable intentions = JBIterable.from(myModel.myIntentions.keySet()) + .transform(intentionText -> { + ApplyIntentionAction intentionAction = myModel.myIntentions.get(intentionText); + if (myModel.actionMatches(pattern, matcher, intentionAction) == MatchMode.NONE) return null; + return new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext); + }) + .filter(Condition.NOT_NULL); return processItems(pattern, intentions, consumer); } - private static boolean processItems(final String pattern, Collection items, Processor consumer) { - List matched = ContainerUtil.map(items, new Function() { - @Override - public MatchedValue fun(Comparable comparable) { - return new MatchedValue(comparable, pattern); - } - }); + private static boolean processItems(String pattern, JBIterable items, Processor consumer) { + ArrayList matched = ContainerUtil.newArrayList(); + items.transform(o -> { + ProgressManager.checkCanceled(); + return o instanceof MatchedValue ? (MatchedValue)o : new MatchedValue(o, pattern); + }).addAllTo(matched); Collections.sort(matched); return ContainerUtil.process(matched, consumer); } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index 6d2333a941ea..4069b7cdbd2e 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -39,6 +39,8 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.OnOffButton; @@ -49,7 +51,6 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; -import org.apache.oro.text.regex.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -60,13 +61,14 @@ import java.awt.*; import java.util.*; import java.util.List; import java.util.regex.Matcher; +import java.util.regex.Pattern; import static com.intellij.ui.SimpleTextAttributes.STYLE_PLAIN; import static com.intellij.ui.SimpleTextAttributes.STYLE_SEARCH_MATCH; @SuppressWarnings("TestOnlyProblems") public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, Comparator, EdtSortingModel, DumbAware { - @NotNull private static java.util.regex.Pattern INNER_GROUP_WITH_IDS = java.util.regex.Pattern.compile("(.*) \\(\\d+\\)"); + private static final Pattern INNER_GROUP_WITH_IDS = Pattern.compile("(.*) \\(\\d+\\)"); @Nullable private final Project myProject; private final Component myContextComponent; @@ -75,8 +77,6 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C private static final Icon EMPTY_ICON = EmptyIcon.ICON_18; - private Pattern myCompiledPattern; - protected final SearchableOptionsRegistrar myIndex; protected final Map myActionGroups = ContainerUtil.newHashMap(); @@ -235,7 +235,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C @Override public ListCellRenderer getListCellRenderer() { - return new GotoActionListCellRenderer(description -> getGroupName(description)); + return new GotoActionListCellRenderer(this::getGroupName); } protected String getActionId(@NotNull AnAction anAction) { @@ -402,36 +402,28 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C public boolean matches(@NotNull String name, @NotNull String pattern) { AnAction anAction = myActionManager.getAction(name); if (anAction == null) return true; - return actionMatches(pattern, anAction) != MatchMode.NONE; + MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); + return actionMatches(pattern, matcher, anAction) != MatchMode.NONE; } - protected MatchMode actionMatches(@NotNull String pattern, @NotNull AnAction anAction) { - Pattern compiledPattern = getPattern(pattern); + protected MatchMode actionMatches(@NotNull String pattern, MinusculeMatcher matcher, @NotNull AnAction anAction) { Presentation presentation = anAction.getTemplatePresentation(); String text = presentation.getText(); String description = presentation.getDescription(); String groupName = myActionGroups.get(anAction); - PatternMatcher matcher = getMatcher(); - if (text != null && matcher.matches(text, compiledPattern)) { + if (text != null && matcher.matches(text)) { return MatchMode.NAME; } - else if (description != null && !description.equals(text) && matcher.matches(description, compiledPattern)) { + else if (description != null && !description.equals(text) && matcher.matches(description)) { return MatchMode.DESCRIPTION; } if (text == null) { return MatchMode.NONE; } - if (groupName == null) { - return matches(pattern, compiledPattern, matcher, text) ? MatchMode.NON_MENU : MatchMode.NONE; - } - if (matches(pattern, compiledPattern, matcher, groupName + " " + text)) { + if (matcher.matches(groupName + " " + text)) { return anAction instanceof ToggleAction ? MatchMode.NAME : MatchMode.GROUP; } - return matches(pattern, compiledPattern, matcher, text + " " + groupName) ? MatchMode.GROUP : MatchMode.NONE; - } - - private static boolean matches(@NotNull String pattern, Pattern compiledPattern, @NotNull PatternMatcher matcher, @NotNull String str) { - return StringUtil.containsIgnoreCase(str, pattern) || matcher.matches(str, compiledPattern); + return matcher.matches(text + " " + groupName) ? MatchMode.GROUP : MatchMode.NONE; } @Nullable @@ -443,25 +435,6 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C return myContextComponent; } - @NotNull - Pattern getPattern(@NotNull String pattern) { - String converted = convertPattern(pattern.trim()); - Pattern compiledPattern = myCompiledPattern; - if (compiledPattern != null && !Comparing.strEqual(converted, compiledPattern.getPattern())) { - compiledPattern = null; - } - if (compiledPattern == null) { - try { - myCompiledPattern = compiledPattern = new Perl5Compiler().compile(converted, Perl5Compiler.READ_ONLY_MASK); - } - catch (MalformedPatternException e) { - //do nothing - } - } - - return compiledPattern; - } - @NotNull @Override public SortedSet sort(@NotNull Set elements) { @@ -474,93 +447,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C NONE, INTENTION, NAME, DESCRIPTION, GROUP, NON_MENU } - static String convertPattern(@NotNull String pattern) { - int eol = pattern.indexOf('\n'); - if (eol != -1) { - pattern = pattern.substring(0, eol); - } - if (pattern.length() >= 80) { - pattern = pattern.substring(0, 80); - } - @NonNls StringBuilder buffer = new StringBuilder(); - - boolean allowToLower = true; - if (containsOnlyUppercaseLetters(pattern)) { - allowToLower = false; - } - - if (allowToLower) { - buffer.append(".*"); - } - - boolean firstIdentifierLetter = true; - for (int i = 0; i < pattern.length(); i++) { - char c = pattern.charAt(i); - if (Character.isLetterOrDigit(c)) { - // This logic allows to use uppercase letters only to catch the name like PDM for PsiDocumentManager - if (Character.isUpperCase(c) || Character.isDigit(c)) { - - if (!firstIdentifierLetter) { - buffer.append("[^A-Z]*"); - } - - buffer.append("["); - buffer.append(c); - if (allowToLower || i == 0) { - buffer.append('|'); - buffer.append(Character.toLowerCase(c)); - } - buffer.append("]"); - } - else if (Character.isLowerCase(c)) { - buffer.append('['); - buffer.append(c); - buffer.append('|'); - buffer.append(Character.toUpperCase(c)); - buffer.append(']'); - } - else { - buffer.append(c); - } - - firstIdentifierLetter = false; - } - else if (c == '*') { - buffer.append(".*"); - firstIdentifierLetter = true; - } - else if (c == '.') { - buffer.append("\\."); - firstIdentifierLetter = true; - } - else if (c == ' ') { - buffer.append(".*\\ "); - firstIdentifierLetter = true; - } - else { - firstIdentifierLetter = true; - // for standard RegExp engine - // buffer.append("\\u"); - // buffer.append(Integer.toHexString(c + 0x20000).substring(1)); - - // for OROMATCHER RegExp engine - buffer.append("\\x"); - buffer.append(Integer.toHexString(c + 0x20000).substring(3)); - } - } - - buffer.append(".*"); - return buffer.toString(); - } - - private static boolean containsOnlyUppercaseLetters(@NotNull String s) { - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c != '*' && c != ' ' && !Character.isUpperCase(c)) return false; - } - return true; - } @Override public boolean willOpenEditor() { @@ -572,17 +459,6 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C return true; } - private final ThreadLocal myMatcher = new ThreadLocal() { - @NotNull - @Override - protected PatternMatcher initialValue() { - return new Perl5Matcher(); - } - }; - PatternMatcher getMatcher() { - return myMatcher.get(); - } - public static class ActionWrapper implements Comparable { @NotNull private final AnAction myAction; @NotNull private final MatchMode myMode;