Skip to main content

jtool_grep/output/
mod.rs

1//! Output formatting for grep results
2
3use crate::types::GrepResult;
4use anyhow::Result;
5use std::io::IsTerminal;
6
7pub mod csv;
8pub mod human;
9pub mod json;
10pub mod jsonl;
11pub mod template;
12
13pub use csv::CsvFormatter;
14pub use human::HumanFormatter;
15pub use json::JsonFormatter;
16pub use jsonl::JsonlFormatter;
17pub use template::TemplateFormatter;
18
19/// Trait for output formatters
20pub trait OutputFormatter {
21    /// Format a single grep result
22    fn format_result(&self, result: &GrepResult) -> Result<String>;
23
24    /// Format multiple grep results
25    fn format_results(&self, results: &[GrepResult]) -> Result<String>;
26
27    /// Print a result directly to stdout
28    fn print_result(&self, result: &GrepResult) -> Result<()> {
29        print!("{}", self.format_result(result)?);
30        Ok(())
31    }
32
33    /// Print multiple results directly to stdout
34    fn print_results(&self, results: &[GrepResult]) -> Result<()> {
35        print!("{}", self.format_results(results)?);
36        Ok(())
37    }
38}
39
40/// Output format presets
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
42pub enum OutputFormat {
43    /// Standard format: `notebook:cellN[exec]:type:line: content`
44    #[default]
45    Standard,
46    /// Compact format: notebook:cellN:lineN: content
47    Compact,
48    /// Ultra-compact: notebook:lineN: content (no cell info)
49    CompactNoCell,
50    /// Only notebook names
51    PathsOnly,
52    /// Only matched text, no metadata
53    MatchesOnly,
54    /// Grouped with separator
55    Grouped,
56}
57
58/// Color output mode
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
60pub enum ColorMode {
61    #[default]
62    Auto,
63    Always,
64    Never,
65}
66
67impl ColorMode {
68    pub fn parse(s: &str) -> Option<Self> {
69        match s.to_lowercase().as_str() {
70            "auto" => Some(ColorMode::Auto),
71            "always" => Some(ColorMode::Always),
72            "never" => Some(ColorMode::Never),
73            _ => None,
74        }
75    }
76
77    /// Determine if color should be used based on mode and terminal detection
78    pub fn should_use_color(&self) -> bool {
79        match self {
80            ColorMode::Always => true,
81            ColorMode::Never => false,
82            ColorMode::Auto => std::io::stdout().is_terminal(),
83        }
84    }
85}
86
87/// Options for output formatting
88#[derive(Debug, Clone, Default)]
89pub struct OutputOptions {
90    /// Show notebook names in output
91    pub show_filename: bool,
92
93    /// Show only notebook names (files-with-matches mode)
94    pub files_with_matches: bool,
95
96    /// Show match counts instead of matches
97    pub count_mode: bool,
98
99    /// Number of context lines to show
100    pub context_lines: Option<usize>,
101
102    /// Use heading mode (group by notebook)
103    pub heading_mode: bool,
104
105    /// Don't show line numbers
106    pub no_line_number: bool,
107
108    /// Output format preset
109    pub format: OutputFormat,
110
111    /// Custom template string
112    pub template: Option<String>,
113
114    /// Color mode
115    pub color_mode: ColorMode,
116}