jtool-grep 0.2.0

notebook-specific grep tool for jtool
Documentation
//! Output formatting for grep results

use crate::types::GrepResult;
use anyhow::Result;
use std::io::IsTerminal;

pub mod csv;
pub mod human;
pub mod json;
pub mod jsonl;
pub mod template;

pub use csv::CsvFormatter;
pub use human::HumanFormatter;
pub use json::JsonFormatter;
pub use jsonl::JsonlFormatter;
pub use template::TemplateFormatter;

/// Trait for output formatters
pub trait OutputFormatter {
    /// Format a single grep result
    fn format_result(&self, result: &GrepResult) -> Result<String>;

    /// Format multiple grep results
    fn format_results(&self, results: &[GrepResult]) -> Result<String>;

    /// Print a result directly to stdout
    fn print_result(&self, result: &GrepResult) -> Result<()> {
        print!("{}", self.format_result(result)?);
        Ok(())
    }

    /// Print multiple results directly to stdout
    fn print_results(&self, results: &[GrepResult]) -> Result<()> {
        print!("{}", self.format_results(results)?);
        Ok(())
    }
}

/// Output format presets
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum OutputFormat {
    /// Standard format: `notebook:cellN[exec]:type:line: content`
    #[default]
    Standard,
    /// Compact format: notebook:cellN:lineN: content
    Compact,
    /// Ultra-compact: notebook:lineN: content (no cell info)
    CompactNoCell,
    /// Only notebook names
    PathsOnly,
    /// Only matched text, no metadata
    MatchesOnly,
    /// Grouped with separator
    Grouped,
}

/// Color output mode
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ColorMode {
    #[default]
    Auto,
    Always,
    Never,
}

impl ColorMode {
    pub fn parse(s: &str) -> Option<Self> {
        match s.to_lowercase().as_str() {
            "auto" => Some(ColorMode::Auto),
            "always" => Some(ColorMode::Always),
            "never" => Some(ColorMode::Never),
            _ => None,
        }
    }

    /// Determine if color should be used based on mode and terminal detection
    pub fn should_use_color(&self) -> bool {
        match self {
            ColorMode::Always => true,
            ColorMode::Never => false,
            ColorMode::Auto => std::io::stdout().is_terminal(),
        }
    }
}

/// Options for output formatting
#[derive(Debug, Clone, Default)]
pub struct OutputOptions {
    /// Show notebook names in output
    pub show_filename: bool,

    /// Show only notebook names (files-with-matches mode)
    pub files_with_matches: bool,

    /// Show match counts instead of matches
    pub count_mode: bool,

    /// Number of context lines to show
    pub context_lines: Option<usize>,

    /// Use heading mode (group by notebook)
    pub heading_mode: bool,

    /// Don't show line numbers
    pub no_line_number: bool,

    /// Output format preset
    pub format: OutputFormat,

    /// Custom template string
    pub template: Option<String>,

    /// Color mode
    pub color_mode: ColorMode,
}