diff --git a/java/java-impl/src/META-INF/JavaPlugin.xml b/java/java-impl/src/META-INF/JavaPlugin.xml
index 57abb09dd535..a218d100f9ea 100644
--- a/java/java-impl/src/META-INF/JavaPlugin.xml
+++ b/java/java-impl/src/META-INF/JavaPlugin.xml
@@ -1221,7 +1221,7 @@
-
+
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSymbolNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSymbolNameCompletionContributor.java
new file mode 100644
index 000000000000..3ac387b021b9
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSymbolNameCompletionContributor.java
@@ -0,0 +1,70 @@
+// 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.codeInsight.completion;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.psi.*;
+import com.intellij.util.ObjectUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class JavaSymbolNameCompletionContributor implements SymbolNameCompletionContributor {
+ @NotNull
+ @Override
+ public Collection getLookupElements(@NotNull PsiFile file, int invocationCount, @NotNull String prefix) {
+ PsiClassOwner javaFile = ObjectUtils.tryCast(file, PsiClassOwner.class);
+ if (javaFile == null) return Collections.emptyList();
+ List result = new ArrayList<>();
+ for (PsiClass aClass : javaFile.getClasses()) {
+ String name = aClass.getName();
+ if (name != null) {
+ result.add(LookupElementBuilder.create(name).withIcon(aClass.getIcon(0)));
+ String infix = getInfix(prefix, name);
+ String memberPrefix = null;
+ if (infix != null) {
+ memberPrefix = prefix.substring(0, name.length() + infix.length());
+ }
+ else if (invocationCount <= 0) continue;
+ processClassBody(invocationCount, result, aClass, infix, memberPrefix);
+ }
+ }
+ return result;
+ }
+
+ protected void processClassBody(int invocationCount, List result, PsiElement aClass, String infix, String memberPrefix) {
+ for (PsiElement child = aClass.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (child instanceof PsiField || child instanceof PsiMethod || child instanceof PsiClass) {
+ String memberName = ((PsiMember)child).getName();
+ Icon icon = child.getIcon(0);
+ if (memberName != null) {
+ LookupElementBuilder element = LookupElementBuilder.create(memberName).withIcon(icon);
+ if (invocationCount > 0) {
+ result.add(element);
+ }
+ if (memberPrefix != null) {
+ if (child instanceof PsiMethod || child instanceof PsiField && !infix.equals("::") || infix.equals(".")) {
+ result.add(LookupElementBuilder.create(memberPrefix + memberName).withIcon(icon));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Nullable
+ private static String getInfix(String currentPrefix, String className) {
+ if (!currentPrefix.startsWith(className)) return null;
+ for (String infix : new String[]{".", "#", "::"}) {
+ if (currentPrefix.startsWith(infix, className.length())) {
+ return infix;
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaTopLevelCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaTopLevelCompletionContributor.java
deleted file mode 100644
index 3da557f37810..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaTopLevelCompletionContributor.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.codeInsight.completion;
-
-import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.psi.*;
-import com.intellij.util.ObjectUtils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-public class JavaTopLevelCompletionContributor implements TopLevelCompletionContributor {
- @Override
- public void addLookupElements(@NotNull PsiFile file, int invocationCount, @NotNull CompletionResultSet result) {
- PsiJavaFile javaFile = ObjectUtils.tryCast(file, PsiJavaFile.class);
- if (javaFile == null) return;
- PrefixMatcher currentMatcher = result.getPrefixMatcher();
- for (PsiClass aClass : javaFile.getClasses()) {
- String name = aClass.getName();
- if (name != null) {
- result.addElement(LookupElementBuilder.create(name).withIcon(aClass.getIcon(0)));
- String infix = getInfix(currentMatcher.getPrefix(), name);
- CompletionResultSet prefixed = null;
- if (infix == null) {
- if (invocationCount <= 0) continue;
- }
- else {
- String memberPrefix = currentMatcher.getPrefix().substring(name.length() + infix.length());
- prefixed = result.withPrefixMatcher(currentMatcher.cloneWithPrefix(memberPrefix));
- }
- for (PsiElement child = aClass.getFirstChild(); child != null; child = child.getNextSibling()) {
- if (child instanceof PsiField || child instanceof PsiMethod || child instanceof PsiClass) {
- String memberName = ((PsiMember)child).getName();
- Icon icon = child.getIcon(0);
- if (memberName != null) {
- LookupElementBuilder element = LookupElementBuilder.create(memberName).withIcon(icon);
- if (invocationCount > 0) {
- result.addElement(element);
- }
- if (prefixed != null) {
- if (child instanceof PsiMethod || child instanceof PsiField && !infix.equals("::") || infix.equals(".")) {
- prefixed.addElement(element);
- }
- }
- }
- }
- }
- }
- }
- }
-
- @Nullable
- private static String getInfix(String currentPrefix, String className) {
- if (!currentPrefix.startsWith(className)) return null;
- for (String infix : new String[]{".", "#", "::"}) {
- if (currentPrefix.startsWith(infix, className.length())) {
- return infix;
- }
- }
- return null;
- }
-}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaTopLevelCompletionContributorTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaSymbolNameCompletionContributorTest.java
similarity index 54%
rename from java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaTopLevelCompletionContributorTest.java
rename to java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaSymbolNameCompletionContributorTest.java
index 04aa14c21ac5..ac8d34b101af 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaTopLevelCompletionContributorTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaSymbolNameCompletionContributorTest.java
@@ -1,19 +1,20 @@
// 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.java.codeInsight.completion;
-import com.intellij.codeInsight.completion.CompletionResultSet;
-import com.intellij.codeInsight.completion.TopLevelCompletionContributor;
-import com.intellij.codeInsight.completion.TopLevelCompletionContributorEP;
-import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
+import com.intellij.codeInsight.completion.PlainPrefixMatcher;
+import com.intellij.codeInsight.completion.PrefixMatcher;
+import com.intellij.codeInsight.completion.SymbolNameCompletionContributor;
+import com.intellij.codeInsight.completion.SymbolNameCompletionContributorEP;
+import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
+import one.util.streamex.StreamEx;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
+import java.util.Collection;
-public class JavaTopLevelCompletionContributorTest extends LightJavaCodeInsightFixtureTestCase {
+public class JavaSymbolNameCompletionContributorTest extends LightJavaCodeInsightFixtureTestCase {
public void testBasics() {
PsiFile file = myFixture.configureByText("Test.java", "class Foo {\n" +
" void fooMethod() {}\n" +
@@ -25,20 +26,18 @@ public class JavaTopLevelCompletionContributorTest extends LightJavaCodeInsightF
"}");
checkCompletion(file, "", 0, "Foo", "Bar");
checkCompletion(file, "F", 1, "Foo", "fooMethod", "fooField", "FooClass");
- checkCompletion(file, "Foo::", 0, "fooMethod");
- checkCompletion(file, "Foo#", 0, "fooMethod", "fooField");
- checkCompletion(file, "Foo.", 0, "fooMethod", "fooField", "FooClass");
+ checkCompletion(file, "Foo::", 0, "Foo::fooMethod");
+ checkCompletion(file, "Foo#", 0, "Foo#fooMethod", "Foo#fooField");
+ checkCompletion(file, "Foo.", 0, "Foo.fooMethod", "Foo.fooField", "Foo.FooClass");
checkCompletion(file, "B", 1, "Bar", "Baz");
}
private static void checkCompletion(PsiFile file, String prefix, int invocationCount, String... expected) {
- TopLevelCompletionContributor contributor = TopLevelCompletionContributorEP.forLanguage(JavaLanguage.INSTANCE);
+ SymbolNameCompletionContributor contributor = SymbolNameCompletionContributorEP.forLanguage(JavaLanguage.INSTANCE);
assertNotNull(contributor);
- List options = new ArrayList<>();
- CompletionResultSet resultSet = CompletionServiceImpl.createResultSetForTest(
- option -> options.add(option.getLookupElement().getLookupString()));
- resultSet = resultSet.withPrefixMatcher(prefix);
- contributor.addLookupElements(file, invocationCount, resultSet);
- assertEquals(Arrays.asList(expected), options);
+ Collection options = contributor.getLookupElements(file, invocationCount, prefix);
+ PrefixMatcher matcher = new PlainPrefixMatcher(prefix);
+ assertEquals(Arrays.asList(expected),
+ StreamEx.of(options).filter(matcher::prefixMatches).map(LookupElement::getLookupString).toList());
}
}
diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/TopLevelCompletionContributor.java b/platform/lang-api/src/com/intellij/codeInsight/completion/SymbolNameCompletionContributor.java
similarity index 60%
rename from platform/lang-api/src/com/intellij/codeInsight/completion/TopLevelCompletionContributor.java
rename to platform/lang-api/src/com/intellij/codeInsight/completion/SymbolNameCompletionContributor.java
index 60a069ad56d4..8c62f4bcd0cc 100644
--- a/platform/lang-api/src/com/intellij/codeInsight/completion/TopLevelCompletionContributor.java
+++ b/platform/lang-api/src/com/intellij/codeInsight/completion/SymbolNameCompletionContributor.java
@@ -1,23 +1,29 @@
// 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.codeInsight.completion;
+import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
+import java.util.Collection;
+
/**
* A language-specific completion contributor which provides reasonable amount of symbols declared in given file
* (likely only top-level declarations). Such contributor could be used in plain text editors like VCS commit message field
* to help users referring to code symbols from the text.
*
- * @see TopLevelCompletionContributorEP
+ * @see SymbolNameCompletionContributorEP
*/
-public interface TopLevelCompletionContributor {
+public interface SymbolNameCompletionContributor {
/**
* Adds lookup elements from given file.
*
* @param file file to add elements from.
* @param invocationCount number of times the completion was invoked (see {@link CompletionParameters#getInvocationCount()}).
- * @param result a result object to add elements to (could be already prefixed with current context).
+ * @param prefix a prefix string. It's not required to return only matches starting with prefix, but this may be used to improve
+ * performance.
+ * @return a collection of {@link LookupElement}'s to suggest.
*/
- void addLookupElements(@NotNull PsiFile file, int invocationCount, @NotNull CompletionResultSet result);
+ @NotNull
+ Collection getLookupElements(@NotNull PsiFile file, int invocationCount, @NotNull String prefix);
}
diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/SymbolNameCompletionContributorEP.java b/platform/lang-api/src/com/intellij/codeInsight/completion/SymbolNameCompletionContributorEP.java
new file mode 100644
index 000000000000..a94e93bace29
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/codeInsight/completion/SymbolNameCompletionContributorEP.java
@@ -0,0 +1,17 @@
+// 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.codeInsight.completion;
+
+import com.intellij.lang.Language;
+import com.intellij.lang.LanguageExtension;
+import com.intellij.lang.LanguageExtensionPoint;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import org.jetbrains.annotations.NotNull;
+
+public class SymbolNameCompletionContributorEP extends LanguageExtensionPoint {
+ private static final ExtensionPointName EP = new ExtensionPointName<>("com.intellij.completion.toplevel");
+ private static final LanguageExtension INSTANCE = new CompletionExtension<>(EP.getName());
+
+ public static SymbolNameCompletionContributor forLanguage(@NotNull Language language) {
+ return INSTANCE.forLanguage(language);
+ }
+}
diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/TopLevelCompletionContributorEP.java b/platform/lang-api/src/com/intellij/codeInsight/completion/TopLevelCompletionContributorEP.java
deleted file mode 100644
index 4ae2f98066fe..000000000000
--- a/platform/lang-api/src/com/intellij/codeInsight/completion/TopLevelCompletionContributorEP.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.codeInsight.completion;
-
-import com.intellij.lang.Language;
-import com.intellij.lang.LanguageExtension;
-import com.intellij.lang.LanguageExtensionPoint;
-import com.intellij.openapi.extensions.ExtensionPointName;
-import org.jetbrains.annotations.NotNull;
-
-public class TopLevelCompletionContributorEP extends LanguageExtensionPoint {
- private static final ExtensionPointName EP = new ExtensionPointName<>("com.intellij.completion.toplevel");
- private static final LanguageExtension INSTANCE = new CompletionExtension<>(EP.getName());
-
- public static TopLevelCompletionContributor forLanguage(@NotNull Language language) {
- return INSTANCE.forLanguage(language);
- }
-}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java
index c8a6243c6f77..a6eb4aaf47ad 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java
@@ -20,7 +20,6 @@ import com.intellij.util.Consumer;
import com.intellij.util.ExceptionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.TestOnly;
import java.util.ArrayList;
@@ -101,11 +100,6 @@ public final class CompletionServiceImpl extends CompletionService {
return new CompletionResultSetImpl(consumer, matcher, contributor, parameters, defaultSorter(parameters, matcher), null);
}
- @TestOnly
- public static CompletionResultSet createResultSetForTest(Consumer super CompletionResult> consumer) {
- return new CompletionResultSetImpl(consumer, PrefixMatcher.ALWAYS_TRUE, null, null, new CompletionSorterImpl(new ArrayList<>()), null);
- }
-
@Override
public CompletionProcess getCurrentCompletion() {
CompletionProgressIndicator indicator = getCurrentCompletionProgressIndicator();
diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
index 842d4b14b940..35c0f8f69cd3 100644
--- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
@@ -545,8 +545,8 @@
-
-
+
+
+
getLookupElements(@NotNull PsiFile file, int invocationCount, @NotNull String prefix) {
+ Collection elements = super.getLookupElements(file, invocationCount, prefix);
+ if (file instanceof GroovyFile) {
+ GrMethod[] methods = ((GroovyFile)file).getMethods();
+ for (GrMethod method : methods) {
+ elements.add(LookupElementBuilder.create(method.getName())
+ .withTailText(" in "+file.getName(), true).withIcon(method.getIcon(0)));
+ }
+ }
+ return elements;
+ }
+
+ @Override
+ protected void processClassBody(int invocationCount, List result, PsiElement aClass, String infix, String memberPrefix) {
+ if (aClass instanceof GrTypeDefinition) {
+ GrTypeDefinitionBody body = ((GrTypeDefinition)aClass).getBody();
+ if (body != null) {
+ super.processClassBody(invocationCount, result, body, infix, memberPrefix);
+ }
+ }
+ }
+}