diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/confidence/EnableAutopopupInStringTemplate.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/confidence/EnableAutopopupInStringTemplate.kt new file mode 100644 index 00000000000..e93eff2afdc --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/confidence/EnableAutopopupInStringTemplate.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2017 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.kotlin.idea.completion.confidence + +import com.intellij.codeInsight.completion.CompletionConfidence +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.util.ThreeState +import org.jetbrains.kotlin.psi.KtSimpleNameStringTemplateEntry +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.psi.psiUtil.prevLeaf + +class EnableAutopopupInStringTemplate : CompletionConfidence() { + override fun shouldSkipAutopopup(contextElement: PsiElement, psiFile: PsiFile, offset: Int): ThreeState { + val stringTemplate = contextElement.prevLeaf()?.getParentOfType(strict = false) ?: return ThreeState.UNSURE + val textRange = TextRange.create(stringTemplate.endOffset, offset) + val containsWhitespaces = textRange.substring(psiFile.text).any { it.isWhitespace() } + return if (containsWhitespaces) ThreeState.UNSURE else ThreeState.NO + } +} \ No newline at end of file diff --git a/idea/idea-completion/testData/confidence/AutoPopupInStringTemplate.kt b/idea/idea-completion/testData/confidence/AutoPopupInStringTemplate.kt new file mode 100644 index 00000000000..1d5992bdcd2 --- /dev/null +++ b/idea/idea-completion/testData/confidence/AutoPopupInStringTemplate.kt @@ -0,0 +1,10 @@ +class Bar { + val aa = "Some" +} + +fun foo() { + val bar = Bar() + val y = "$bar." +} + +// ELEMENT: aa \ No newline at end of file diff --git a/idea/idea-completion/testData/confidence/NoAutoPopupInRawStringTemplateAfterNewLine.kt b/idea/idea-completion/testData/confidence/NoAutoPopupInRawStringTemplateAfterNewLine.kt new file mode 100644 index 00000000000..2723b9eafd2 --- /dev/null +++ b/idea/idea-completion/testData/confidence/NoAutoPopupInRawStringTemplateAfterNewLine.kt @@ -0,0 +1,11 @@ +class Bar { + val aa = "Some" +} + +fun foo() { + val bar = Bar() + val y = """$bar. +a""" +} + +// NO_LOOKUP \ No newline at end of file diff --git a/idea/idea-completion/testData/confidence/NoAutoPopupInString.kt b/idea/idea-completion/testData/confidence/NoAutoPopupInString.kt index 949fcc773a6..b848b47f002 100644 --- a/idea/idea-completion/testData/confidence/NoAutoPopupInString.kt +++ b/idea/idea-completion/testData/confidence/NoAutoPopupInString.kt @@ -2,3 +2,4 @@ fun test() { "a" } +// NO_LOOKUP \ No newline at end of file diff --git a/idea/idea-completion/testData/confidence/NoAutoPopupInStringTemplateAfterSpace.kt b/idea/idea-completion/testData/confidence/NoAutoPopupInStringTemplateAfterSpace.kt new file mode 100644 index 00000000000..c8866f62563 --- /dev/null +++ b/idea/idea-completion/testData/confidence/NoAutoPopupInStringTemplateAfterSpace.kt @@ -0,0 +1,10 @@ +class Bar { + val aa = "Some" +} + +fun foo() { + val bar = Bar() + val y = "$bar. a" +} + +// NO_LOOKUP \ No newline at end of file diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/confidence/KotlinConfidenceTest.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/confidence/KotlinConfidenceTest.java index cbbf5b04b85..c2c5bb6e707 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/confidence/KotlinConfidenceTest.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/confidence/KotlinConfidenceTest.java @@ -20,10 +20,13 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; import com.intellij.codeInsight.completion.CompletionType; import com.intellij.codeInsight.completion.LightCompletionTestCase; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; import org.apache.commons.lang.SystemUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.idea.completion.test.CompletionTestUtilKt; @@ -32,6 +35,7 @@ import org.jetbrains.kotlin.idea.test.TestUtilsKt; import org.jetbrains.kotlin.test.InTextDirectivesUtils; import java.io.File; +import java.util.List; public class KotlinConfidenceTest extends LightCompletionTestCase { private static final String TYPE_DIRECTIVE_PREFIX = "// TYPE:"; @@ -60,6 +64,18 @@ public class KotlinConfidenceTest extends LightCompletionTestCase { doTest(); } + public void testAutoPopupInStringTemplate() { + doTest(); + } + + public void testNoAutoPopupInStringTemplateAfterSpace() { + doTest(); + } + + public void testNoAutoPopupInRawStringTemplateAfterNewLine() { + doTest(); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -83,23 +99,31 @@ public class KotlinConfidenceTest extends LightCompletionTestCase { try { configureByFile(getBeforeFileName()); - String typeText = getTypeTextFromFile(); - if (typeText != null) { - type(typeText); - checkResultByFile(getAfterFileName()); + String text = getEditor().getDocument().getText(); + String typeText = getTypeText(text); + List expectedElements = InTextDirectivesUtils.findLinesWithPrefixesRemoved(text, "// ELEMENT:"); + boolean noLookup = InTextDirectivesUtils.isDirectiveDefined(text, "// NO_LOOKUP"); + + assertFalse("Can't both expect lookup elements and no lookup", !expectedElements.isEmpty() && noLookup); + + if (noLookup) { + assertNull("Expected no lookup", getLookup()); + return; } - else { - LookupImpl lookup = getLookup(); - assertNull("No completion auto-popup expected", lookup); + else if (!expectedElements.isEmpty()) { + assertContainsItems(ArrayUtil.toStringArray(expectedElements)); + return; } + assertNotNull("You must type something, use // TYPE:", typeText); + type(typeText); + checkResultByFile(getAfterFileName()); } finally { CodeInsightSettings.getInstance().SELECT_AUTOPOPUP_SUGGESTIONS_BY_CHARS = completeByChars; } } - protected static String getTypeTextFromFile() { - String text = getEditor().getDocument().getText(); + protected static String getTypeText(String text) { String[] directives = InTextDirectivesUtils.findArrayWithPrefixes(text, TYPE_DIRECTIVE_PREFIX); if (directives.length == 0) return null; @@ -131,5 +155,9 @@ public class KotlinConfidenceTest extends LightCompletionTestCase { protected void complete() { new CodeCompletionHandlerBase(CompletionType.BASIC, false, true, true).invokeCompletion( getProject(), getEditor(), 0, false, false); + + LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(myEditor); + myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY); + myPrefix = lookup == null ? null : lookup.itemPattern(lookup.getItems().get(0)); } } diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 2a2cc3b9452..54279a74a93 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -491,6 +491,7 @@ +