From 53fe1568c93bf9d4a30bace8ae5b10d64886cb57 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 20 Jan 2016 21:24:15 +0300 Subject: [PATCH] KT-8529 Code completion for parameter name and type together replaces wrong range on Tab #KT-8529 Fixed --- .../completion/KotlinCompletionContributor.kt | 16 +++++++--- .../ParameterNameAndTypeCompletion.kt | 30 +++++++++++++++---- .../basic/parameterNameAndType/TabReplace1.kt | 6 ++++ .../parameterNameAndType/TabReplace1.kt.after | 6 ++++ .../basic/parameterNameAndType/TabReplace2.kt | 6 ++++ .../parameterNameAndType/TabReplace2.kt.after | 6 ++++ .../BasicCompletionHandlerTestGenerated.java | 12 ++++++++ 7 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt create mode 100644 idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt create mode 100644 idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt.after diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt index 0ed45d99128..8c9d41e0b95 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt @@ -108,9 +108,9 @@ class KotlinCompletionContributor : CompletionContributor() { ?: DEFAULT_DUMMY_IDENTIFIER } - if (context.completionType == CompletionType.SMART && !isAtEndOfLine(offset, context.editor.document) /* do not use parent expression if we are at the end of line - it's probably parsed incorrectly */) { - val tokenAt = psiFile.findElementAt(Math.max(0, offset)) - if (tokenAt != null) { + val tokenAt = psiFile.findElementAt(Math.max(0, offset)) + if (tokenAt != null) { + if (context.completionType == CompletionType.SMART && !isAtEndOfLine(offset, context.editor.document) /* do not use parent expression if we are at the end of line - it's probably parsed incorrectly */) { var parent = tokenAt.parent if (parent is KtExpression && parent !is KtBlockExpression) { // search expression to be replaced - go up while we are the first child of parent expression @@ -131,11 +131,19 @@ class KotlinCompletionContributor : CompletionContributor() { val argumentList = (expression.parent as? KtValueArgument)?.parent as? KtValueArgumentList if (argumentList != null) { context.offsetMap.addOffset(SmartCompletion.MULTIPLE_ARGUMENTS_REPLACEMENT_OFFSET, - argumentList.rightParenthesis?.textRange?.startOffset ?: argumentList.endOffset) + argumentList.rightParenthesis?.textRange?.startOffset ?: argumentList.endOffset) } } } + + if (tokenAt.node.elementType == KtTokens.IDENTIFIER) { + val parameter = tokenAt.parent as? KtParameter + if (parameter != null) { + context.offsetMap.addOffset(ParameterNameAndTypeCompletion.REPLACEMENT_OFFSET, parameter.endOffset) + } + } } + } private fun replacementOffsetByExpression(expression: KtExpression): Int { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt index 9e8c0d29e13..f203757f452 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt @@ -16,10 +16,7 @@ package org.jetbrains.kotlin.idea.completion -import com.intellij.codeInsight.completion.CompletionInitializationContext -import com.intellij.codeInsight.completion.CompletionParameters -import com.intellij.codeInsight.completion.InsertionContext -import com.intellij.codeInsight.completion.PrefixMatcher +import com.intellij.codeInsight.completion.* import com.intellij.codeInsight.completion.impl.CamelHumpMatcher import com.intellij.codeInsight.lookup.* import com.intellij.openapi.progress.ProgressManager @@ -30,9 +27,12 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager import com.intellij.psi.codeStyle.NameUtil import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.completion.handlers.isCharAt +import org.jetbrains.kotlin.idea.completion.handlers.skipSpaces import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings +import org.jetbrains.kotlin.idea.quickfix.moveCaret import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.getResolutionScope @@ -206,6 +206,22 @@ class ParameterNameAndTypeCompletion( } override fun handleInsert(context: InsertionContext) { + if (context.completionChar == Lookup.REPLACE_SELECT_CHAR) { + val replacementOffset = context.offsetMap.getOffset(REPLACEMENT_OFFSET) + if (replacementOffset != -1) { + val tailOffset = context.tailOffset + context.document.deleteString(tailOffset, replacementOffset) + + val chars = context.document.charsSequence + var offset = chars.skipSpaces(tailOffset) + if (chars.isCharAt(offset, ',')) { + offset++ + offset = chars.skipSpaces(offset) + context.editor.moveCaret(offset) + } + } + } + val settings = CodeStyleSettingsManager.getInstance(context.project).currentSettings.getCustomSettings(KotlinCodeStyleSettings::class.java) val spaceBefore = if (settings.SPACE_BEFORE_TYPE_COLON) " " else "" val spaceAfter = if (settings.SPACE_AFTER_TYPE_COLON) " " else "" @@ -224,8 +240,10 @@ class ParameterNameAndTypeCompletion( override fun hashCode() = parameterName.hashCode() } - private companion object { - val PRIORITY_KEY = Key("ParameterNameAndTypeCompletion.PRIORITY_KEY") + companion object { + private val PRIORITY_KEY = Key("ParameterNameAndTypeCompletion.PRIORITY_KEY") + + val REPLACEMENT_OFFSET = OffsetKey.create("ParameterNameAndTypeCompletion.REPLACEMENT_OFFSET") } object Weigher : LookupElementWeigher("kotlin.parameterNameAndTypePriority") { diff --git a/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt new file mode 100644 index 00000000000..cfdd88fa7e0 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt @@ -0,0 +1,6 @@ +class FooBar + +fun f(bpp: (Int, Char) -> String) + +// ELEMENT_TEXT: bar: FooBar +// CHAR: '\t' diff --git a/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt.after b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt.after new file mode 100644 index 00000000000..1779070faef --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt.after @@ -0,0 +1,6 @@ +class FooBar + +fun f(bar: FooBar) + +// ELEMENT_TEXT: bar: FooBar +// CHAR: '\t' diff --git a/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt new file mode 100644 index 00000000000..1097ed0c9d3 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt @@ -0,0 +1,6 @@ +class FooBar + +fun f(bpp: Int, c: Char) + +// ELEMENT_TEXT: bar: FooBar +// CHAR: '\t' diff --git a/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt.after b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt.after new file mode 100644 index 00000000000..fabc67ab71b --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt.after @@ -0,0 +1,6 @@ +class FooBar + +fun f(bar: FooBar, c: Char) + +// ELEMENT_TEXT: bar: FooBar +// CHAR: '\t' 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 8d1eb6a96de..db3975de936 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 @@ -562,6 +562,18 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion doTest(fileName); } + @TestMetadata("TabReplace1.kt") + public void testTabReplace1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt"); + doTest(fileName); + } + + @TestMetadata("TabReplace2.kt") + public void testTabReplace2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt"); + doTest(fileName); + } + @TestMetadata("TypeParameter.kt") public void testTypeParameter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/parameterNameAndType/TypeParameter.kt");