KT-7731 Completion: replacement of call with no parameters with property by Tab
#KT-7731 Fixed
This commit is contained in:
+4
-4
@@ -95,8 +95,8 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
// search expression to be replaced - go up while we are the first child of parent expression
|
// search expression to be replaced - go up while we are the first child of parent expression
|
||||||
var expression = parent as JetExpression
|
var expression = parent as JetExpression
|
||||||
parent = expression.getParent()
|
parent = expression.getParent()
|
||||||
while (parent is JetExpression && parent!!.getFirstChild() == expression) {
|
while (parent is JetExpression && parent.getFirstChild() == expression) {
|
||||||
expression = parent as JetExpression
|
expression = parent
|
||||||
parent = expression.getParent()
|
parent = expression.getParent()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
val text = builder.toString()
|
val text = builder.toString()
|
||||||
val file = JetPsiFactory(tokenBefore.getProject()).createFile(text)
|
val file = JetPsiFactory(tokenBefore.getProject()).createFile(text)
|
||||||
val declaration = file.getDeclarations().singleOrNull() ?: return null
|
val declaration = file.getDeclarations().singleOrNull() ?: return null
|
||||||
if (declaration.getTextLength() != text.length) return null
|
if (declaration.getTextLength() != text.length()) return null
|
||||||
val containsErrorElement = !PsiTreeUtil.processElements(file, PsiElementProcessor<PsiElement>{ it !is PsiErrorElement })
|
val containsErrorElement = !PsiTreeUtil.processElements(file, PsiElementProcessor<PsiElement>{ it !is PsiErrorElement })
|
||||||
return if (containsErrorElement) null else tail + "$"
|
return if (containsErrorElement) null else tail + "$"
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,7 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
JetTokens.LPAR -> balance++
|
JetTokens.LPAR -> balance++
|
||||||
JetTokens.RPAR -> balance--
|
JetTokens.RPAR -> balance--
|
||||||
}
|
}
|
||||||
current = current!!.prevLeaf()
|
current = current.prevLeaf()
|
||||||
}
|
}
|
||||||
return balance
|
return balance
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-33
@@ -20,7 +20,6 @@ import com.intellij.codeInsight.AutoPopupController
|
|||||||
import com.intellij.codeInsight.completion.InsertionContext
|
import com.intellij.codeInsight.completion.InsertionContext
|
||||||
import com.intellij.codeInsight.lookup.Lookup
|
import com.intellij.codeInsight.lookup.Lookup
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.openapi.editor.Document
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
@@ -52,11 +51,6 @@ public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler
|
|||||||
private fun addImport(context : InsertionContext, item : LookupElement) {
|
private fun addImport(context : InsertionContext, item : LookupElement) {
|
||||||
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
|
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
|
||||||
|
|
||||||
val startOffset = context.getStartOffset()
|
|
||||||
val element = context.getFile().findElementAt(startOffset)
|
|
||||||
|
|
||||||
if (element == null) return
|
|
||||||
|
|
||||||
val file = context.getFile()
|
val file = context.getFile()
|
||||||
val o = item.getObject()
|
val o = item.getObject()
|
||||||
if (file is JetFile && o is DeclarationDescriptorLookupObject) {
|
if (file is JetFile && o is DeclarationDescriptorLookupObject) {
|
||||||
@@ -77,7 +71,30 @@ public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object KotlinPropertyInsertHandler : KotlinCallableInsertHandler()
|
public object KotlinPropertyInsertHandler : KotlinCallableInsertHandler() {
|
||||||
|
public override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||||
|
super.handleInsert(context, item)
|
||||||
|
|
||||||
|
if (context.getCompletionChar() == Lookup.REPLACE_SELECT_CHAR) {
|
||||||
|
deleteEmptyParenthesis(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteEmptyParenthesis(context: InsertionContext) {
|
||||||
|
val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject())
|
||||||
|
psiDocumentManager.commitAllDocuments()
|
||||||
|
psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument())
|
||||||
|
|
||||||
|
val offset = context.getTailOffset()
|
||||||
|
val document = context.getDocument()
|
||||||
|
val chars = document.getCharsSequence()
|
||||||
|
|
||||||
|
val lParenOffset = chars.indexOfSkippingSpace('(', offset) ?: return
|
||||||
|
val rParenOffset = chars.indexOfSkippingSpace(')', lParenOffset + 1) ?: return
|
||||||
|
|
||||||
|
document.deleteString(offset, rParenOffset + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum class CaretPosition {
|
public enum class CaretPosition {
|
||||||
IN_BRACKETS
|
IN_BRACKETS
|
||||||
@@ -143,8 +160,8 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val
|
|||||||
val closingBracket = if (braces) '}' else ')'
|
val closingBracket = if (braces) '}' else ')'
|
||||||
|
|
||||||
if (completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
if (completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||||
val offset1 = skipSpaces(chars, offset)
|
val offset1 = chars.skipSpaces(offset)
|
||||||
if (offset1 < document.getTextLength()) {
|
if (offset1 < chars.length()) {
|
||||||
if (chars[offset1] == '<') {
|
if (chars[offset1] == '<') {
|
||||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
||||||
val token = context.getFile().findElementAt(offset1)!!
|
val token = context.getFile().findElementAt(offset1)!!
|
||||||
@@ -158,9 +175,9 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var openingBracketOffset = indexOfSkippingSpace(document, openingBracket, offset)
|
var openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset)
|
||||||
var inBracketsShift = 0
|
var inBracketsShift = 0
|
||||||
if (openingBracketOffset == -1) {
|
if (openingBracketOffset == null) {
|
||||||
if (braces) {
|
if (braces) {
|
||||||
if (completionChar == ' ' || completionChar == '{') {
|
if (completionChar == ' ' || completionChar == '{') {
|
||||||
context.setAddCompletionChar(false)
|
context.setAddCompletionChar(false)
|
||||||
@@ -180,13 +197,12 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val
|
|||||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
||||||
}
|
}
|
||||||
|
|
||||||
openingBracketOffset = indexOfSkippingSpace(document, openingBracket, offset)
|
openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset)!!
|
||||||
assert(openingBracketOffset != -1, "If there wasn't open bracket it should already have been inserted")
|
|
||||||
|
val closeBracketOffset = chars.indexOfSkippingSpace(closingBracket, openingBracketOffset + 1)
|
||||||
|
|
||||||
val closeBracketOffset = indexOfSkippingSpace(document, closingBracket, openingBracketOffset + 1)
|
|
||||||
val editor = context.getEditor()
|
val editor = context.getEditor()
|
||||||
|
if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) {
|
||||||
if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == -1) {
|
|
||||||
editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift)
|
editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift)
|
||||||
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement)
|
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement)
|
||||||
}
|
}
|
||||||
@@ -197,7 +213,7 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val
|
|||||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
||||||
|
|
||||||
if (lambdaInfo != null && lambdaInfo.explicitParameters) {
|
if (lambdaInfo != null && lambdaInfo.explicitParameters) {
|
||||||
insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset + 1), lambdaInfo.lambdaType)
|
insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset!! + 1), lambdaInfo.lambdaType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,22 +227,8 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val
|
|||||||
public val NO_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null)
|
public val NO_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null)
|
||||||
public val WITH_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, null)
|
public val WITH_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, null)
|
||||||
|
|
||||||
private fun indexOfSkippingSpace(document: Document, ch : Char, startIndex : Int) : Int {
|
private fun isInsertSpacesInOneLineFunctionEnabled(project: Project)
|
||||||
val text = document.getCharsSequence()
|
= CodeStyleSettingsManager.getSettings(project).getCustomSettings(javaClass<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
||||||
for (i in startIndex..text.length() - 1) {
|
|
||||||
val currentChar = text[i]
|
|
||||||
if (ch == currentChar) return i
|
|
||||||
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<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
fun CharSequence.indexOfSkippingSpace(c: Char, startIndex: Int): Int? {
|
||||||
|
for (i in startIndex..this.length() - 1) {
|
||||||
|
val currentChar = this[i]
|
||||||
|
if (c == currentChar) return i
|
||||||
|
if (currentChar != ' ' && currentChar != '\t') return null
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CharSequence.skipSpaces(index: Int): Int
|
||||||
|
= (index..length() - 1).firstOrNull { val c = this[it]; c != ' ' && c != '\t' } ?: this.length()
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class C {
|
||||||
|
val bar: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(c: C) {
|
||||||
|
val v = c.<caret>getBar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELEMENT: bar
|
||||||
|
// CHAR: '\t'
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class C {
|
||||||
|
val bar: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(c: C) {
|
||||||
|
val v = c.bar<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELEMENT: bar
|
||||||
|
// CHAR: '\t'
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class C {
|
||||||
|
val bar: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(c: C) {
|
||||||
|
val v = c.<caret>getBar(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELEMENT: bar
|
||||||
|
// CHAR: '\t'
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
class C {
|
||||||
|
val bar: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(c: C) {
|
||||||
|
val v = c.bar<caret>(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELEMENT: bar
|
||||||
|
// CHAR: '\t'
|
||||||
+12
@@ -101,6 +101,18 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ReplaceFunctionCallByProperty.kt")
|
||||||
|
public void testReplaceFunctionCallByProperty() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ReplaceFunctionCallByProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ReplaceFunctionCallByPropertyArgs.kt")
|
||||||
|
public void testReplaceFunctionCallByPropertyArgs() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/ReplaceFunctionCallByPropertyArgs.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("SecondTypeArg.kt")
|
@TestMetadata("SecondTypeArg.kt")
|
||||||
public void testSecondTypeArg() throws Exception {
|
public void testSecondTypeArg() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/SecondTypeArg.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/SecondTypeArg.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user