Smart completion inserts closing parenthesis as well

This commit is contained in:
Valentin Kipyatkov
2014-04-10 18:47:01 +04:00
parent f984dbc5b6
commit 5d8c5cfa31
12 changed files with 61 additions and 20 deletions
@@ -40,6 +40,7 @@ trait SmartCompletionData{
enum class Tail { enum class Tail {
COMMA COMMA
PARENTHESIS
} }
data class ExpectedTypeInfo(val `type`: JetType, val tail: Tail?) data class ExpectedTypeInfo(val `type`: JetType, val tail: Tail?)
@@ -175,7 +176,7 @@ private fun calcArgumentExpectedTypes(expressionWithType: JetExpression, binding
val parameters = candidate.getResultingDescriptor().getValueParameters() val parameters = candidate.getResultingDescriptor().getValueParameters()
if (parameters.size <= argumentIndex) continue if (parameters.size <= argumentIndex) continue
val parameterDescriptor = parameters[argumentIndex] val parameterDescriptor = parameters[argumentIndex]
val tail = if (argumentIndex == parameters.size - 1) null else Tail.COMMA val tail = if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA
expectedTypes.add(ExpectedTypeInfo(parameterDescriptor.getType(), tail)) expectedTypes.add(ExpectedTypeInfo(parameterDescriptor.getType(), tail))
} }
return expectedTypes return expectedTypes
@@ -493,11 +494,15 @@ private fun decorateLookupElement(lookupElement: LookupElement, tail: Tail?): Lo
Tail.COMMA -> object: LookupElementDecorator<LookupElement>(lookupElement) { Tail.COMMA -> object: LookupElementDecorator<LookupElement>(lookupElement) {
override fun handleInsert(context: InsertionContext) { override fun handleInsert(context: InsertionContext) {
WithCommaInsertHandler.handleInsert(context, lookupElement) WithTailInsertHandler(',', true /*TODO: use code style option*/).handleInsert(context, lookupElement)
} }
} }
else -> throw RuntimeException("Unknown tail type") Tail.PARENTHESIS -> object: LookupElementDecorator<LookupElement>(lookupElement) {
override fun handleInsert(context: InsertionContext) {
WithTailInsertHandler(')', false).handleInsert(context, lookupElement)
}
}
} }
} }
@@ -5,8 +5,9 @@ import com.intellij.codeInsight.completion.*
import com.intellij.openapi.editor.event.DocumentListener import com.intellij.openapi.editor.event.DocumentListener
import com.intellij.openapi.editor.event.DocumentEvent import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiDocumentManager
object WithCommaInsertHandler : InsertHandler<LookupElement> { class WithTailInsertHandler(val tailChar: Char, val spaceAfter: Boolean) : InsertHandler<LookupElement> {
override fun handleInsert(context: InsertionContext, item: LookupElement) { override fun handleInsert(context: InsertionContext, item: LookupElement) {
val document = context.getDocument() val document = context.getDocument()
val caretModel = context.getEditor().getCaretModel() val caretModel = context.getEditor().getCaretModel()
@@ -28,20 +29,23 @@ object WithCommaInsertHandler : InsertHandler<LookupElement> {
} }
document.addDocumentListener(documentListener) document.addDocumentListener(documentListener)
item.handleInsert(context) item.handleInsert(context)
PsiDocumentManager.getInstance(context.getProject()).doPostponedOperationsAndUnblockDocument(document)
document.removeDocumentListener(documentListener) document.removeDocumentListener(documentListener)
val moveCaret = caretModel.getOffset() == maxChangeOffset val moveCaret = caretModel.getOffset() == maxChangeOffset
if (maxChangeOffset < document.getTextLength() && document.getText(TextRange(maxChangeOffset, maxChangeOffset + 1)) == ",") { if (maxChangeOffset < document.getTextLength() && document.getText(TextRange(maxChangeOffset, maxChangeOffset + 1))[0] == tailChar) {
document.deleteString(maxChangeOffset, maxChangeOffset + 1) document.deleteString(maxChangeOffset, maxChangeOffset + 1)
if (maxChangeOffset < document.getTextLength() && document.getText(TextRange(maxChangeOffset, maxChangeOffset + 1)) == " ") { if (spaceAfter && maxChangeOffset < document.getTextLength() && document.getText(TextRange(maxChangeOffset, maxChangeOffset + 1)) == " ") {
document.deleteString(maxChangeOffset, maxChangeOffset + 1) document.deleteString(maxChangeOffset, maxChangeOffset + 1)
} }
} }
val textToInsert = ", " //TODO: code style option val textToInsert = if (spaceAfter) tailChar + " " else tailChar.toString()
document.insertString(maxChangeOffset, textToInsert) document.insertString(maxChangeOffset, textToInsert)
if (moveCaret) { if (moveCaret) {
caretModel.moveToOffset(maxChangeOffset + textToInsert.length) caretModel.moveToOffset(maxChangeOffset + textToInsert.length)
@@ -0,0 +1,7 @@
fun foo(s: String){ }
fun bar(sss: String) {
foo(<caret>
}
//ELEMENT: sss
@@ -0,0 +1,7 @@
fun foo(s: String){ }
fun bar(sss: String) {
foo(sss)<caret>
}
//ELEMENT: sss
@@ -0,0 +1,7 @@
fun foo(s: String){ }
fun bar(sss: String) {
foo(<caret>)
}
//ELEMENT: sss
@@ -0,0 +1,7 @@
fun foo(s: String){ }
fun bar(sss: String) {
foo(sss)<caret>
}
//ELEMENT: sss
@@ -1,7 +1,7 @@
fun foo(s: String){ } fun foo(s: String){ }
fun bar(sss: String) { fun bar(sss: String) {
foo(sss<caret>) foo(sss)<caret>
} }
//ELEMENT: sss //ELEMENT: sss
@@ -1,7 +1,7 @@
fun foo(s: String){ } fun foo(s: String){ }
fun bar(sss: String) { fun bar(sss: String) {
foo(sss<caret>) foo(sss)<caret>
} }
//ELEMENT: sss //ELEMENT: sss
@@ -1,7 +1,7 @@
fun foo(s: String){ } fun foo(s: String){ }
fun bar(sss: String) { fun bar(sss: String) {
foo(sss<caret>) foo(sss)<caret>
} }
//ELEMENT: sss //ELEMENT: sss
@@ -1,7 +1,7 @@
fun foo(s: String){ } fun foo(s: String){ }
fun bar(sss: String) { fun bar(sss: String) {
foo(sss<caret>) foo(sss)<caret>
} }
//ELEMENT: sss //ELEMENT: sss
@@ -1,7 +1,7 @@
fun foo(s: String){ } fun foo(s: String){ }
fun bar(ss: String) { fun bar(ss: String) {
foo(ss<caret>) foo(ss)<caret>
} }
//ELEMENT: ss //ELEMENT: ss
@@ -16,17 +16,11 @@
package org.jetbrains.jet.completion.handlers; package org.jetbrains.jet.completion.handlers;
import junit.framework.Assert; import org.jetbrains.jet.JetTestUtils;
import junit.framework.Test; import org.jetbrains.jet.test.TestMetadata;
import junit.framework.TestSuite;
import java.io.File; import java.io.File;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.jetbrains.jet.completion.handlers.AbstractSmartCompletionHandlerTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -66,6 +60,16 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest("idea/testData/completion/handlers/smart/ClassObjectMethod2.kt"); doTest("idea/testData/completion/handlers/smart/ClassObjectMethod2.kt");
} }
@TestMetadata("ClosingParenthesis1.kt")
public void testClosingParenthesis1() throws Exception {
doTest("idea/testData/completion/handlers/smart/ClosingParenthesis1.kt");
}
@TestMetadata("ClosingParenthesis2.kt")
public void testClosingParenthesis2() throws Exception {
doTest("idea/testData/completion/handlers/smart/ClosingParenthesis2.kt");
}
@TestMetadata("Comma1.kt") @TestMetadata("Comma1.kt")
public void testComma1() throws Exception { public void testComma1() throws Exception {
doTest("idea/testData/completion/handlers/smart/Comma1.kt"); doTest("idea/testData/completion/handlers/smart/Comma1.kt");