Skip to main content

jtool_grep/
types.rs

1//! Core types for grep functionality
2
3use serde::{Deserialize, Serialize};
4
5/// A single match found in a notebook
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Match {
8    /// Cell index (0-based)
9    pub cell_index: usize,
10
11    /// Cell number (1-based, human-friendly)
12    pub cell_number: usize,
13
14    /// Execution count (may be None for unexecuted cells)
15    pub execution_count: Option<i32>,
16
17    /// Type of match (input or output)
18    pub match_type: MatchType,
19
20    /// Line number within the cell (0-based)
21    pub line_index: usize,
22
23    /// Line number (1-based, human-friendly)
24    pub line_number: usize,
25
26    /// The full line content
27    pub line_content: String,
28
29    /// The matched portion of the line
30    pub matched_text: String,
31
32    /// Context lines before the match
33    #[serde(skip_serializing_if = "Vec::is_empty", default)]
34    pub context_before: Vec<String>,
35
36    /// Context lines after the match
37    #[serde(skip_serializing_if = "Vec::is_empty", default)]
38    pub context_after: Vec<String>,
39}
40
41impl Match {
42    /// Create a new Match with 1-based numbers calculated
43    pub fn new(
44        cell_index: usize,
45        execution_count: Option<i32>,
46        match_type: MatchType,
47        line_index: usize,
48        line_content: String,
49        matched_text: String,
50    ) -> Self {
51        Self {
52            cell_index,
53            cell_number: cell_index + 1,
54            execution_count,
55            match_type,
56            line_index,
57            line_number: line_index + 1,
58            line_content,
59            matched_text,
60            context_before: Vec::new(),
61            context_after: Vec::new(),
62        }
63    }
64}
65
66/// Type of match (input or output)
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
68#[serde(rename_all = "lowercase")]
69pub enum MatchType {
70    /// Match in cell input (source code)
71    Input,
72    /// Match in cell output
73    Output,
74}
75
76impl std::fmt::Display for MatchType {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        match self {
79            MatchType::Input => write!(f, "input"),
80            MatchType::Output => write!(f, "output"),
81        }
82    }
83}
84
85/// Options for grep search
86#[derive(Debug, Clone)]
87pub struct GrepOptions {
88    /// The pattern to search for
89    pub pattern: String,
90
91    /// Case insensitive search
92    pub case_insensitive: bool,
93
94    /// Search in cell inputs
95    pub search_inputs: bool,
96
97    /// Search in cell outputs
98    pub search_outputs: bool,
99
100    /// Number of context lines (for -C flag)
101    pub context_lines: Option<usize>,
102
103    /// Number of lines before match (for -B flag)
104    pub context_before: Option<usize>,
105
106    /// Number of lines after match (for -A flag)
107    pub context_after: Option<usize>,
108
109    /// Match only whole words
110    pub word_regexp: bool,
111
112    /// Treat pattern as fixed string (not regex)
113    pub fixed_strings: bool,
114
115    /// Show only the matching part of lines
116    pub only_matching: bool,
117
118    /// Invert match (show non-matching lines)
119    pub invert_match: bool,
120
121    /// Maximum number of matches per notebook
122    pub max_count: Option<usize>,
123
124    /// Filter: only search code cells
125    pub code_cells_only: bool,
126
127    /// Filter: only search markdown cells
128    pub markdown_cells_only: bool,
129
130    /// Filter: only search raw cells
131    pub raw_cells_only: bool,
132
133    /// Filter: only search executed cells (have execution_count)
134    pub executed_only: bool,
135
136    /// Filter: only search non-executed cells
137    pub not_executed_only: bool,
138
139    /// Filter: only search stream outputs
140    pub stream_output_only: bool,
141
142    /// Filter: only search error outputs
143    pub error_output_only: bool,
144
145    /// Filter: only search result outputs
146    pub result_output_only: bool,
147
148    /// Only search notebooks matching glob pattern
149    pub glob_pattern: Option<String>,
150
151    /// Exclude notebooks matching pattern
152    pub exclude_pattern: Option<String>,
153}
154
155impl Default for GrepOptions {
156    fn default() -> Self {
157        Self {
158            pattern: String::new(),
159            case_insensitive: false,
160            search_inputs: true,
161            search_outputs: true,
162            context_lines: None,
163            context_before: None,
164            context_after: None,
165            word_regexp: false,
166            fixed_strings: false,
167            only_matching: false,
168            invert_match: false,
169            max_count: None,
170            code_cells_only: false,
171            markdown_cells_only: false,
172            raw_cells_only: false,
173            executed_only: false,
174            not_executed_only: false,
175            stream_output_only: false,
176            error_output_only: false,
177            result_output_only: false,
178            glob_pattern: None,
179            exclude_pattern: None,
180        }
181    }
182}
183
184/// Result of a grep search
185#[derive(Debug, Clone, Serialize)]
186pub struct GrepResult {
187    /// Path to the notebook
188    pub notebook: String,
189
190    /// All matches found
191    pub matches: Vec<Match>,
192}
193
194impl GrepResult {
195    pub fn new(notebook: String) -> Self {
196        Self {
197            notebook,
198            matches: Vec::new(),
199        }
200    }
201
202    pub fn is_empty(&self) -> bool {
203        self.matches.is_empty()
204    }
205
206    pub fn match_count(&self) -> usize {
207        self.matches.len()
208    }
209}