KT-13047 Autocomplete inserts a fully-qualified variable name inside a String
KT-12083 String interpolation -- auto {} if there is a letter after cursor
#KT-13047 Fixed
#KT-12083 Fixed
This commit is contained in:
+6
@@ -24,11 +24,17 @@ import org.jetbrains.kotlin.idea.util.CallType
|
||||
|
||||
class KotlinPropertyInsertHandler(callType: CallType<*>) : KotlinCallableInsertHandler(callType) {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
val surroundedWithBraces = surroundWithBracesIfInStringTemplate(context)
|
||||
|
||||
super.handleInsert(context, item)
|
||||
|
||||
if (context.completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||
deleteEmptyParenthesis(context)
|
||||
}
|
||||
|
||||
if (surroundedWithBraces) {
|
||||
removeRedundantBracesInStringTemplate(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteEmptyParenthesis(context: InsertionContext) {
|
||||
|
||||
+28
-1
@@ -29,9 +29,12 @@ import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import org.jetbrains.kotlin.idea.completion.KeywordLookupObject
|
||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtBlockStringTemplateEntry
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry
|
||||
|
||||
fun surroundWithBracesIfInStringTemplate(context: InsertionContext) {
|
||||
fun surroundWithBracesIfInStringTemplate(context: InsertionContext): Boolean {
|
||||
val startOffset = context.startOffset
|
||||
val document = context.document
|
||||
if (startOffset > 0 && document.charsSequence[startOffset - 1] == '$') {
|
||||
@@ -47,6 +50,30 @@ fun surroundWithBracesIfInStringTemplate(context: InsertionContext) {
|
||||
val tailOffset = context.tailOffset
|
||||
document.insertString(tailOffset, "}")
|
||||
context.tailOffset = tailOffset
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun removeRedundantBracesInStringTemplate(context: InsertionContext) {
|
||||
val document = context.document
|
||||
val tailOffset = context.tailOffset
|
||||
if (document.charsSequence[tailOffset] == '}') {
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
|
||||
val token = context.file.findElementAt(tailOffset)
|
||||
if (token != null && token.node.elementType == KtTokens.LONG_TEMPLATE_ENTRY_END) {
|
||||
val entry = token.parent as KtBlockStringTemplateEntry
|
||||
val nameExpression = entry.expression as? KtNameReferenceExpression ?: return
|
||||
if (canPlaceAfterSimpleNameEntry(entry.nextSibling)) {
|
||||
context.tailOffset++ // place after '}' otherwise it gets invalidated
|
||||
val name = nameExpression.getReferencedName()
|
||||
val newEntry = KtPsiFactory(entry).createSimpleNameStringTemplateEntry(name)
|
||||
entry.replace(newEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package p
|
||||
|
||||
val vvv = 1
|
||||
|
||||
fun foo() {
|
||||
val s = "$<caret>"
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package p
|
||||
|
||||
val vvv = 1
|
||||
|
||||
fun foo() {
|
||||
val s = "$vvv<caret>"
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package p
|
||||
|
||||
val vvv = 1
|
||||
|
||||
fun foo() {
|
||||
val s = "${<caret>}"
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package p
|
||||
|
||||
val vvv = 1
|
||||
|
||||
fun foo() {
|
||||
val s = "${vvv}"
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package p
|
||||
|
||||
val vvv = 1
|
||||
|
||||
fun foo() {
|
||||
val s = "$<caret>word"
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package p
|
||||
|
||||
val vvv = 1
|
||||
|
||||
fun foo() {
|
||||
val s = "${vvv<caret>}word"
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
@@ -0,0 +1,14 @@
|
||||
package p
|
||||
|
||||
object OOO {
|
||||
val vvv = 1
|
||||
}
|
||||
|
||||
class C {
|
||||
fun foo() {
|
||||
"$v<caret>"
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
// INVOCATION_COUNT: 2
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package p
|
||||
|
||||
object OOO {
|
||||
val vvv = 1
|
||||
}
|
||||
|
||||
class C {
|
||||
fun foo() {
|
||||
"${OOO.vvv}"
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: vvv
|
||||
// INVOCATION_COUNT: 2
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package some
|
||||
|
||||
fun other() {
|
||||
val v = "$somePr<caret>"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package other
|
||||
|
||||
val someProp: Int = 1
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package some
|
||||
|
||||
import other.someProp
|
||||
|
||||
fun other() {
|
||||
val v = "$someProp<caret>"
|
||||
}
|
||||
+24
@@ -709,6 +709,24 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/stringTemplate"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("GlobalVal.kt")
|
||||
public void testGlobalVal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/GlobalVal.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("GlobalValInCurlyBraces.kt")
|
||||
public void testGlobalValInCurlyBraces() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/GlobalValInCurlyBraces.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InsertCurlyBracesBeforeLetter.kt")
|
||||
public void testInsertCurlyBracesBeforeLetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/InsertCurlyBracesBeforeLetter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NotEmptyPrefix.kt")
|
||||
public void testNotEmptyPrefix() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/NotEmptyPrefix.kt");
|
||||
@@ -720,6 +738,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/Replace.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ValInObject.kt")
|
||||
public void testValInObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/ValInObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall")
|
||||
|
||||
+4
@@ -49,6 +49,10 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testTopLevelValImportInStringTemplate() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testNoParenthesisInImports() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user