use super::OutputFormatter;
use crate::config::OutputConfig;
use crate::search::SearchResult;
use anyhow::Result;
use csv::Writer;
use serde::Serialize;
use std::io::Write;
#[derive(Default)]
pub struct CsvFormatter;
impl 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(())
}
}