started autocompletion in the plugin
This commit is contained in:
1 parent
678cfbf45e
commit
c35d684df1
15 files changed
+1631
-2
No files matched your search
@@ -0,0 +1,102 @@
|
||||
package net.sergeych.lyng.miniast
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CompletionEngineLightTest {
|
||||
|
||||
private fun names(items: List<CompletionItem>): List<String> = items.map { it.name }
|
||||
|
||||
@Test
|
||||
fun iteratorAfterLines_noGlobals() = runBlocking {
|
||||
TestDocsBootstrap.ensure("lyng.stdlib", "lyng.io.fs")
|
||||
val code = """
|
||||
import lyng.io.fs
|
||||
import lyng.stdlib
|
||||
|
||||
val files = Path("../..").lines().<caret>
|
||||
""".trimIndent()
|
||||
val items = CompletionEngineLight.completeAtMarkerSuspend(code)
|
||||
val ns = names(items)
|
||||
// No globals after a dot
|
||||
assertFalse(ns.contains("Path"), "Should not contain global 'Path' after dot")
|
||||
assertFalse(ns.contains("Array"), "Should not contain global 'Array' after dot")
|
||||
assertFalse(ns.contains("String"), "Should not contain global 'String' after dot")
|
||||
// Should have some iterator members (at least non-empty)
|
||||
assertTrue(ns.isNotEmpty(), "Iterator members should be suggested")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iteratorAfterLines_withPrefix() = runBlocking {
|
||||
TestDocsBootstrap.ensure("lyng.stdlib", "lyng.io.fs")
|
||||
val code = """
|
||||
import lyng.io.fs
|
||||
import lyng.stdlib
|
||||
|
||||
val files = Path("../..").lines().t<caret>
|
||||
""".trimIndent()
|
||||
val items = CompletionEngineLight.completeAtMarkerSuspend(code)
|
||||
val ns = names(items)
|
||||
// No globals after a dot even with prefix
|
||||
assertFalse(ns.contains("Path"))
|
||||
assertFalse(ns.contains("Array"))
|
||||
assertFalse(ns.contains("String"))
|
||||
// All start with 't'
|
||||
assertTrue(ns.all { it.startsWith("t", ignoreCase = true) }, "All suggestions should respect prefix 't'")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun listLiteral_membersAndInherited() = runBlocking {
|
||||
TestDocsBootstrap.ensure("lyng.stdlib")
|
||||
val code = """
|
||||
import lyng.stdlib
|
||||
|
||||
val x = [1,2,3].<caret>
|
||||
""".trimIndent()
|
||||
val items = CompletionEngineLight.completeAtMarkerSuspend(code)
|
||||
val ns = names(items)
|
||||
// No globals after a dot
|
||||
assertFalse(ns.contains("Array"))
|
||||
assertFalse(ns.contains("String"))
|
||||
assertFalse(ns.contains("Path"))
|
||||
// Expect more than a couple of items (not just one)
|
||||
assertTrue(ns.size >= 3, "Too few member suggestions after list literal: $ns")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun stringLiteral_members() = runBlocking {
|
||||
TestDocsBootstrap.ensure("lyng.stdlib")
|
||||
val code = """
|
||||
import lyng.stdlib
|
||||
|
||||
val s = "abc".<caret>
|
||||
""".trimIndent()
|
||||
val items = CompletionEngineLight.completeAtMarkerSuspend(code)
|
||||
val ns = names(items)
|
||||
assertTrue(ns.isNotEmpty(), "String members should be suggested")
|
||||
assertFalse(ns.contains("Path"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shebang_and_fs_import_iterator_after_lines() = runBlocking {
|
||||
TestDocsBootstrap.ensure("lyng.stdlib", "lyng.io.fs")
|
||||
val code = """
|
||||
#!/bin/env lyng
|
||||
|
||||
import lyng.io.fs
|
||||
import lyng.stdlib
|
||||
|
||||
val files = Path("../..").lines().<caret>
|
||||
""".trimIndent()
|
||||
val items = CompletionEngineLight.completeAtMarkerSuspend(code)
|
||||
val ns = names(items)
|
||||
// Should not contain globals after dot
|
||||
assertFalse(ns.contains("Path"))
|
||||
assertFalse(ns.contains("Array"))
|
||||
assertFalse(ns.contains("String"))
|
||||
// Should contain some iterator members
|
||||
assertTrue(ns.isNotEmpty(), "Iterator members should be suggested after lines() with shebang present")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package net.sergeych.lyng.miniast
|
||||
|
||||
/** Ensure docs modules are loaded for tests (stdlib + optional lyngio). */
|
||||
object TestDocsBootstrap {
|
||||
@Volatile private var ensured = false
|
||||
|
||||
fun ensure(vararg modules: String) {
|
||||
if (ensured) return
|
||||
synchronized(this) {
|
||||
if (ensured) return
|
||||
// Touch stdlib to seed lazy docs
|
||||
BuiltinDocRegistry.docsForModule("lyng.stdlib")
|
||||
// Try to load external fs docs registrar reflectively
|
||||
val ok = try {
|
||||
val cls = Class.forName("net.sergeych.lyngio.docs.FsBuiltinDocs")
|
||||
val m = cls.getMethod("ensure")
|
||||
m.invoke(null)
|
||||
true
|
||||
} catch (_: Throwable) { false }
|
||||
if (!ok) {
|
||||
// Minimal fallback for lyng.io.fs (Path with lines(): Iterator<String>)
|
||||
BuiltinDocRegistry.moduleReplace("lyng.io.fs") {
|
||||
classDoc(name = "Path", doc = "Filesystem path class.") {
|
||||
method(name = "lines", doc = "Iterate file as lines of text.", returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.String"))))
|
||||
method(name = "exists", doc = "Whether the path exists.", returns = type("lyng.Bool"))
|
||||
}
|
||||
valDoc(name = "Path", doc = "Path class", type = type("Path"))
|
||||
}
|
||||
}
|
||||
ensured = true
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user