gdelt 0.1.0

CLI for GDELT Project - optimized for agentic usage with local data caching
//! Table output formatting using comfy-table

use crate::cli::output::Tabular;
use crate::error::Result;
use comfy_table::{presets, Cell, ContentArrangement, Table};

/// Table output formatter
pub struct TableOutput {
    max_width: Option<u16>,
}

impl TableOutput {
    pub fn new() -> Self {
        Self { max_width: None }
    }

    pub fn with_max_width(mut self, width: u16) -> Self {
        self.max_width = Some(width);
        self
    }

    /// Print a single value as a table (key-value pairs)
    pub fn print<T: Tabular>(&self, value: &T) -> Result<()> {
        let headers = T::headers();
        let row = value.row();

        let mut table = Table::new();
        table.load_preset(presets::UTF8_FULL);
        table.set_content_arrangement(ContentArrangement::Dynamic);

        if let Some(width) = self.max_width {
            table.set_width(width);
        }

        // For single items, display as key-value pairs
        if headers.len() <= 4 {
            for (key, val) in headers.iter().zip(row.iter()) {
                table.add_row(vec![Cell::new(key), Cell::new(val)]);
            }
        } else {
            table.set_header(&headers);
            table.add_row(&row);
        }

        println!("{table}");
        Ok(())
    }

    /// Print multiple values as a table
    pub fn print_rows<T: Tabular>(&self, values: &[T]) -> Result<()> {
        if values.is_empty() {
            println!("No results");
            return Ok(());
        }

        let mut table = Table::new();
        table.load_preset(presets::UTF8_FULL);
        table.set_content_arrangement(ContentArrangement::Dynamic);

        if let Some(width) = self.max_width {
            table.set_width(width);
        }

        table.set_header(&T::headers());

        for value in values {
            table.add_row(&value.row());
        }

        println!("{table}");
        Ok(())
    }
}

impl Default for TableOutput {
    fn default() -> Self {
        Self::new()
    }
}