Skip to content

Commit 3792bab

Browse files
author
simuleite
committed
Write Index to UniAST
1 parent 5f3e7a3 commit 3792bab

2 files changed

Lines changed: 96 additions & 88 deletions

File tree

internal/cmd/cli/search_symbol.go

Lines changed: 48 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -128,103 +128,70 @@ abcoder cli search_symbol myrepo "Get*"`,
128128
return fmt.Errorf("repo not found: %s", repoName)
129129
}
130130

131-
// 尝试加载索引
132-
idx, err := loadSymbolIndex(astsDir, repoName, repoFile)
131+
// 读取 JSON 文件
132+
data, err := os.ReadFile(repoFile)
133133
if err != nil {
134-
return fmt.Errorf("failed to load index: %w", err)
134+
return fmt.Errorf("failed to read repo file: %w", err)
135135
}
136136

137-
// 如果索引不存在或过期,需要从 JSON 构建
138-
if idx == nil {
139-
fmt.Fprintf(os.Stderr, "Index not found or outdated, rebuilding...\n")
140-
data, err := os.ReadFile(repoFile)
141-
if err != nil {
142-
return fmt.Errorf("failed to read repo file: %w", err)
143-
}
144-
145-
modsVal, err := sonic.Get(data, "Modules")
146-
if err != nil {
147-
return fmt.Errorf("failed to get modules: %w", err)
148-
}
149-
150-
mods, err := modsVal.Map()
151-
if err != nil {
152-
return fmt.Errorf("failed to parse modules: %w", err)
153-
}
154-
155-
indexData := make(map[string][]NameMatch)
156-
157-
for _, modVal := range mods {
158-
mod, ok := modVal.(map[string]interface{})
159-
if !ok {
160-
continue
161-
}
137+
var results = make(map[string]map[string][]string)
162138

163-
pkgs, ok := mod["Packages"].(map[string]interface{})
164-
if !ok {
165-
continue
139+
// 方式1: 使用 NameToLocations(新增字段,O(1))
140+
nameToLocsVal, err := sonic.Get(data, "NameToLocations")
141+
if err == nil && nameToLocsVal.Exists() {
142+
nameToLocs, err := nameToLocsVal.Map()
143+
if err == nil {
144+
if verbose {
145+
fmt.Fprintf(os.Stderr, "[VERBOSE] using NameToLocations (new)\n")
166146
}
167-
168-
for _, pkgVal := range pkgs {
169-
pkg, ok := pkgVal.(map[string]interface{})
170-
if !ok {
171-
continue
172-
}
173-
174-
// Functions
175-
if fns, ok := pkg["Functions"].(map[string]interface{}); ok {
176-
for _, fnVal := range fns {
177-
fn, ok := fnVal.(map[string]interface{})
178-
if !ok {
179-
continue
147+
for name := range nameToLocs {
148+
if matchName(name, query) {
149+
locVal := nameToLocsVal.Get(name)
150+
filesVal := locVal.Get("Files")
151+
if filesVal.Exists() {
152+
files, _ := filesVal.Array()
153+
for _, f := range files {
154+
fileStr, _ := f.(string)
155+
if results[fileStr] == nil {
156+
results[fileStr] = map[string][]string{
157+
"FUNC": {},
158+
"TYPE": {},
159+
"VAR": {},
160+
}
161+
}
162+
results[fileStr]["FUNC"] = append(results[fileStr]["FUNC"], name)
180163
}
181-
name := fn["Name"].(string)
182-
file := fn["File"].(string)
183-
indexData[name] = append(indexData[name], NameMatch{File: file, Type: "FUNC"})
184-
}
185-
}
186-
187-
// Types
188-
if types, ok := pkg["Types"].(map[string]interface{}); ok {
189-
for _, typeVal := range types {
190-
t, ok := typeVal.(map[string]interface{})
191-
if !ok {
192-
continue
193-
}
194-
name := t["Name"].(string)
195-
file := t["File"].(string)
196-
indexData[name] = append(indexData[name], NameMatch{File: file, Type: "TYPE"})
197164
}
198165
}
166+
}
199167

200-
// Vars
201-
if vars, ok := pkg["Vars"].(map[string]interface{}); ok {
202-
for _, varVal := range vars {
203-
v, ok := varVal.(map[string]interface{})
204-
if !ok {
205-
continue
206-
}
207-
name := v["Name"].(string)
208-
file := v["File"].(string)
209-
indexData[name] = append(indexData[name], NameMatch{File: file, Type: "VAR"})
210-
}
168+
// 如果有结果,直接返回
169+
if len(results) > 0 {
170+
output := SearchResult{
171+
RepoName: repoName,
172+
Query: query,
173+
Results: results,
211174
}
175+
b, _ := json.MarshalIndent(output, "", " ")
176+
fmt.Fprintf(os.Stdout, "%s\n", b)
177+
return nil
212178
}
213179
}
180+
}
214181

215-
// 保存索引
216-
if err := saveSymbolIndex(astsDir, repoName, repoFile, indexData); err != nil {
217-
fmt.Fprintf(os.Stderr, "Warning: failed to save index: %v\n", err)
218-
}
219-
220-
idx = &SymbolIndex{
221-
Mtime: 0, // 临时使用
222-
Data: indexData,
223-
}
182+
// 方式2: 回退到 .idx 文件(旧逻辑)
183+
if verbose {
184+
fmt.Fprintf(os.Stderr, "[VERBOSE] fallback to .idx file\n")
185+
}
186+
idx, err := loadSymbolIndex(astsDir, repoName, repoFile)
187+
if err != nil {
188+
return fmt.Errorf("failed to load index: %w", err)
189+
}
190+
if idx == nil {
191+
return fmt.Errorf("no symbol index found for repo: %s", repoName)
224192
}
225193

226194
// 搜索
227-
results := make(map[string]map[string][]string)
228195
for name, matches := range idx.Data {
229196
if matchName(name, query) {
230197
for _, m := range matches {

internal/cmd/cli/utils.go

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,20 +211,64 @@ func iterSymbolNameFile(data []byte, modPath, pkgPath, category string) ([][]str
211211
return results, nil
212212
}
213213

214-
// findPkgPathByFile 通过 filePath 推导 pkgPath,验证该 pkg 包含该文件
214+
// findPkgPathByFile 通过 filePath 查找 pkgPath
215215
// 返回: modPath, pkgPath
216-
// 特点:只读取 package 的 file 列表验证,不读取完整内容(极致按需)
216+
// 使用 File.ModPath + File.PkgPath 实现 O(1) 查找
217217
func findPkgPathByFile(data []byte, filePath string) (string, string, error) {
218+
if verbose {
219+
fmt.Fprintf(os.Stderr, "[VERBOSE] findPkgPathByFile: filePath=%s\n", filePath)
220+
}
221+
222+
// 1. 遍历 Modules,尝试直接通过 Files[filePath] 找到 File
223+
modsVal, err := sonic.Get(data, "Modules")
224+
if err != nil {
225+
return "", "", err
226+
}
227+
modsIter, err := modsVal.Properties()
228+
if err != nil {
229+
return "", "", err
230+
}
231+
var modPair ast.Pair
232+
233+
for modsIter.Next(&modPair) {
234+
modPath := modPair.Key
235+
236+
// 直接查找 Module.Files[filePath]
237+
fileVal, err := sonic.Get(data, "Modules", modPath, "Files", filePath)
238+
if err != nil || !fileVal.Exists() {
239+
continue
240+
}
241+
242+
// 读取 File.ModPath 和 File.PkgPath(JSON 字段名是大写)
243+
modPathVal, _ := fileVal.Get("ModPath").String()
244+
pkgPathVal, _ := fileVal.Get("PkgPath").String()
245+
246+
if modPathVal != "" && pkgPathVal != "" {
247+
if verbose {
248+
fmt.Fprintf(os.Stderr, "[VERBOSE] HIT via Files: modPath=%s, pkgPath=%s\n", modPathVal, pkgPathVal)
249+
}
250+
return modPathVal, pkgPathVal, nil
251+
}
252+
}
253+
254+
// 2. 回退:使用旧的推导方式(兼容旧数据)
255+
if verbose {
256+
fmt.Fprintf(os.Stderr, "[VERBOSE] fallback to derived path\n")
257+
}
258+
return findPkgPathByFileDerived(data, filePath)
259+
}
260+
261+
// findPkgPathByFileDerived 通过推导查找 pkgPath(旧逻辑,兼容)
262+
func findPkgPathByFileDerived(data []byte, filePath string) (string, string, error) {
218263
derivedPkg := filepath.Dir(filePath)
219264
if derivedPkg == "." {
220265
derivedPkg = ""
221266
}
222267

223268
if verbose {
224-
fmt.Fprintf(os.Stderr, "[VERBOSE] findPkgPathByFile: filePath=%s, derivedPkg=%s\n", filePath, derivedPkg)
269+
fmt.Fprintf(os.Stderr, "[VERBOSE] findPkgPathByFileDerived: filePath=%s, derivedPkg=%s\n", filePath, derivedPkg)
225270
}
226271

227-
// 1. 遍历 mods,尝试直接定位
228272
modsVal, err := sonic.Get(data, "Modules")
229273
if err != nil {
230274
return "", "", err
@@ -238,7 +282,6 @@ func findPkgPathByFile(data []byte, filePath string) (string, string, error) {
238282
for modsIter.Next(&modPair) {
239283
modPath := modPair.Key
240284

241-
// 拼接完整 pkgPath
242285
var fullPkgPath string
243286
if derivedPkg == "" {
244287
fullPkgPath = modPath
@@ -250,7 +293,6 @@ func findPkgPathByFile(data []byte, filePath string) (string, string, error) {
250293
fmt.Fprintf(os.Stderr, "[VERBOSE] trying direct: modPath=%s, fullPkgPath=%s\n", modPath, fullPkgPath)
251294
}
252295

253-
// 检查该 package 是否存在且包含该文件(只读 File 字段验证)
254296
if matched, _ := pkgHasFile(data, modPath, fullPkgPath, filePath, "", "Functions"); matched {
255297
if verbose {
256298
fmt.Fprintf(os.Stderr, "[VERBOSE] HIT via direct: modPath=%s, fullPkgPath=%s\n", modPath, fullPkgPath)
@@ -271,7 +313,6 @@ func findPkgPathByFile(data []byte, filePath string) (string, string, error) {
271313
}
272314
}
273315

274-
// 2. 全量加载:一次性加载 Modules.Packages,建立索引查找
275316
if verbose {
276317
fmt.Fprintf(os.Stderr, "[VERBOSE] fallback to findPkgPathByFileFullLoad\n")
277318
}

0 commit comments

Comments
 (0)