From daa8dd3eee5e2960f4f77c601510fb999ad28cbb Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 16 Feb 2017 18:46:53 +0100 Subject: [PATCH] java/groovy completion: load more class name variants when prefix is changed (IDEA-168079) --- .../completion/JavaNoVariantsDelegator.java | 6 +- .../completion/JavaAutoPopupTest.groovy | 28 +++++++ .../completion/impl/BetterPrefixMatcher.java | 75 ++++++++++++++----- .../completion/GroovyNoVariantsDelegator.java | 4 +- .../completion/GroovyAutoPopupTest.groovy | 28 +++++++ 5 files changed, 118 insertions(+), 23 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index 302b3a886e4a..e38133bb3cc4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -65,8 +65,8 @@ public class JavaNoVariantsDelegator extends CompletionContributor { result.runRemainingContributors(parameters, tracker); final boolean empty = tracker.containsOnlyPackages || suggestAllAnnotations(parameters); - if (!empty && parameters.getInvocationCount() == 0) { - result.restartCompletionWhenNothingMatches(); + if (JavaCompletionContributor.isClassNamePossible(parameters) && !JavaCompletionContributor.mayStartClassName(result)) { + result.restartCompletionOnAnyPrefixChange(); } if (empty) { @@ -207,7 +207,7 @@ public class JavaNoVariantsDelegator extends CompletionContributor { public ResultTracker(CompletionResultSet result) { myResult = result; - betterMatcher = new BetterPrefixMatcher(result); + betterMatcher = new BetterPrefixMatcher.AutoRestarting(result); } @Override diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index f79577088330..1b01089eceaf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -1805,4 +1805,32 @@ ita assert lookup assert myFixture.lookupElementStrings == ['itar'] } + + void "test expand class list when typing more or moving caret"() { + myFixture.addClass 'package foo; public class KimeFamilyRange {}' + myFixture.addClass 'package foo; public class FamiliesRangesMetaData {}' + myFixture.addClass 'public class KSomethingInCurrentPackage {}' + myFixture.configureByText 'a.java', 'class Foo { }' + + type 'F' + assert !myFixture.lookupElementStrings.contains('KimeFamilyRange') + + type 'aRa' + myFixture.assertPreferredCompletionItems 0, 'FamiliesRangesMetaData', 'KimeFamilyRange' + + 4.times { + edt { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_LEFT) } + joinCompletion() + } + assert !myFixture.lookupElementStrings.contains('KimeFamilyRange') + + type 'K' + + 4.times { + edt { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT) } + joinCompletion() + } + + myFixture.assertPreferredCompletionItems 0, 'KimeFamilyRange' + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java index 2a84a4200405..1a62abef7a47 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java @@ -39,32 +39,43 @@ public class BetterPrefixMatcher extends PrefixMatcher { myMinMatchingDegree = minMatchingDegree; } - public BetterPrefixMatcher(CompletionResultSet set) { - this(set.getPrefixMatcher(), Integer.MIN_VALUE); - } - @NotNull public BetterPrefixMatcher improve(CompletionResult result) { int degree = RealPrefixMatchingWeigher.getBestMatchingDegree(result.getLookupElement(), result.getPrefixMatcher()); if (degree <= myMinMatchingDegree) return this; - return new BetterPrefixMatcher(myOriginal, degree); + return createCopy(myOriginal, degree); } - + + @NotNull + protected BetterPrefixMatcher createCopy(PrefixMatcher original, int degree) { + return new BetterPrefixMatcher(original, degree); + } + @Override public boolean prefixMatches(@NotNull String name) { - if (myHumpMatcher != null) { - FList fragments = myHumpMatcher.matchingFragments(name); - if (fragments == null || !MinusculeMatcher.isStartMatch(fragments)) { - return false; - } - return myHumpMatcher.matchingDegree(name, fragments) >= myMinMatchingDegree; - } + return prefixMatchesEx(name) == MatchingOutcome.BETTER_MATCH; + } - if (!myOriginal.prefixMatches(name) || !myOriginal.isStartMatch(name)) { - return false; - } - return myOriginal.matchingDegree(name) >= myMinMatchingDegree; + protected MatchingOutcome prefixMatchesEx(String name) { + return myHumpMatcher != null ? matchOptimized(name, myHumpMatcher) : matchGeneric(name); + } + + private MatchingOutcome matchGeneric(String name) { + if (!myOriginal.prefixMatches(name)) return MatchingOutcome.NON_MATCH; + if (!myOriginal.isStartMatch(name)) return MatchingOutcome.WORSE_MATCH; + return myOriginal.matchingDegree(name) >= myMinMatchingDegree ? MatchingOutcome.BETTER_MATCH : MatchingOutcome.WORSE_MATCH; + } + + private MatchingOutcome matchOptimized(String name, CamelHumpMatcher matcher) { + FList fragments = matcher.matchingFragments(name); + if (fragments == null) return MatchingOutcome.NON_MATCH; + if (!MinusculeMatcher.isStartMatch(fragments)) return MatchingOutcome.WORSE_MATCH; + return matcher.matchingDegree(name, fragments) >= myMinMatchingDegree ? MatchingOutcome.BETTER_MATCH : MatchingOutcome.WORSE_MATCH; + } + + protected enum MatchingOutcome { + NON_MATCH, WORSE_MATCH, BETTER_MATCH } @Override @@ -80,6 +91,34 @@ public class BetterPrefixMatcher extends PrefixMatcher { @NotNull @Override public PrefixMatcher cloneWithPrefix(@NotNull String prefix) { - return new BetterPrefixMatcher(myOriginal.cloneWithPrefix(prefix), myMinMatchingDegree); + return createCopy(myOriginal.cloneWithPrefix(prefix), myMinMatchingDegree); + } + + public static class AutoRestarting extends BetterPrefixMatcher { + private final CompletionResultSet myResult; + + public AutoRestarting(@NotNull CompletionResultSet result) { + this(result, result.getPrefixMatcher(), Integer.MIN_VALUE); + } + + private AutoRestarting(CompletionResultSet result, PrefixMatcher original, int minMatchingDegree) { + super(original, minMatchingDegree); + myResult = result; + } + + @NotNull + @Override + protected BetterPrefixMatcher createCopy(PrefixMatcher original, int degree) { + return new AutoRestarting(myResult, original, degree); + } + + @Override + protected MatchingOutcome prefixMatchesEx(String name) { + MatchingOutcome outcome = super.prefixMatchesEx(name); + if (outcome == MatchingOutcome.WORSE_MATCH) { + myResult.restartCompletionOnAnyPrefixChange(); + } + return outcome; + } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java index c805ffb0fb57..ef0deb4aac20 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java @@ -52,8 +52,8 @@ public class GroovyNoVariantsDelegator extends CompletionContributor { result.runRemainingContributors(parameters, tracker); final boolean empty = tracker.containsOnlyPackages || suggestAnnotations(parameters); - if (!empty && parameters.getInvocationCount() == 0) { - result.restartCompletionWhenNothingMatches(); + if (GrMainCompletionProvider.isClassNamePossible(parameters.getPosition()) && !JavaCompletionContributor.mayStartClassName(result)) { + result.restartCompletionOnAnyPrefixChange(); } if (empty) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index 6e85ba21e03b..d44b373e1e18 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -248,5 +248,33 @@ foo(new ) assert !lookup } + void "test expand class list when typing more or moving caret"() { + myFixture.addClass 'package foo; public class KimeFamilyRange {}' + myFixture.addClass 'package foo; public class FamiliesRangesMetaData {}' + myFixture.addClass 'public class KSomethingInCurrentPackage {}' + myFixture.configureByText 'a.groovy', '' + + type 'F' + assert !myFixture.lookupElementStrings.contains('KimeFamilyRange') + + type 'aRa' + myFixture.assertPreferredCompletionItems 0, 'FamiliesRangesMetaData', 'KimeFamilyRange' + + 4.times { + edt { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_LEFT) } + myTester.joinCompletion() + } + assert !myFixture.lookupElementStrings.contains('KimeFamilyRange') + + type 'K' + + 4.times { + edt { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT) } + myTester.joinCompletion() + } + + myFixture.assertPreferredCompletionItems 0, 'KimeFamilyRange' + } + }