src/cli/command/grep.rs

//! `ripgrab grep` — one-shot scan without follow.
//!
//! Opens each path, walks every line once, applies the filter, writes the
//! matches to stdout. Useful in CI or pre-commit scripts.

use std::io;

use anyhow::Result;

use crate::cli::args::GrepArgs;
use crate::filter::{FilterSet, MatchOutcome};
use crate::render::mode::stream::StreamRenderer;
use crate::source::file::FileSource;
use crate::source::Source;

pub async fn run(args: GrepArgs) -> Result<()> {
    let filter = FilterSet::compile(&args.includes, &[], None)?;
    let compiled = args
        .where_clause
        .as_deref()
        .map(crate::filter::dsl::parse_and_compile)
        .transpose()?;

    let stdout = io::stdout();
    let mut renderer = StreamRenderer::new(stdout.lock(), true, true);

    for path in &args.paths {
        let mut src = FileSource::open(path).await?;
        while let Some(item) = src.next_line().await? {
            if let Some(c) = &compiled {
                let mut ctx = crate::filter::dsl::EvalContext::new();
                ctx.set("origin", &item.origin);
                ctx.set("body", &item.line);
                if !crate::filter::dsl::evaluate(c, &ctx) {
                    continue;
                }
            }
            if let MatchOutcome::Plain = filter.apply(&item.line) {
                renderer.render(&item.origin, &item.line)?;
            }
        }
    }
    renderer.flush()?;
    Ok(())
}