mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[toml] IDEA-288468 Provide completion for values
GitOrigin-RevId: b46aaa32f7f4c93b46d6d8545f0ea41b32dcb3bc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
17b6900b88
commit
679bc3f560
@@ -69,4 +69,26 @@ class TomlCompletionFixture(
|
||||
error("Expected completions that don't contain $variants, but got ${lookups.map { it.render() }}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeSoloCompletion() {
|
||||
val lookups = myFixture.completeBasic()
|
||||
|
||||
if (lookups != null) {
|
||||
if (lookups.size == 1) {
|
||||
// for cases like `frob/*caret*/nicate()`,
|
||||
// completion won't be selected automatically.
|
||||
myFixture.type('\n')
|
||||
return
|
||||
}
|
||||
fun LookupElement.debug(): String = "$lookupString ($psiElement)"
|
||||
error("Expected a single completion, but got ${lookups.size}\n"
|
||||
+ lookups.joinToString("\n") { it.debug() })
|
||||
}
|
||||
}
|
||||
|
||||
fun doSingleCompletion(code: String, after: String) {
|
||||
myFixture.configureByText(defaultFileName, code.trimIndent())
|
||||
executeSoloCompletion()
|
||||
myFixture.checkResult(after.trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -29,4 +29,9 @@ abstract class TomlJsonSchemaCompletionTestBase : TomlJsonSchemaTestBase() {
|
||||
@Language("TOML") code: String,
|
||||
render: LookupElement.() -> String = { lookupString }
|
||||
) = completionFixture.checkNotContainsCompletion(variants, code, render)
|
||||
|
||||
fun doSingleCompletion(
|
||||
@Language("TOML") before: String,
|
||||
@Language("TOML") after: String
|
||||
) = completionFixture.doSingleCompletion(before, after)
|
||||
}
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package org.toml.ide.json
|
||||
|
||||
class TomlJsonSchemaValueCompletionTest : TomlJsonSchemaCompletionTestBase() {
|
||||
fun `test enum variants`() = checkContainsCompletion(setOf("\"2015\"", "\"2018\"", "\"2021\""), """
|
||||
[package]
|
||||
edition = <caret>
|
||||
""")
|
||||
|
||||
fun `test variants inside array table`() = checkContainsCompletion(setOf("\"\""), """
|
||||
[[bin]]
|
||||
name = <caret>
|
||||
""")
|
||||
|
||||
fun `test string literal inside literal variants`() = checkNotContainsCompletion(setOf("\"\""), """
|
||||
[package]
|
||||
name = "<caret>"
|
||||
""")
|
||||
|
||||
fun `test boolean value variants`() = checkContainsCompletion(setOf("true", "false"), """
|
||||
[[bin]]
|
||||
test = <caret>
|
||||
""")
|
||||
|
||||
// TODO: Support value completion in inline tables
|
||||
fun `test variants inside inline table`() {
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
checkContainsCompletion(setOf("\"\""), """
|
||||
package = { name = <caret> }
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test inside inside inline array`() {
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
checkContainsCompletion(setOf("{}"), """
|
||||
bin = [<caret>]
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test variants inside inline array and table`() {
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
checkContainsCompletion(setOf("\"\""), """
|
||||
bin = [{ name = <caret> }]
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test enum string value completion in literal`() = doSingleCompletion("""
|
||||
[package]
|
||||
edition = "21<caret>"
|
||||
""", """
|
||||
[package]
|
||||
edition = "2021<caret>"
|
||||
""")
|
||||
|
||||
fun `test enum string value completion`() = doSingleCompletion("""
|
||||
[package]
|
||||
edition = 21<caret>
|
||||
""", """
|
||||
[package]
|
||||
edition = "2021"<caret>
|
||||
""")
|
||||
|
||||
fun `test array completion`() = doSingleCompletion("""
|
||||
[package]
|
||||
authors = <caret>
|
||||
""", """
|
||||
[package]
|
||||
authors = [<caret>]
|
||||
""")
|
||||
|
||||
fun `test inline table completion`() = doSingleCompletion("""
|
||||
[dependencies]
|
||||
foo = <caret>
|
||||
""", """
|
||||
[dependencies]
|
||||
foo = {<caret>}
|
||||
""")
|
||||
|
||||
fun `test string literal completion`() = doSingleCompletion("""
|
||||
[package]
|
||||
name = <caret>
|
||||
""", """
|
||||
[package]
|
||||
name = "<caret>"
|
||||
""")
|
||||
|
||||
fun `test number enum variants`() = checkContainsCompletion(setOf("1", "2"), """
|
||||
[foo]
|
||||
number-enum = <caret>
|
||||
""")
|
||||
}
|
||||
@@ -39,6 +39,9 @@
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"test": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,6 +99,10 @@
|
||||
},
|
||||
"a": {
|
||||
"type": "integer"
|
||||
},
|
||||
"number-enum": {
|
||||
"type": "number",
|
||||
"enum": [1, 2, 3]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,19 @@ object TomlJsonPsiWalker : JsonLikePsiWalker {
|
||||
val parentKey = parent.header.key ?: break
|
||||
// add table header segments to process all the previous siblings to handle nested array tables cases
|
||||
parentKey.segments.mapTo(tableHeaderSegments) { it.name }
|
||||
|
||||
// TODO: Workaround, should be fixed in TOML grammar
|
||||
// if it is a request from inspections, it walks only properties,
|
||||
// so we don't have path calculation from key or value
|
||||
if (element is TomlKeyValue) {
|
||||
val currentKey = current.key
|
||||
|
||||
for (segment in currentKey.segments.asReversed()) {
|
||||
if (segment != element || forceLastTransition) {
|
||||
position.addPrecedingStep(segment.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
current is TomlValue && parent is TomlArray -> {
|
||||
if (current != element || forceLastTransition) {
|
||||
|
||||
+48
@@ -11,7 +11,9 @@ import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.editor.EditorModificationUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.util.Consumer
|
||||
@@ -24,7 +26,10 @@ import com.jetbrains.jsonSchema.impl.JsonSchemaObject
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaResolver
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaType
|
||||
import org.toml.ide.experiments.TomlExperiments
|
||||
import org.toml.lang.psi.TomlLiteral
|
||||
import org.toml.lang.psi.TomlTableHeader
|
||||
import org.toml.lang.psi.ext.TomlLiteralKind
|
||||
import org.toml.lang.psi.ext.kind
|
||||
|
||||
class TomlJsonSchemaCompletionContributor : CompletionContributor() {
|
||||
override fun fillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet) {
|
||||
@@ -68,6 +73,10 @@ class TomlJsonSchemaCompletionContributor : CompletionContributor() {
|
||||
val schemaProperties = schema.properties
|
||||
addAllPropertyVariants(properties, adapter, schemaProperties, knownNames, originalPosition)
|
||||
}
|
||||
|
||||
if (isName != ThreeState.YES) {
|
||||
suggestValues(schema, isName == ThreeState.NO)
|
||||
}
|
||||
}
|
||||
|
||||
for (variant in variants) {
|
||||
@@ -118,6 +127,45 @@ class TomlJsonSchemaCompletionContributor : CompletionContributor() {
|
||||
variants.add(lookupElement)
|
||||
}
|
||||
|
||||
private val isInsideStringLiteral: Boolean
|
||||
get() = (position.parent as? TomlLiteral)?.kind is TomlLiteralKind.String
|
||||
|
||||
private fun suggestValues(schema: JsonSchemaObject, isSurelyValue: Boolean) {
|
||||
val enumVariants = schema.enum
|
||||
if (enumVariants != null) {
|
||||
for (o in enumVariants) {
|
||||
if (isInsideStringLiteral && o !is String) continue
|
||||
|
||||
val variant = if (isInsideStringLiteral) {
|
||||
StringUtil.unquoteString(o.toString())
|
||||
} else {
|
||||
o.toString()
|
||||
}
|
||||
variants.add(LookupElementBuilder.create(variant))
|
||||
}
|
||||
} else if (isSurelyValue) {
|
||||
variants.addAll(suggestValuesByType(schema.guessType()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun suggestValuesByType(type: JsonSchemaType?): List<LookupElement> = when (type) {
|
||||
JsonSchemaType._object -> listOf(buildPairLookupElement("{}"))
|
||||
JsonSchemaType._array -> listOf(buildPairLookupElement("[]"))
|
||||
JsonSchemaType._string -> if (isInsideStringLiteral) {
|
||||
emptyList()
|
||||
} else {
|
||||
listOf(buildPairLookupElement("\"\""))
|
||||
}
|
||||
JsonSchemaType._boolean -> listOf("true", "false").map { LookupElementBuilder.create(it) }
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
private fun buildPairLookupElement(element: String): LookupElementBuilder =
|
||||
LookupElementBuilder.create(element)
|
||||
.withInsertHandler { context, _ ->
|
||||
EditorModificationUtil.moveCaretRelatively(context.editor, -1)
|
||||
}
|
||||
|
||||
private fun getIconForType(type: JsonSchemaType?) = when (type) {
|
||||
JsonSchemaType._object -> AllIcons.Json.Object
|
||||
JsonSchemaType._array -> AllIcons.Json.Array
|
||||
|
||||
Reference in New Issue
Block a user