autopopup with all class names when nothing imported is found

This commit is contained in:
peter
2011-11-08 20:38:06 +01:00
parent 9a8357225a
commit 5790df8467
11 changed files with 211 additions and 8 deletions
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2011 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.codeInsight.completion;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.util.Consumer;
/**
* @author peter
*/
public class ClassByNameMerger implements Consumer<LookupElement> {
private int number = 0;
private LookupElement lastElement;
private final boolean myShouldMerge;
private final CompletionResultSet myResult;
public ClassByNameMerger(boolean shouldMerge, CompletionResultSet result) {
myShouldMerge = shouldMerge;
myResult = result;
}
@Override
public void consume(LookupElement element) {
if (!myShouldMerge) {
myResult.addElement(element);
return;
}
if (lastElement != null) {
if (lastElement.getLookupString().equals(element.getLookupString())) {
number++;
lastElement = LookupElementBuilder.create(element.getLookupString()).setTailText(" (" + number + " variants...)", true);
return;
}
myResult.addElement(lastElement);
}
lastElement = element;
number = 1;
}
public void finishedClassProcessing() {
if (lastElement != null) {
myResult.addElement(lastElement);
}
}
}
@@ -36,11 +36,17 @@ public class JavaNoVariantsDelegator extends CompletionContributor {
};
result.runRemainingContributors(parameters, passResult);
if (!empty.get() && parameters.getInvocationCount() == 0) {
result.restartCompletionWhenNothingMatches();
}
if (empty.get()) {
if (parameters.getCompletionType() == CompletionType.BASIC &&
parameters.getInvocationCount() == 1 &&
parameters.getInvocationCount() <= 1 &&
JavaCompletionContributor.mayStartClassName(result, false) &&
JavaCompletionContributor.isClassNamePossible(parameters.getPosition())) {
final ClassByNameMerger merger = new ClassByNameMerger(parameters.getInvocationCount() == 0, result);
JavaClassNameCompletionContributor.addAllClasses(parameters, JavaCompletionSorting.addJavaSorting(parameters, result),
true, new Consumer<LookupElement>() {
@Override
@@ -49,9 +55,13 @@ public class JavaNoVariantsDelegator extends CompletionContributor {
if (classElement != null) {
classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
}
result.addElement(element);
merger.consume(classElement);
}
});
merger.finishedClassProcessing();
} else if (parameters.getCompletionType() == CompletionType.SMART && parameters.getInvocationCount() == 2) {
result.runRemainingContributors(parameters.withInvocationCount(3), passResult);
}
@@ -1095,5 +1095,20 @@ class Foo {{
assert end == myFixture.editor.caretModel.logicalPosition
}
public void testNonImportedClass() {
myFixture.addClass("package foo; public class Abcdefg {}")
myFixture.configureByText 'a.java', 'class Foo extends <caret>'
type 'Abcde '
myFixture.checkResult 'import foo.Abcdefg;\n\nclass Foo extends Abcdefg <caret>'
}
public void testTwoNonImportedClasses() {
myFixture.addClass("package foo; public class Abcdefg {}")
myFixture.addClass("package bar; public class Abcdefg {}")
myFixture.configureByText 'a.java', 'class Foo extends <caret>'
type 'Abcde '
myFixture.checkResult 'class Foo extends Abcdefg <caret>'
}
}
@@ -99,4 +99,6 @@ public abstract class CompletionResultSet {
}
public abstract void restartCompletionOnPrefixChange(ElementPattern<String> prefixCondition);
public abstract void restartCompletionWhenNothingMatches();
}
@@ -501,7 +501,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
private boolean hideAutopopupIfMeaningless() {
if (isAutopopupCompletion() && !myLookup.isSelectionTouched() && !myLookup.isCalculating()) {
if (!myLookup.isLookupDisposed() && isAutopopupCompletion() && !myLookup.isSelectionTouched() && !myLookup.isCalculating()) {
myLookup.refreshUi(true);
final List<LookupElement> items = myLookup.getItems();
@@ -618,7 +618,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
final CompletionProgressIndicator current = CompletionServiceImpl.getCompletionService().getCurrentCompletion();
LOG.assertTrue(this == current, current + "!=" + this);
if (isAutopopupCompletion() && (myLookup.isLookupDisposed() || !myLookup.isShown() || hideAutopopupIfMeaningless())) {
if (isAutopopupCompletion() && !myLookup.isShown()) {
if (CompletionServiceImpl.getCompletionService().getCurrentCompletion() == this) {
closeAndFinish(true);
}
@@ -627,6 +627,8 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
return;
}
hideAutopopupIfMeaningless();
final CompletionPhase.CommittingDocuments phase = new CompletionPhase.CommittingDocuments(this, myEditor);
CompletionServiceImpl.setCompletionPhase(phase);
@@ -181,6 +181,14 @@ public class CompletionServiceImpl extends CompletionService{
indicator.addWatchedPrefix(myTextBeforePosition.length() - getPrefixMatcher().getPrefix().length(), prefixCondition);
}
}
@Override
public void restartCompletionWhenNothingMatches() {
final CompletionProgressIndicator indicator = getCompletionService().getCurrentCompletion();
if (indicator != null) {
indicator.getLookup().setStartCompletionWhenNothingMatches(true);
}
}
}
public static boolean assertPhase(Class<? extends CompletionPhase>... possibilities) {
@@ -84,7 +84,12 @@ public class LookupTypedHandler extends TypedHandlerDelegate {
});
lookup.appendPrefix(charTyped);
if (lookup.isStartCompletionWhenNothingMatches() && lookup.getItems().isEmpty()) {
AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor, null);
final CompletionProgressIndicator completion = CompletionServiceImpl.getCompletionService().getCurrentCompletion();
if (completion != null) {
completion.scheduleRestart();
} else {
AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor, null);
}
}
AutoHardWrapHandler.getInstance().wrapLineIfNecessary(editor, DataManager.getInstance().getDataContext(editor.getContentComponent()), modificationStamp);
+1
View File
@@ -235,6 +235,7 @@
implementationClass="org.jetbrains.plugins.groovy.codeInsight.GroovyLineMarkerProvider"/>
<codeInsight.gotoSuper language="Groovy" implementationClass="org.jetbrains.plugins.groovy.codeInsight.navigation.actions.GroovyGotoSuperHandler"/>
<lookup.charFilter implementation="org.jetbrains.plugins.groovy.lang.completion.GroovyReferenceCharFilter"/>
<completion.contributor language="Groovy" implementationClass="org.jetbrains.plugins.groovy.lang.completion.GroovyNoVariantsDelegator" id="groovyBasic2ClassName" order="first"/>
<completion.contributor language="Groovy" implementationClass="org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionContributor" id="groovyBasic"/>
<completion.contributor language="Groovy" implementationClass="org.jetbrains.plugins.groovy.lang.completion.GroovySmartCompletionContributor"/>
<completion.contributor language="Groovy" implementationClass="org.jetbrains.plugins.groovy.lang.completion.GrMethodMergingContributor"
@@ -174,13 +174,22 @@ public class GroovyCompletionContributor extends CompletionContributor {
private static void addAllClasses(CompletionParameters parameters, final CompletionResultSet result, final InheritorsHolder inheritors) {
addAllClasses(parameters, result, new Consumer<LookupElement>() {
@Override
public void consume(LookupElement element) {
result.addElement(element);
}
}, inheritors);
}
public static void addAllClasses(CompletionParameters parameters, CompletionResultSet result, final Consumer<LookupElement> consumer, final InheritorsHolder inheritors) {
final PsiElement position = parameters.getPosition();
final ElementFilter filter = getClassFilter(position);
AllClassesGetter.processJavaClasses(parameters, result.getPrefixMatcher(), parameters.getInvocationCount() <= 1, new Consumer<PsiClass>() {
@Override
public void consume(PsiClass psiClass) {
if (!inheritors.alreadyProcessed(psiClass) && filter.isAcceptable(psiClass, position)) {
result.addElement(GroovyCompletionUtil.createClassLookupItem(psiClass));
consumer.consume(GroovyCompletionUtil.createClassLookupItem(psiClass));
}
}
});
@@ -311,8 +320,7 @@ public class GroovyCompletionContributor extends CompletionContributor {
if (reference.getQualifier() == null) {
GroovySmartCompletionContributor.addExpectedClassMembers(parameters, result);
if (!PsiJavaPatterns.psiElement().inside(GrImportStatement.class).accepts(position) &&
JavaCompletionContributor.mayStartClassName(result, parameters.isRelaxedMatching())) {
if (isClassNamePossible(position) && JavaCompletionContributor.mayStartClassName(result, parameters.isRelaxedMatching())) {
if (JavaCompletionContributor.mayShowAllClasses(parameters)) {
addAllClasses(parameters, result, inheritors);
} else {
@@ -350,6 +358,12 @@ public class GroovyCompletionContributor extends CompletionContributor {
}
public static boolean isClassNamePossible(PsiElement position) {
PsiElement parent = position.getParent();
return parent instanceof GrReferenceElement && ((GrReferenceElement)parent).getQualifier() == null &&
!PsiJavaPatterns.psiElement().inside(GrImportStatement.class).accepts(position);
}
private static void addUnfinishedMethodTypeParameters(PsiElement position, CompletionResultSet result) {
final ProcessingContext context = new ProcessingContext();
if (PsiJavaPatterns.psiElement().inside(
@@ -0,0 +1,69 @@
/*
* Copyright 2000-2011 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 org.jetbrains.plugins.groovy.lang.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.util.Ref;
import com.intellij.util.Consumer;
/**
* @author peter
*/
public class GroovyNoVariantsDelegator extends CompletionContributor {
@Override
public void fillCompletionVariants(final CompletionParameters parameters, final CompletionResultSet result) {
final Ref<Boolean> empty = Ref.create(true);
Consumer<CompletionResult> passResult = new Consumer<CompletionResult>() {
public void consume(final CompletionResult lookupElement) {
empty.set(false);
result.passResult(lookupElement);
}
};
result.runRemainingContributors(parameters, passResult);
if (!empty.get() && parameters.getInvocationCount() == 0) {
result.restartCompletionWhenNothingMatches();
}
if (empty.get()) {
if (parameters.getCompletionType() == CompletionType.BASIC &&
parameters.getInvocationCount() <= 1 &&
JavaCompletionContributor.mayStartClassName(result, false) &&
GroovyCompletionContributor.isClassNamePossible(parameters.getPosition())) {
final ClassByNameMerger merger = new ClassByNameMerger(parameters.getInvocationCount() == 0, result);
GroovyCompletionContributor.addAllClasses(parameters, result,
new Consumer<LookupElement>() {
@Override
public void consume(LookupElement element) {
JavaPsiClassReferenceElement classElement = element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY);
if (classElement != null) {
classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
}
merger.consume(classElement);
}
}, new InheritorsHolder(parameters.getPosition(), result));
merger.finishedClassProcessing();
}
}
}
}
@@ -197,4 +197,20 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase {
type ' in c'
assert lookup.focused
}
public void testNonImportedClass() {
myFixture.addClass("package foo; public class Abcdefg {}")
myFixture.configureByText 'a.groovy', '<caret>'
type 'Abcde '
myFixture.checkResult 'import foo.Abcdefg\n\nAbcdefg <caret>'
}
public void testTwoNonImportedClasses() {
myFixture.addClass("package foo; public class Abcdefg {}")
myFixture.addClass("package bar; public class Abcdefg {}")
myFixture.configureByText 'a.groovy', '<caret>'
type 'Abcde '
myFixture.checkResult 'Abcdefg <caret>'
}
}