opengrep 1.1.0

Advanced AST-aware code search tool with tree-sitter parsing and AI integration capabilities
Documentation
//! CSV output formatter.

use super::OutputFormatter;
use crate::config::OutputConfig;
use crate::search::SearchResult;
use anyhow::Result;
use csv::Writer;
use serde::Serialize;
use std::io::Write;

/// Formats search results as CSV.
#[derive(Default)]
pub struct CsvFormatter;

impl CsvFormatter {
    /// Creates a new `CsvFormatter`.
    pub fn new() -> Self {
        Self
    }
}

#[derive(Serialize)]
struct CsvRecord<'a> {
    file_path: &'a str,
    line_number: usize,
    column_start: usize,
    column_end: usize,
    line_text: &'a str,
    ast_node_type: Option<String>,
    ast_parent_name: Option<String>,
    score: f64,
}

impl OutputFormatter for CsvFormatter {
    fn format<W: Write>(
        &self,
        results: &[SearchResult],
        writer: &mut W,
        _config: &OutputConfig,
    ) -> Result<()> {
        let mut wtr = Writer::from_writer(writer);

        for result in results.iter().filter(|r| !r.matches.is_empty()) {
            for m in &result.matches {
                let record = CsvRecord {
                    file_path: &result.path.to_string_lossy(),
                    line_number: m.line_number,
                    column_start: m.column_range.start,
                    column_end: m.column_range.end,
                    line_text: &m.line_text,
                    ast_node_type: m.ast_context.as_ref().map(|c| c.summary.clone()),
                    ast_parent_name: None,
                    score: m.score,
                };
                wtr.serialize(record)?;
            }
        }
        wtr.flush()?;
        Ok(())
    }
}