mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-12 05:12:39 +00:00
address review: report GREP search-budget exhaustion to the overlay warning
This commit is contained in:
1 parent
e8b96e7e02
commit
8ef09e8ed9
2 files changed
+25
-11
No files matched your search
+21
-10
@@ -412,14 +412,24 @@ impl Grep {
|
||||
/// Non-empty matches in `text`, at most `limit` of them: an empty match styles nothing, so it
|
||||
/// doesn't count toward a GREP style's cap. Empty matches still cost a search each, so the
|
||||
/// scan stops after `limit` × [`SEARCHES_PER_MATCH`] searches in all.
|
||||
pub fn find_nonempty(&self, text: &str, limit: usize) -> Result<Vec<Range<usize>>, GrepError> {
|
||||
self.re
|
||||
.find_iter(text)
|
||||
.take(limit.saturating_mul(SEARCHES_PER_MATCH))
|
||||
.filter(|m| !m.as_ref().is_ok_and(|m| m.range().is_empty()))
|
||||
.take(limit)
|
||||
.map(|m| m.map(|m| m.range()).map_err(run_err))
|
||||
.collect()
|
||||
///
|
||||
/// The flag is true when the search budget ran out with text left to scan, so the matches may
|
||||
/// be incomplete (reaching `limit` is not flagged: the caller sees the full vector).
|
||||
pub fn find_nonempty(&self, text: &str, limit: usize) -> Result<(Vec<Range<usize>>, bool), GrepError> {
|
||||
let mut it = self.re.find_iter(text);
|
||||
let mut out = Vec::new();
|
||||
for _ in 0..limit.saturating_mul(SEARCHES_PER_MATCH) {
|
||||
if out.len() >= limit {
|
||||
return Ok((out, false));
|
||||
}
|
||||
let Some(m) = it.next() else { return Ok((out, false)) };
|
||||
let r = m.map_err(run_err)?.range();
|
||||
if !r.is_empty() {
|
||||
out.push(r);
|
||||
}
|
||||
}
|
||||
let more = out.len() < limit && it.next().is_some();
|
||||
Ok((out, more))
|
||||
}
|
||||
|
||||
/// Matches in `text` and their replacements, `template` expanded per match (`$1`…; see
|
||||
@@ -533,9 +543,10 @@ mod tests {
|
||||
// found within the budget and not past it.
|
||||
let g = grep("a*");
|
||||
let near = format!("{}a", "b".repeat(10 * SEARCHES_PER_MATCH - 2));
|
||||
assert_eq!(g.find_nonempty(&near, 10).unwrap().len(), 1);
|
||||
let (ms, exhausted) = g.find_nonempty(&near, 10).unwrap();
|
||||
assert_eq!((ms.len(), ms[0].clone(), exhausted), (1, near.len() - 1..near.len(), false));
|
||||
let far = format!("{}a", "b".repeat(10 * SEARCHES_PER_MATCH + 50));
|
||||
assert!(g.find_nonempty(&far, 10).unwrap().is_empty(), "the scan stops at the search budget");
|
||||
assert_eq!(g.find_nonempty(&far, 10).unwrap(), (vec![], true), "the scan stops at the search budget and says so");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -107,7 +107,10 @@ pub(crate) fn overlays(text: &str, range: Range<usize>, nested: &[NestedStyle],
|
||||
with_pattern(&g.pattern, |slot| {
|
||||
let Some(re) = slot else { return };
|
||||
match re.find_nonempty(text.get(range.start..end).unwrap_or(""), crate::grep::MAX_MATCHES_PER_PARAGRAPH) {
|
||||
Ok(ms) => {
|
||||
Ok((ms, exhausted)) => {
|
||||
if exhausted {
|
||||
log::warn!("GREP style {:?} ran out of search budget in one paragraph; the rest may not be styled", g.pattern);
|
||||
}
|
||||
if ms.len() == crate::grep::MAX_MATCHES_PER_PARAGRAPH {
|
||||
log::warn!("GREP style {:?} matched more than {} times in one paragraph; the rest are not styled", g.pattern, ms.len());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user