diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt index ba70a060335..2767fc2d7f5 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt @@ -79,7 +79,7 @@ public class KotlinCompletionCharFilter() : CharFilter() { Result.HIDE_LOOKUP } - ',', ' ', '(', '=' -> Result.SELECT_ITEM_AND_FINISH_LOOKUP + ',', ' ', '(', '=', '!' -> Result.SELECT_ITEM_AND_FINISH_LOOKUP else -> CharFilter.Result.HIDE_LOOKUP } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt index 4295d0dac00..9380fd9f201 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt @@ -142,13 +142,18 @@ class LookupElementsCollector( getDelegate().handleInsert(context) if (context.shouldAddCompletionChar() && !isJustTyping(context, this)) { - val handler = when (context.getCompletionChar()) { - ',' -> WithTailInsertHandler.commaTail() - '=' -> WithTailInsertHandler.eqTail() - else -> null + when (context.getCompletionChar()) { + ',' -> WithTailInsertHandler.commaTail().postHandleInsert(context, getDelegate()) + + '=' -> WithTailInsertHandler.eqTail().postHandleInsert(context, getDelegate()) + + '!' -> { + WithExpressionPrefixInsertHandler("!").postHandleInsert(context) + context.setAddCompletionChar(false) + } } - handler?.postHandleInsert(context, getDelegate()) } + } }) } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/WithExpressionPrefixInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/WithExpressionPrefixInsertHandler.kt new file mode 100644 index 00000000000..0c995f13f4f --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/WithExpressionPrefixInsertHandler.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2015 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.handlers + +import com.intellij.codeInsight.completion.InsertHandler +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.psi.PsiDocumentManager +import org.jetbrains.kotlin.psi.JetCallExpression +import org.jetbrains.kotlin.psi.JetDotQualifiedExpression +import org.jetbrains.kotlin.psi.JetExpression +import org.jetbrains.kotlin.psi.JetSimpleNameExpression +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType + +class WithExpressionPrefixInsertHandler(val prefix: String) : InsertHandler { + override fun handleInsert(context: InsertionContext, item: LookupElement) { + item.handleInsert(context) + + postHandleInsert(context) + } + + fun postHandleInsert(context: InsertionContext) { + PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments() + + val offset = context.getStartOffset() + val token = context.getFile().findElementAt(offset)!! + var expression = token.getStrictParentOfType() ?: return + if (expression is JetSimpleNameExpression) { + var parent = expression.getParent() + if (parent is JetCallExpression && expression == parent.getCalleeExpression()) { + expression = parent + parent = parent.getParent() + } + if (parent is JetDotQualifiedExpression && expression == parent.getSelectorExpression()) { + expression = parent + } + } + + context.getDocument().insertString(expression.getTextRange().getStartOffset(), prefix) + } +} \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt index 2ef61a132d9..bcbc06ba7f6 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt @@ -26,8 +26,8 @@ import com.intellij.psi.PsiDocumentManager import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.completion.* +import org.jetbrains.kotlin.idea.completion.handlers.WithExpressionPrefixInsertHandler import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler -import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.JetValueArgument @@ -99,16 +99,7 @@ fun LookupElement.withOptions(options: ItemOptions): LookupElement { } override fun handleInsert(context: InsertionContext) { - getDelegate().handleInsert(context) - - PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments() - - val offset = context.getStartOffset() - val token = context.getFile().findElementAt(offset)!! - val argument = token.getStrictParentOfType() - if (argument != null) { - context.getDocument().insertString(argument.getArgumentExpression()!!.getTextRange().getStartOffset(), "*") - } + WithExpressionPrefixInsertHandler("*").handleInsert(context, getDelegate()) } } } diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar1.kt b/idea/idea-completion/testData/handlers/basic/ExclChar1.kt new file mode 100644 index 00000000000..73d0fb0cb2a --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar1.kt @@ -0,0 +1,6 @@ +fun foo(flag: Boolean) { + if () +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar1.kt.after b/idea/idea-completion/testData/handlers/basic/ExclChar1.kt.after new file mode 100644 index 00000000000..17c5c86b7dd --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar1.kt.after @@ -0,0 +1,6 @@ +fun foo(flag: Boolean) { + if (!flag) +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar2.kt b/idea/idea-completion/testData/handlers/basic/ExclChar2.kt new file mode 100644 index 00000000000..ce6ddaac821 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar2.kt @@ -0,0 +1,8 @@ +fun String.checkIt(s: String): Boolean = true + +fun foo(s: String) { + if (s.) +} + +// ELEMENT: checkIt +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar2.kt.after b/idea/idea-completion/testData/handlers/basic/ExclChar2.kt.after new file mode 100644 index 00000000000..640ca0a9645 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar2.kt.after @@ -0,0 +1,8 @@ +fun String.checkIt(s: String): Boolean = true + +fun foo(s: String) { + if (!s.checkIt()) +} + +// ELEMENT: checkIt +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar3.kt b/idea/idea-completion/testData/handlers/basic/ExclChar3.kt new file mode 100644 index 00000000000..534c849f04f --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar3.kt @@ -0,0 +1,8 @@ +class C(val flag: Boolean) + +fun foo(c: C) { + if (c.) +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar3.kt.after b/idea/idea-completion/testData/handlers/basic/ExclChar3.kt.after new file mode 100644 index 00000000000..ff5988e7186 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar3.kt.after @@ -0,0 +1,8 @@ +class C(val flag: Boolean) + +fun foo(c: C) { + if (!c.flag) +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar4.kt b/idea/idea-completion/testData/handlers/basic/ExclChar4.kt new file mode 100644 index 00000000000..cfb3db68f8f --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar4.kt @@ -0,0 +1,8 @@ +fun flag(): Boolean{} + +fun foo() { + if () +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar4.kt.after b/idea/idea-completion/testData/handlers/basic/ExclChar4.kt.after new file mode 100644 index 00000000000..4c93f8369f2 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar4.kt.after @@ -0,0 +1,8 @@ +fun flag(): Boolean{} + +fun foo() { + if (!flag()) +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar5.kt b/idea/idea-completion/testData/handlers/basic/ExclChar5.kt new file mode 100644 index 00000000000..c12fb4bc86c --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar5.kt @@ -0,0 +1,6 @@ +fun foo() { + if () +} + +// ELEMENT: true +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/basic/ExclChar5.kt.after b/idea/idea-completion/testData/handlers/basic/ExclChar5.kt.after new file mode 100644 index 00000000000..d64353de193 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/ExclChar5.kt.after @@ -0,0 +1,6 @@ +fun foo() { + if (!true) +} + +// ELEMENT: true +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/smart/ExclChar.kt b/idea/idea-completion/testData/handlers/smart/ExclChar.kt new file mode 100644 index 00000000000..73d0fb0cb2a --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/ExclChar.kt @@ -0,0 +1,6 @@ +fun foo(flag: Boolean) { + if () +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/testData/handlers/smart/ExclChar.kt.after b/idea/idea-completion/testData/handlers/smart/ExclChar.kt.after new file mode 100644 index 00000000000..ca0b6311c4a --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/ExclChar.kt.after @@ -0,0 +1,6 @@ +fun foo(flag: Boolean) { + if (!flag) +} + +// ELEMENT: flag +// CHAR: '!' diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java index 440ed2e5ec2..417e4b4c482 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java @@ -47,6 +47,36 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion doTest(fileName); } + @TestMetadata("ExclChar1.kt") + public void testExclChar1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ExclChar1.kt"); + doTest(fileName); + } + + @TestMetadata("ExclChar2.kt") + public void testExclChar2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ExclChar2.kt"); + doTest(fileName); + } + + @TestMetadata("ExclChar3.kt") + public void testExclChar3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ExclChar3.kt"); + doTest(fileName); + } + + @TestMetadata("ExclChar4.kt") + public void testExclChar4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ExclChar4.kt"); + doTest(fileName); + } + + @TestMetadata("ExclChar5.kt") + public void testExclChar5() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ExclChar5.kt"); + doTest(fileName); + } + @TestMetadata("ExtensionReceiverTypeArg.kt") public void testExtensionReceiverTypeArg() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ExtensionReceiverTypeArg.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java index de5b8f9fcd9..dd00e0bd93c 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java @@ -323,6 +323,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest(fileName); } + @TestMetadata("ExclChar.kt") + public void testExclChar() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/ExclChar.kt"); + doTest(fileName); + } + @TestMetadata("ForLoopRange.kt") public void testForLoopRange() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/ForLoopRange.kt");