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) {
|
class KotlinPropertyInsertHandler(callType: CallType<*>) : KotlinCallableInsertHandler(callType) {
|
||||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||||
|
val surroundedWithBraces = surroundWithBracesIfInStringTemplate(context)
|
||||||
|
|
||||||
super.handleInsert(context, item)
|
super.handleInsert(context, item)
|
||||||
|
|
||||||
if (context.completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
if (context.completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||||
deleteEmptyParenthesis(context)
|
deleteEmptyParenthesis(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (surroundedWithBraces) {
|
||||||
|
removeRedundantBracesInStringTemplate(context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteEmptyParenthesis(context: InsertionContext) {
|
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.completion.KeywordLookupObject
|
||||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
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.KtPsiFactory
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry
|
||||||
|
|
||||||
fun surroundWithBracesIfInStringTemplate(context: InsertionContext) {
|
fun surroundWithBracesIfInStringTemplate(context: InsertionContext): Boolean {
|
||||||
val startOffset = context.startOffset
|
val startOffset = context.startOffset
|
||||||
val document = context.document
|
val document = context.document
|
||||||
if (startOffset > 0 && document.charsSequence[startOffset - 1] == '$') {
|
if (startOffset > 0 && document.charsSequence[startOffset - 1] == '$') {
|
||||||
@@ -47,6 +50,30 @@ fun surroundWithBracesIfInStringTemplate(context: InsertionContext) {
|
|||||||
val tailOffset = context.tailOffset
|
val tailOffset = context.tailOffset
|
||||||
document.insertString(tailOffset, "}")
|
document.insertString(tailOffset, "}")
|
||||||
context.tailOffset = 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);
|
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")
|
@TestMetadata("NotEmptyPrefix.kt")
|
||||||
public void testNotEmptyPrefix() throws Exception {
|
public void testNotEmptyPrefix() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/NotEmptyPrefix.kt");
|
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");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate/Replace.kt");
|
||||||
doTest(fileName);
|
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")
|
@TestMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall")
|
||||||
|
|||||||
+4
@@ -49,6 +49,10 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
|
|||||||
doTest()
|
doTest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testTopLevelValImportInStringTemplate() {
|
||||||
|
doTest()
|
||||||
|
}
|
||||||
|
|
||||||
fun testNoParenthesisInImports() {
|
fun testNoParenthesisInImports() {
|
||||||
doTest()
|
doTest()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user