MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / search_content

Function search_content

atomic-repository/src/content_search.rs:59–128  ·  view source on GitHub ↗

Search the content index. Returns matching lines with file paths, line numbers, and content. Supports path filtering, file type filtering, and case-insensitive search. Results are ranked: source files (`src/`, `lib/`, `pkg/`, `internal/`) are prioritized over config, test, build, and generated files. Within each tier, results preserve filesystem order from the index. The returned [`ContentSearc

(
    repo_root: &Path,
    pattern: &str,
    opts: ContentSearchOptions,
)

Source from the content-addressed store, hash-verified

57/// (capped to `max_results`) and the `total_matches` count so callers
58/// know how many were found before truncation.
59pub fn search_content(
60 repo_root: &Path,
61 pattern: &str,
62 opts: ContentSearchOptions,
63) -> Result<ContentSearchResult, ContentSearchError> {
64 let config = content_config(repo_root);
65 let index = Index::open(config)?;
66
67 let display_limit = opts.max_results.unwrap_or(50);
68
69 // Fetch a large candidate set so we can rank before truncating.
70 // We ask for 10x the display limit (capped at 2000) to get good
71 // coverage across the repo before applying our own ranking.
72 let fetch_limit = (display_limit * 10).min(2000);
73
74 let search_opts = SearchOptions {
75 path_filter: opts.path_filter,
76 file_type: opts.file_type,
77 exclude_type: opts.exclude_type,
78 max_results: Some(fetch_limit),
79 case_insensitive: opts.case_insensitive,
80 };
81
82 let raw_matches = index.search(pattern, &search_opts)?;
83 let total_matches = raw_matches.len();
84
85 // Build per-directory match counts for the facets summary.
86 let mut dir_counts: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
87 for m in &raw_matches {
88 let path_str = m.path.to_string_lossy();
89 // Use the first two path components as the directory bucket.
90 let dir = path_str
91 .splitn(3, '/')
92 .take(2)
93 .collect::<Vec<_>>()
94 .join("/");
95 *dir_counts.entry(dir).or_insert(0) += 1;
96 }
97
98 // Sort directory facets by count (descending).
99 let mut dir_facets: Vec<(String, usize)> = dir_counts.into_iter().collect();
100 dir_facets.sort_by_key(|entry| std::cmp::Reverse(entry.1));
101 dir_facets.truncate(10); // top 10 directories
102
103 // Rank matches: source code files first, then everything else.
104 let mut ranked: Vec<(usize, &syntext::SearchMatch)> = raw_matches
105 .iter()
106 .map(|m| (path_tier(m.path.to_string_lossy().as_ref()), m))
107 .collect();
108 ranked.sort_by_key(|(tier, _)| *tier);
109
110 let matches: Vec<ContentMatch> = ranked
111 .into_iter()
112 .take(display_limit)
113 .map(|(_, m)| ContentMatch {
114 path: m.path.to_string_lossy().to_string(),
115 line_number: m.line_number,
116 line_content: String::from_utf8_lossy(&m.line_content).to_string(),

Callers 3

runMethod · 0.85
vault_kg_searchMethod · 0.85
exec_code_searchMethod · 0.85

Calls 7

content_configFunction · 0.85
truncateMethod · 0.80
as_refMethod · 0.80
path_tierFunction · 0.70
lenMethod · 0.45
into_iterMethod · 0.45
iterMethod · 0.45

Tested by

no test coverage detected