Resource Bundles: Enable property key completion in string literals
#KT-6946 Fixed
This commit is contained in:
@@ -23,5 +23,6 @@
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="idea-js" scope="TEST" />
|
||||
<orderEntry type="module" module-name="js.frontend" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="properties" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
+8
@@ -79,6 +79,8 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
||||
|
||||
isInUnclosedSuperQualifier(tokenBefore) -> CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED + ">"
|
||||
|
||||
isInSimpleStringTemplate(tokenBefore) -> CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED
|
||||
|
||||
else -> specialLambdaSignatureDummyIdentifier(tokenBefore)
|
||||
?: specialExtensionReceiverDummyIdentifier(tokenBefore)
|
||||
?: specialInTypeArgsDummyIdentifier(tokenBefore)
|
||||
@@ -242,6 +244,8 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
||||
return
|
||||
}
|
||||
|
||||
if (PropertyKeyCompletion.perform(parameters, result)) return
|
||||
|
||||
try {
|
||||
result.restartCompletionWhenNothingMatches()
|
||||
|
||||
@@ -432,4 +436,8 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
||||
val superToken = ltToken.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment }
|
||||
return superToken?.node?.elementType == JetTokens.SUPER_KEYWORD
|
||||
}
|
||||
|
||||
private fun isInSimpleStringTemplate(tokenBefore: PsiElement?): Boolean {
|
||||
return tokenBefore?.parents?.firstIsInstanceOrNull<JetStringTemplateExpression>()?.isPlain() ?: false
|
||||
}
|
||||
}
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionParameters
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import com.intellij.lang.properties.references.PropertiesCompletionContributor
|
||||
import com.intellij.lang.properties.references.PropertyReference
|
||||
import org.jetbrains.kotlin.psi.JetStringTemplateExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isPlain
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
|
||||
object PropertyKeyCompletion {
|
||||
fun perform(parameters: CompletionParameters, result: CompletionResultSet): Boolean {
|
||||
val template = parameters.position.getStrictParentOfType<JetStringTemplateExpression>() ?: return false
|
||||
if (!template.isPlain()) return false
|
||||
|
||||
val references = template.references
|
||||
val propertyReference = references.firstIsInstanceOrNull<PropertyReference>() ?: return false
|
||||
if (PropertiesCompletionContributor.hasMoreImportantReference(references, propertyReference)) return false
|
||||
|
||||
val startOffset = parameters.offset
|
||||
val offsetInElement = startOffset - template.startOffset
|
||||
val range = propertyReference.rangeInElement
|
||||
if (offsetInElement < range.startOffset) return false
|
||||
|
||||
val prefix = template.text.substring(range.startOffset, offsetInElement)
|
||||
val variants = PropertiesCompletionContributor.getVariants(propertyReference)
|
||||
result.withPrefixMatcher(prefix).addAllElements(variants.toList())
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.annotations
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||
public annotation class PropertyKey(public val resourceBundle: String)
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
fun message(@PropertyKey(resourceBundle = "PropertyKeysEmptyString") key: String) = key
|
||||
|
||||
fun test() {
|
||||
message("<caret>")
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "1", typeText: "PropertyKeysEmptyString" }
|
||||
// EXIST: { lookupString: "bar.baz", itemText: "bar.baz", tailText: "2", typeText: "PropertyKeysEmptyString" }
|
||||
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "3", typeText: "PropertyKeysEmptyString" }
|
||||
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "4", typeText: "PropertyKeysEmptyString" }
|
||||
// NOTHING_ELSE
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
foo.bar = 1
|
||||
bar.baz = 2
|
||||
foo.bar.baz = 3
|
||||
foo.test = 4
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.annotations
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||
public annotation class PropertyKey(public val resourceBundle: String)
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
fun message(@PropertyKey(resourceBundle = "PropertyKeysNoPrefix") key: String) = key
|
||||
|
||||
fun test() {
|
||||
message("<caret>foo")
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "1", typeText: "PropertyKeysNoPrefix" }
|
||||
// EXIST: { lookupString: "bar.baz", itemText: "bar.baz", tailText: "2", typeText: "PropertyKeysNoPrefix" }
|
||||
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "3", typeText: "PropertyKeysNoPrefix" }
|
||||
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "4", typeText: "PropertyKeysNoPrefix" }
|
||||
// NOTHING_ELSE
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
foo.bar = 1
|
||||
bar.baz = 2
|
||||
foo.bar.baz = 3
|
||||
foo.test = 4
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.annotations
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||
public annotation class PropertyKey(public val resourceBundle: String)
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
fun message(@PropertyKey(resourceBundle = "PropertyKeysWithPrefix") key: String) = key
|
||||
|
||||
fun test() {
|
||||
message("foo.<caret>")
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "1", typeText: "PropertyKeysWithPrefix" }
|
||||
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "3", typeText: "PropertyKeysWithPrefix" }
|
||||
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "4", typeText: "PropertyKeysWithPrefix" }
|
||||
// NOTHING_ELSE
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
foo.bar = 1
|
||||
bar.baz = 2
|
||||
foo.bar.baz = 3
|
||||
foo.test = 4
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
fun message(@PropertyKey(resourceBundle = "TestBundle") key: String) = key
|
||||
|
||||
fun test() {
|
||||
message("foo.<caret>b")
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.annotations
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||
public annotation class PropertyKey(public val resourceBundle: String)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
fun message(@PropertyKey(resourceBundle = "TestBundle") key: String) = key
|
||||
|
||||
fun test() {
|
||||
message("foo.barb")
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
fun message(@PropertyKey(resourceBundle = "TestBundle") key: String) = key
|
||||
|
||||
fun test() {
|
||||
message("foo.<caret>b")
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.annotations
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||
public annotation class PropertyKey(public val resourceBundle: String)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
fun message(@PropertyKey(resourceBundle = "TestBundle") key: String) = key
|
||||
|
||||
fun test() {
|
||||
message("foo.bar")
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
foo.bar = 1
|
||||
bar.baz = 2
|
||||
+18
@@ -293,6 +293,24 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyKeysEmptyString")
|
||||
public void testPropertyKeysEmptyString() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PropertyKeysEmptyString/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyKeysNoPrefix")
|
||||
public void testPropertyKeysNoPrefix() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PropertyKeysNoPrefix/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyKeysWithPrefix")
|
||||
public void testPropertyKeysWithPrefix() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PropertyKeysWithPrefix/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SyntheticExtensionForGenericClass")
|
||||
public void testSyntheticExtensionForGenericClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/SyntheticExtensionForGenericClass/");
|
||||
|
||||
+10
-1
@@ -77,9 +77,18 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
|
||||
doTest('!')
|
||||
}
|
||||
|
||||
fun doTest(completionChar: Char = '\n') {
|
||||
fun testPropertyKeysWithPrefixEnter() {
|
||||
doTest('\n', "TestBundle.properties")
|
||||
}
|
||||
|
||||
fun testPropertyKeysWithPrefixTab() {
|
||||
doTest('\t', "TestBundle.properties")
|
||||
}
|
||||
|
||||
fun doTest(completionChar: Char = '\n', vararg extraFileNames: String) {
|
||||
val fileName = getTestName(false)
|
||||
|
||||
configureByFiles(null, *extraFileNames)
|
||||
configureByFiles(null, fileName + "-1.kt", fileName + "-2.kt")
|
||||
complete(2)
|
||||
if (myItems != null) {
|
||||
|
||||
Reference in New Issue
Block a user