diff --git a/java/java-tests/testSrc/com/intellij/ide/util/gotoByName/GotoActionTest.groovy b/java/java-tests/testSrc/com/intellij/ide/util/gotoByName/GotoActionTest.groovy index 1b00f8c71176..5f48c43e1289 100644 --- a/java/java-tests/testSrc/com/intellij/ide/util/gotoByName/GotoActionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/ide/util/gotoByName/GotoActionTest.groovy @@ -76,6 +76,15 @@ class GotoActionTest extends LightJavaCodeInsightFixtureTestCase { assert actionMatches('refactor variable', extractMethod) == MatchMode.GROUP } + void "test no lowercase camel-hump action match"() { + def action = ActionManager.instance.getAction("InvalidateCaches") + assert actionMatches('invalid', action) == MatchMode.NAME + assert actionMatches('invalidate caches', action) == MatchMode.NAME + assert actionMatches('cache invalid', action) == MatchMode.NAME + assert actionMatches('rebuild of all caches', action) == MatchMode.DESCRIPTION + assert actionMatches('restart', action) == MatchMode.NONE + } + void "test matched value comparator"() { def pattern = 'Text' def names = ['Text', 'Text completion', 'Completion Text', 'Add text', 'Retextovize mapping', 'Value', 'A', 'Z'] 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 7d5f3b00cf60..d9686af65068 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -1978,7 +1978,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private GotoActionItemProvider createActionProvider() { GotoActionModel model = new GotoActionModel(project, myFocusComponent, myEditor) { @Override - protected MatchMode actionMatches(@NotNull String pattern, MinusculeMatcher matcher, @NotNull AnAction anAction) { + protected MatchMode actionMatches(@NotNull String pattern, Matcher matcher, @NotNull AnAction anAction) { MatchMode mode = super.actionMatches(pattern, matcher, anAction); return mode == MatchMode.NAME ? mode : MatchMode.NONE; } 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 62f015bf226b..877c34964af0 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 @@ -19,14 +19,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.codeStyle.MinusculeMatcher; -import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.switcher.QuickActionProvider; import com.intellij.util.CollectConsumer; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.JBIterable; import com.intellij.util.text.Matcher; +import com.intellij.psi.codeStyle.WordPrefixMatcher; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -149,7 +148,7 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { } } if (!StringUtil.isEmptyOrSpaces(pattern)) { - Matcher matcher = NameUtil.buildMatcher("*" + pattern).build(); + Matcher matcher = buildMatcher(pattern); if (optionDescriptions == null) optionDescriptions = new THashSet<>(); for (Map.Entry entry : map.entrySet()) { if (matcher.matches(entry.getValue())) { @@ -180,7 +179,7 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { private boolean processActions(String pattern, Processor consumer, DataContext dataContext) { Set ids = ((ActionManagerImpl)myActionManager).getActionIds(); JBIterable actions = JBIterable.from(ids).filterMap(myActionManager::getAction); - MinusculeMatcher matcher = buildMatcher(pattern); + Matcher matcher = buildMatcher(pattern); QuickActionProvider provider = dataContext.getData(QuickActionProvider.KEY); if (provider != null) { @@ -196,12 +195,12 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { } @NotNull - static MinusculeMatcher buildMatcher(String pattern) { - return NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); + static Matcher buildMatcher(String pattern) { + return new WordPrefixMatcher(pattern); } private boolean processIntentions(String pattern, Processor consumer, DataContext dataContext) { - MinusculeMatcher matcher = buildMatcher(pattern); + Matcher matcher = buildMatcher(pattern); Map intentionMap = myIntentions.getValue(); JBIterable intentions = JBIterable.from(intentionMap.keySet()) .filterMap(intentionText -> { 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 34b35de27215..7322766673bf 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 @@ -28,7 +28,6 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.OnOffButton; @@ -384,7 +383,7 @@ public class GotoActionModel implements ChooseByNameModel, Comparator, D return ((MatchedValue) mv).getValueText(); } - protected MatchMode actionMatches(@NotNull String pattern, MinusculeMatcher matcher, @NotNull AnAction anAction) { + protected MatchMode actionMatches(@NotNull String pattern, com.intellij.util.text.Matcher matcher, @NotNull AnAction anAction) { Presentation presentation = anAction.getTemplatePresentation(); String text = presentation.getText(); String description = presentation.getDescription(); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/OptionsTopHitProvider.java b/platform/platform-impl/src/com/intellij/ide/ui/OptionsTopHitProvider.java index bdfee639cd13..c91a108d82ed 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/OptionsTopHitProvider.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/OptionsTopHitProvider.java @@ -25,10 +25,10 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.codeStyle.MinusculeMatcher; -import com.intellij.psi.codeStyle.NameUtil; +import com.intellij.psi.codeStyle.WordPrefixMatcher; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.Matcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -117,13 +117,12 @@ public abstract class OptionsTopHitProvider implements OptionsSearchTopHitProvid @Nullable Project project) { if (provider.getId().startsWith(id) || pattern.startsWith(" ")) { pattern = pattern.startsWith(" ") ? pattern.trim() : StringUtil.toLowerCase(pattern.substring(id.length()).trim()); - MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); - consumeTopHitsForApplicableProvider(provider, matcher, collector, project); + consumeTopHitsForApplicableProvider(provider, new WordPrefixMatcher(pattern), collector, project); } } private static void consumeTopHitsForApplicableProvider(@NotNull OptionsSearchTopHitProvider provider, - @NotNull MinusculeMatcher matcher, + @NotNull Matcher matcher, @NotNull Consumer collector, @Nullable Project project) { for (OptionDescription option : getCachedOptions(provider, project, null)) { @@ -220,7 +219,7 @@ public abstract class OptionsTopHitProvider implements OptionsSearchTopHitProvid } public void consumeAllTopHits(@NotNull String pattern, @NotNull Consumer collector, @Nullable Project project) { - MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); + Matcher matcher = new WordPrefixMatcher(pattern); for (OptionsSearchTopHitProvider.ProjectLevelProvider provider : PROJECT_LEVEL_EP.getExtensionList()) { consumeTopHitsForApplicableProvider(provider, matcher, collector, project); } diff --git a/platform/platform-impl/src/com/intellij/psi/codeStyle/WordPrefixMatcher.java b/platform/platform-impl/src/com/intellij/psi/codeStyle/WordPrefixMatcher.java new file mode 100644 index 000000000000..d4eb03e7a474 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/psi/codeStyle/WordPrefixMatcher.java @@ -0,0 +1,23 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.psi.codeStyle; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.Matcher; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +public class WordPrefixMatcher implements Matcher { + private final String[] myPatternWords; + + public WordPrefixMatcher(String pattern) { + myPatternWords = NameUtil.nameToWords(pattern); + } + + @Override + public boolean matches(@NotNull String name) { + String[] nameWords = NameUtil.nameToWords(name); + return Arrays.stream(myPatternWords).allMatch(pw -> ContainerUtil.exists(nameWords, nw -> StringUtil.startsWithIgnoreCase(nw, pw))); + } +}