use super::{Lens, LensContext, LensId, LensOutput};
use forge::budget::estimator::TokenEstimator;
use once_cell::sync::Lazy;
use regex::Regex;
static NOISE_PATTERNS: Lazy<Vec<Regex>> = Lazy::new(|| {
vec![
Regex::new(r"^\s*$").unwrap(), Regex::new(r"^={5,}$").unwrap(), Regex::new(r"^-{5,}$").unwrap(), Regex::new(r"^\s*#\s*$").unwrap(), Regex::new(r"^\s*Compiling .+ v[\d.]+").unwrap(), Regex::new(r"^\s*Downloading\s").unwrap(), Regex::new(r"^\s*Resolving\s").unwrap(),
]
});
pub struct FocusLens;
impl Lens for FocusLens {
fn id(&self) -> LensId {
LensId::Focus
}
fn apply(&self, input: &str, ctx: &LensContext) -> LensOutput {
let tokens_before = TokenEstimator::count_nonblocking(input);
let filtered: Vec<&str> = input
.lines()
.filter(|line| !NOISE_PATTERNS.iter().any(|re| re.is_match(line)))
.collect();
let content = if let Some(ref hint) = ctx.task_hint {
let keywords: Vec<&str> = hint.split_whitespace().collect();
let mut boosted: Vec<&str> = Vec::new();
let mut rest: Vec<&str> = Vec::new();
for line in &filtered {
if keywords
.iter()
.any(|kw| line.to_lowercase().contains(&kw.to_lowercase()))
{
boosted.push(line);
} else {
rest.push(line);
}
}
boosted.extend(rest);
boosted.join("\n")
} else {
filtered.join("\n")
};
let tokens_after = TokenEstimator::count_nonblocking(&content);
LensOutput {
content,
tokens_before,
tokens_after,
applied: vec!["focus".into()],
}
}
}