use std::path::Path;
use std::sync::Mutex;
use super::file_metadata;
use crate::error::SrcwalkError;
use crate::search::rank;
use crate::types::{Match, SearchResult};
use grep_regex::RegexMatcher;
use grep_searcher::sinks::UTF8;
use grep_searcher::Searcher;
const MAX_SEARCH_FILE_SIZE: u64 = 500_000;
pub fn search(
pattern: &str,
scope: &Path,
is_regex: bool,
context: Option<&Path>,
glob: Option<&str>,
) -> Result<SearchResult, SrcwalkError> {
let matcher = if is_regex {
RegexMatcher::new(pattern)
} else {
RegexMatcher::new(®ex_syntax::escape(pattern))
}
.map_err(|e| SrcwalkError::InvalidQuery {
query: pattern.to_string(),
reason: e.to_string(),
})?;
let matches: Mutex<Vec<Match>> = Mutex::new(Vec::new());
let walker = super::walker(scope, glob)?;
walker.run(|| {
let matcher = &matcher;
let matches = &matches;
Box::new(move |entry| {
let Ok(entry) = entry else {
return ignore::WalkState::Continue;
};
if !entry.file_type().is_some_and(|ft| ft.is_file()) {
return ignore::WalkState::Continue;
}
let path = entry.path();
if let Ok(meta) = std::fs::metadata(path) {
if meta.len() > MAX_SEARCH_FILE_SIZE {
return ignore::WalkState::Continue;
}
}
let (file_lines, mtime) = file_metadata(path);
let mut file_matches = Vec::new();
let mut searcher = Searcher::new();
let _ = searcher.search_path(
matcher,
path,
UTF8(|line_num, line| {
file_matches.push(Match {
path: path.to_path_buf(),
line: line_num as u32,
text: line.trim_end().to_string(),
is_definition: false,
exact: false,
file_lines,
mtime,
def_range: None,
def_name: None,
def_weight: 0,
impl_target: None,
in_comment: false,
});
Ok(true)
}),
);
if !file_matches.is_empty() {
let mut all = matches
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
all.extend(file_matches);
}
ignore::WalkState::Continue
})
});
let mut all_matches = matches
.into_inner()
.unwrap_or_else(std::sync::PoisonError::into_inner);
rank::sort(&mut all_matches, pattern, scope, context);
let total = all_matches.len();
Ok(SearchResult {
query: pattern.to_string(),
scope: scope.to_path_buf(),
matches: all_matches,
total_found: total,
definitions: 0,
usages: total,
comments: 0,
has_more: false,
offset: 0,
})
}