Files
codex/codex-rs/file-search/src/snapshot.rs
T
Charlie Marsh aeec726de8 Reduce path storage in the file-search index (#55351)
## What changed

Reuse the matcher column for ASCII paths instead of storing a separate full path for every indexed entry. Store the selected search root and entry type alongside each entry so snapshots can build results without resolving the root again.

Retain the original relative path for Unicode entries because matcher columns keep only one code point per grapheme.

GitOrigin-RevId: 1e931482c9a656970e2eeaaade02f19063464f12
2026-10-19 19:10:58 +00:00

76 lines
2.6 KiB
Rust

//! Converts matcher snapshots without associating old results with a new query.
use crate::FileMatch;
use crate::FileSearchSnapshot;
use crate::IndexedEntry;
use crate::SessionInner;
use nucleo::Matcher;
use nucleo::Nucleo;
use nucleo::Utf32String;
use std::path::PathBuf;
pub(super) fn for_query(
inner: &SessionInner,
nucleo: &Nucleo<IndexedEntry>,
query: &str,
indices_matcher: &mut Option<Matcher>,
walk_complete: bool,
) -> Option<FileSearchSnapshot> {
let snapshot = nucleo.snapshot();
let pattern = snapshot.pattern().column_pattern(0);
// A tick can collect the previous query's results while the new query is
// still running. Wait for a matching snapshot before using the new label.
if pattern.atoms != nucleo.pattern.column_pattern(0).atoms {
return None;
}
let limit = inner.limit.min(snapshot.matched_item_count() as usize);
let matches = snapshot
.matches()
.iter()
.take(limit)
.filter_map(|match_| {
let item = snapshot.get_item(match_.idx)?;
let (root_idx, relative_path, match_type) = match item.data {
IndexedEntry::Ascii {
root_idx,
match_type,
} => {
let Utf32String::Ascii(path) = &item.matcher_columns[0] else {
return None;
};
(*root_idx, path.as_ref(), *match_type)
}
IndexedEntry::Unicode(entry) => (
entry.root_idx,
entry.relative_path.as_ref(),
entry.match_type,
),
};
let indices = if let Some(indices_matcher) = indices_matcher.as_mut() {
let mut indices = Vec::<u32>::new();
let haystack = item.matcher_columns[0].slice(..);
let _ = pattern.indices(haystack, indices_matcher, &mut indices);
indices.sort_unstable();
indices.dedup();
Some(indices)
} else {
None
};
Some(FileMatch {
score: match_.score,
path: PathBuf::from(relative_path),
match_type,
root: inner.search_directories[root_idx].clone(),
indices,
})
})
.collect();
Some(FileSearchSnapshot {
query: query.to_string(),
matches,
total_match_count: snapshot.matched_item_count() as usize,
scanned_file_count: snapshot.item_count() as usize,
walk_complete,
})
}