From bfdbbe02470ba972a7cafe498380b7357ae678ce Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 23 Dec 2014 21:31:39 +0300 Subject: [PATCH] KT-6407 Completing function with "tab" (replace) shouldn't insert parentheses when type arguments are present #KT-6407 Fixed --- .../handlers/KotlinCallableInsertHandler.kt | 35 +++++++++++++++---- .../handlers/basic/GenericFunctionWithTab.kt | 6 ++++ .../basic/GenericFunctionWithTab.kt.after | 6 ++++ .../BasicCompletionHandlerTestGenerated.java | 6 ++++ 4 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt create mode 100644 idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt index b383795d0af..4052fbfd3a5 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt @@ -40,12 +40,13 @@ import org.jetbrains.jet.lang.psi.JetSimpleNameExpression import org.jetbrains.jet.lang.psi.JetPsiFactory import org.jetbrains.jet.lang.psi.JetParenthesizedExpression import org.jetbrains.jet.lang.psi.JetBinaryExpressionWithTypeRHS -import org.jetbrains.jet.lang.psi.JetExpression import org.jetbrains.jet.plugin.codeInsight.ShortenReferences -import org.jetbrains.jet.lang.psi.JetCodeFragment import org.jetbrains.jet.lang.psi.psiUtil.getStrictParentOfType import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.jet.plugin.completion.qualifiedNameForSourceCode +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.lang.psi.JetTypeArgumentList +import com.intellij.codeInsight.lookup.Lookup public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler() { public override fun handleInsert(context: InsertionContext, item: LookupElement) { @@ -139,15 +140,34 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val context.setAddCompletionChar(false) } - val offset = context.getTailOffset() + var offset = context.getTailOffset() val document = context.getDocument() + val chars = document.getCharsSequence() - val forceParenthesis = lambdaInfo != null && completionChar == '\t' && document.getCharsSequence().charAt(offset) == '(' + val forceParenthesis = lambdaInfo != null && completionChar == '\t' && chars.charAt(offset) == '(' val braces = lambdaInfo != null && completionChar != '(' && !forceParenthesis val openingBracket = if (braces) '{' else '(' val closingBracket = if (braces) '}' else ')' + if (completionChar == Lookup.REPLACE_SELECT_CHAR) { + offset = skipSpaces(chars, offset) + if (offset < document.getTextLength()) { + val c = chars[offset] + if (c == '<') { + PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) + val psiFile = context.getFile() + val token = psiFile.findElementAt(offset) + if (token.getNode().getElementType() == JetTokens.LT) { + val parent = token.getParent() + if (parent is JetTypeArgumentList && parent.getText().indexOf('\n') < 0/* if type argument list is on multiple lines this is more likely wrong parsing*/) { + offset = parent.getTextRange().getEndOffset() + } + } + } + } + } + var openingBracketOffset = indexOfSkippingSpace(document, openingBracket, offset) var inBracketsShift = 0 if (openingBracketOffset == -1) { @@ -208,13 +228,16 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val private fun indexOfSkippingSpace(document: Document, ch : Char, startIndex : Int) : Int { val text = document.getCharsSequence() for (i in startIndex..text.length() - 1) { - val currentChar = text.charAt(i) + val currentChar = text[i] if (ch == currentChar) return i - if (!Character.isWhitespace(currentChar)) return -1 + if (currentChar != ' ' && currentChar != '\t') return -1 } return -1 } + private fun skipSpaces(chars: CharSequence, index : Int) : Int + = (index..chars.length() - 1).firstOrNull { val c = chars[it]; c != ' ' && c != '\t' } ?: chars.length() + private fun isInsertSpacesInOneLineFunctionEnabled(project : Project) = CodeStyleSettingsManager.getSettings(project) .getCustomSettings(javaClass())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD diff --git a/idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt b/idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt new file mode 100644 index 00000000000..0b558784d7c --- /dev/null +++ b/idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt @@ -0,0 +1,6 @@ +fun foo() {} + +fun use() = f() + +// ELEMENT: foo +// CHAR: '\t' diff --git a/idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt.after b/idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt.after new file mode 100644 index 00000000000..08f69a53ed3 --- /dev/null +++ b/idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt.after @@ -0,0 +1,6 @@ +fun foo() {} + +fun use() = foo() + +// ELEMENT: foo +// CHAR: '\t' diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTestGenerated.java index b522d117ff5..412607e058f 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTestGenerated.java @@ -48,6 +48,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion doTest(fileName); } + @TestMetadata("GenericFunctionWithTab.kt") + public void testGenericFunctionWithTab() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/basic/GenericFunctionWithTab.kt"); + doTest(fileName); + } + @TestMetadata("SecondTypeArg.kt") public void testSecondTypeArg() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/basic/SecondTypeArg.kt");