Search 在 memoryPath 下执行全文搜索 默认使用大小写不敏感的字面量匹配,可选正则模式
(ctx context.Context, opts *SearchOptions)
| 169 | // Search 在 memoryPath 下执行全文搜索 |
| 170 | // 默认使用大小写不敏感的字面量匹配,可选正则模式 |
| 171 | func (m *Manager) Search(ctx context.Context, opts *SearchOptions) ([]SearchMatch, error) { |
| 172 | if opts == nil { |
| 173 | return nil, errors.New("memory.Search: options cannot be nil") |
| 174 | } |
| 175 | rawQuery := strings.TrimSpace(opts.Query) |
| 176 | if rawQuery == "" { |
| 177 | return nil, errors.New("memory.Search: query cannot be empty") |
| 178 | } |
| 179 | |
| 180 | var pattern string |
| 181 | if opts.Regex { |
| 182 | pattern = rawQuery |
| 183 | } else { |
| 184 | // 使用大小写不敏感的字面量匹配 |
| 185 | pattern = "(?i)" + regexp.QuoteMeta(rawQuery) |
| 186 | } |
| 187 | |
| 188 | // 根据命名空间选择搜索根路径 |
| 189 | searchPath := m.memoryPath |
| 190 | if ns := strings.TrimSpace(opts.Namespace); ns != "" { |
| 191 | // Namespace 也通过 resolvePath 规范化,确保不会逃出 memoryPath |
| 192 | searchPath = m.resolvePath(ns) |
| 193 | } |
| 194 | |
| 195 | matches, err := m.backend.GrepRaw(ctx, pattern, searchPath, opts.Glob) |
| 196 | if err != nil { |
| 197 | return nil, fmt.Errorf("memory.Search: grep failed: %w", err) |
| 198 | } |
| 199 | |
| 200 | maxResults := opts.MaxResults |
| 201 | if maxResults > 0 && len(matches) > maxResults { |
| 202 | matches = matches[:maxResults] |
| 203 | } |
| 204 | |
| 205 | results := make([]SearchMatch, 0, len(matches)) |
| 206 | for _, m := range matches { |
| 207 | results = append(results, SearchMatch{ |
| 208 | Path: m.Path, |
| 209 | LineNumber: m.LineNumber, |
| 210 | Line: m.Line, |
| 211 | Match: m.Match, |
| 212 | }) |
| 213 | } |
| 214 | |
| 215 | return results, nil |
| 216 | } |
| 217 | |
| 218 | // normalizeDir 规范化目录路径为 "/xxx/" 形式 |
| 219 | func normalizeDir(path string) string { |
nothing calls this directly
no test coverage detected