Skip to content

Commit f0f1214

Browse files
committed
feat(cartographer): add SearchContent/FindFiles FFI + structural perf tests
- Add SearchContent and FindFiles FFI calls with stub implementations - Add structural perf tests split across CGO and non-CGO build tags
1 parent efaec76 commit f0f1214

5 files changed

Lines changed: 534 additions & 0 deletions

File tree

internal/cartographer/bridge.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,62 @@ func UnreferencedSymbols(path string) (*UnreferencedSymbolsResult, error) {
321321
return &result, nil
322322
}
323323

324+
// SearchContent searches for a regex or literal pattern across all non-noise project files.
325+
// opts may be nil to use defaults (case-sensitive, unlimited results, no glob filter).
326+
func SearchContent(path, pattern string, opts *SearchContentOptions) (*SearchResult, error) {
327+
cPath := C.CString(path)
328+
defer C.free(unsafe.Pointer(cPath))
329+
330+
cPattern := C.CString(pattern)
331+
defer C.free(unsafe.Pointer(cPattern))
332+
333+
var cOpts *C.char
334+
if opts != nil {
335+
b, err := json.Marshal(opts)
336+
if err != nil {
337+
return nil, &CartographerError{err.Error()}
338+
}
339+
cOpts = C.CString(string(b))
340+
defer C.free(unsafe.Pointer(cOpts))
341+
}
342+
343+
resp, err := callFFI(func() *C.char {
344+
return C.cartographer_search_content(cPath, cPattern, cOpts)
345+
})
346+
if err != nil {
347+
return nil, err
348+
}
349+
350+
var result SearchResult
351+
if err := json.Unmarshal(resp.Data, &result); err != nil {
352+
return nil, &CartographerError{err.Error()}
353+
}
354+
return &result, nil
355+
}
356+
357+
// FindFiles finds files whose repo-relative path matches a glob pattern.
358+
// limit=0 means unlimited.
359+
func FindFiles(path, pattern string, limit uint32) (*FindResult, error) {
360+
cPath := C.CString(path)
361+
defer C.free(unsafe.Pointer(cPath))
362+
363+
cPattern := C.CString(pattern)
364+
defer C.free(unsafe.Pointer(cPattern))
365+
366+
resp, err := callFFI(func() *C.char {
367+
return C.cartographer_find_files(cPath, cPattern, C.uint(limit))
368+
})
369+
if err != nil {
370+
return nil, err
371+
}
372+
373+
var result FindResult
374+
if err := json.Unmarshal(resp.Data, &result); err != nil {
375+
return nil, &CartographerError{err.Error()}
376+
}
377+
return &result, nil
378+
}
379+
324380
// GetModuleContext returns a single module's skeleton with dependency info.
325381
func GetModuleContext(path, moduleID string, depth uint32) (*ModuleContext, error) {
326382
cPath := C.CString(path)

internal/cartographer/bridge_stub.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ func HiddenCoupling(_ string, _ uint32, _ uint32) ([]CoChangePair, error) { ret
2626
func Semidiff(_, _, _ string) ([]SemidiffFile, error) { return nil, ErrUnavailable }
2727
func RankedSkeleton(_ string, _ []string, _ uint32) (*RankedSkeletonResult, error) { return nil, ErrUnavailable }
2828
func UnreferencedSymbols(_ string) (*UnreferencedSymbolsResult, error) { return nil, ErrUnavailable }
29+
func SearchContent(_, _ string, _ *SearchContentOptions) (*SearchResult, error) { return nil, ErrUnavailable }
30+
func FindFiles(_, _ string, _ uint32) (*FindResult, error) { return nil, ErrUnavailable }

internal/cartographer/types.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,52 @@ type SemidiffFile struct {
178178
Removed []string `json:"removed"`
179179
}
180180

181+
// SearchContentOptions configures a content search request.
182+
type SearchContentOptions struct {
183+
Literal bool `json:"literal,omitempty"`
184+
CaseSensitive *bool `json:"caseSensitive,omitempty"` // default true
185+
ContextLines int `json:"contextLines,omitempty"`
186+
MaxResults int `json:"maxResults,omitempty"`
187+
FileGlob string `json:"fileGlob,omitempty"`
188+
}
189+
190+
// ContextLine is one line of before/after context around a search match.
191+
type ContextLine struct {
192+
LineNumber int `json:"lineNumber"`
193+
Line string `json:"line"`
194+
}
195+
196+
// ContentMatch is one matching line with optional surrounding context.
197+
type ContentMatch struct {
198+
Path string `json:"path"`
199+
LineNumber int `json:"lineNumber"`
200+
Line string `json:"line"`
201+
BeforeContext []ContextLine `json:"beforeContext,omitempty"`
202+
AfterContext []ContextLine `json:"afterContext,omitempty"`
203+
}
204+
205+
// SearchResult is returned by SearchContent.
206+
type SearchResult struct {
207+
Matches []ContentMatch `json:"matches"`
208+
TotalMatches int `json:"totalMatches"`
209+
FilesSearched int `json:"filesSearched"`
210+
Truncated bool `json:"truncated"`
211+
}
212+
213+
// FindFile is one file returned by FindFiles.
214+
type FindFile struct {
215+
Path string `json:"path"`
216+
Language *string `json:"language,omitempty"`
217+
SizeBytes uint64 `json:"sizeBytes"`
218+
}
219+
220+
// FindResult is returned by FindFiles.
221+
type FindResult struct {
222+
Files []FindFile `json:"files"`
223+
TotalMatches int `json:"totalMatches"`
224+
Truncated bool `json:"truncated"`
225+
}
226+
181227
// CartographerError is returned when a Cartographer FFI call fails.
182228
type CartographerError struct {
183229
Message string

0 commit comments

Comments
 (0)