watchdiff_tui/core/
events.rs1use 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 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 let highlighted = event.to_highlighted();
116
117 self.events.insert(0, event);
119 self.highlighted_events.insert(0, highlighted);
120
121 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}