feat(memory): GDScript symbol extraction in RepoMapIndexer

Adds 'gd' to SYMBOL_PATTERNS (func/class_name/class/signal/enum at column 0,
optional static prefix). Because INDEXED_EXTENSIONS derives from the pattern
keys, .gd files now also participate in WorkspaceStateProbe fingerprinting,
making fp: state keys content-sensitive for Godot repos.
This commit is contained in:
2026-06-11 14:32:04 +04:00
parent 1976d8ad2b
commit 81a21bfe57
2 changed files with 36 additions and 0 deletions
@@ -82,6 +82,8 @@ class RepoMapIndexer(
"go" to Regex("""(?m)^\s*(?:func\s+(?:\([^)]*\)\s*)?|type\s+)(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
"js" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
"ts" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class|interface|type|enum)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
// GDScript: column-0 declarations only, so indented inner-class members never match.
"gd" to Regex("""(?m)^(?:static\s+)?(?:func|class_name|class|signal|enum)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
)
}
}
@@ -41,6 +41,40 @@ class RepoMapIndexerTest {
assertTrue(entries.first { it.path == "Old.kt" }.symbols.contains("Old"))
}
@Test
fun `extracts GDScript top-level symbols`(@TempDir root: Path) {
root.resolve("player.gd").writeText(
"""
class_name Player
extends CharacterBody2D
signal health_changed(new_health)
enum State { IDLE, RUNNING }
static func create() -> Player:
return Player.new()
func take_damage(amount: int) -> void:
health -= amount
class InnerHelper:
func help():
pass
""".trimIndent(),
)
val entry = RepoMapIndexer().index(root).single()
assertEquals("player.gd", entry.path)
assertTrue(
entry.symbols.containsAll(
listOf("Player", "health_changed", "State", "create", "take_damage", "InnerHelper"),
),
"missing symbols in: ${entry.symbols}",
)
assertFalse(entry.symbols.contains("help"), "indented inner method must not be matched")
}
@Test
fun `empty or missing root yields empty map`(@TempDir root: Path) {
assertTrue(RepoMapIndexer().index(root).isEmpty())