watchdiff_tui/core/
events.rs

1use std::path::PathBuf;
2use std::time::SystemTime;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub enum FileEventKind {
7    Created,
8    Modified,
9    Deleted,
10    Moved { from: PathBuf, to: PathBuf },
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct FileEvent {
15    pub path: PathBuf,
16    pub kind: FileEventKind,
17    pub timestamp: SystemTime,
18    pub diff: Option<String>,
19    pub content_preview: Option<String>,
20}
21
22#[derive(Debug, Clone)]
23pub struct HighlightedFileEvent {
24    pub path: PathBuf,
25    pub kind: FileEventKind,
26    pub timestamp: SystemTime,
27    pub diff: Option<String>,
28    pub content_preview: Option<String>,
29    pub highlighted_diff: Option<String>,
30    pub highlighted_preview: Option<String>,
31}
32
33impl FileEvent {
34    pub fn new(path: PathBuf, kind: FileEventKind) -> Self {
35        Self {
36            path,
37            kind,
38            timestamp: SystemTime::now(),
39            diff: None,
40            content_preview: None,
41        }
42    }
43
44    pub fn with_diff(mut self, diff: String) -> Self {
45        self.diff = Some(diff);
46        self
47    }
48
49    pub fn with_preview(mut self, preview: String) -> Self {
50        self.content_preview = Some(preview);
51        self
52    }
53
54    pub fn to_highlighted(&self) -> HighlightedFileEvent {
55        let highlighted_event = HighlightedFileEvent {
56            path: self.path.clone(),
57            kind: self.kind.clone(),
58            timestamp: self.timestamp,
59            diff: self.diff.clone(),
60            content_preview: self.content_preview.clone(),
61            highlighted_diff: None,
62            highlighted_preview: None,
63        };
64
65        // Skip syntax highlighting to avoid ANSI escape codes in TUI
66        // The TUI will use its own built-in coloring for diff display
67        // Terminal highlighting is only useful for non-TUI output modes
68
69        highlighted_event
70    }
71}
72
73impl HighlightedFileEvent {
74    pub fn from_file_event(event: FileEvent) -> Self {
75        event.to_highlighted()
76    }
77}
78
79#[derive(Debug, Clone)]
80pub enum AppEvent {
81    FileChanged(FileEvent),
82    Tick,
83    Quit,
84    ScrollUp,
85    ScrollDown,
86    ToggleHelp,
87}
88
89#[derive(Debug, Clone)]
90pub struct AppState {
91    pub events: Vec<FileEvent>,
92    pub highlighted_events: Vec<HighlightedFileEvent>,
93    pub scroll_offset: usize,
94    pub max_events: usize,
95    pub show_help: bool,
96    pub watched_files: std::collections::HashSet<PathBuf>,
97}
98
99impl Default for AppState {
100    fn default() -> Self {
101        Self {
102            events: Vec::new(),
103            highlighted_events: Vec::new(),
104            scroll_offset: 0,
105            max_events: 1000,
106            show_help: false,
107            watched_files: std::collections::HashSet::new(),
108        }
109    }
110}
111
112impl AppState {
113    pub fn add_event(&mut self, event: FileEvent) {
114        // Convert to highlighted event
115        let highlighted = event.to_highlighted();
116        
117        // Add to both collections
118        self.events.insert(0, event);
119        self.highlighted_events.insert(0, highlighted);
120        
121        // Maintain size limits
122        if self.events.len() > self.max_events {
123            self.events.truncate(self.max_events);
124        }
125        if self.highlighted_events.len() > self.max_events {
126            self.highlighted_events.truncate(self.max_events);
127        }
128        
129        self.scroll_offset = 0;
130    }
131
132    pub fn scroll_up(&mut self) {
133        if self.scroll_offset > 0 {
134            self.scroll_offset -= 1;
135        }
136    }
137
138    pub fn scroll_down(&mut self) {
139        if self.scroll_offset < self.highlighted_events.len().saturating_sub(1) {
140            self.scroll_offset += 1;
141        }
142    }
143
144    pub fn toggle_help(&mut self) {
145        self.show_help = !self.show_help;
146    }
147
148    pub fn get_visible_events(&self, height: usize) -> &[FileEvent] {
149        let start = self.scroll_offset;
150        let end = (start + height).min(self.events.len());
151        &self.events[start..end]
152    }
153
154    pub fn get_visible_highlighted_events(&self, height: usize) -> &[HighlightedFileEvent] {
155        let start = self.scroll_offset;
156        let end = (start + height).min(self.highlighted_events.len());
157        &self.highlighted_events[start..end]
158    }
159}