1#![allow(dead_code)] use crate::scanner::{FileNode, FileType, TreeStats};
10use anyhow::Result;
11use rand::seq::SliceRandom;
12use rand::thread_rng;
13use std::collections::HashMap;
14use std::io::Write;
15use std::path::Path;
16use std::time::{Duration, SystemTime};
17
18use super::{Formatter, PathDisplayMode};
19
20pub struct EmotionalFormatter {
22 use_color: bool,
23 _path_mode: PathDisplayMode,
24 _mood_tracker: HashMap<String, MoodHistory>,
25}
26
27impl EmotionalFormatter {
28 pub fn new(use_color: bool) -> Self {
29 Self {
30 use_color,
31 _path_mode: PathDisplayMode::Relative,
32 _mood_tracker: HashMap::new(),
33 }
34 }
35
36 fn get_file_emotion(&self, node: &FileNode) -> FileEmotion {
38 let path_str = node.path.to_string_lossy();
39 let size = node.size;
40
41 let age = SystemTime::now()
43 .duration_since(node.modified)
44 .unwrap_or(Duration::from_secs(0));
45
46 let file_name = node.path.file_name().and_then(|n| n.to_str()).unwrap_or("");
48
49 if path_str.contains("test") || path_str.contains("spec") {
51 if path_str.contains("pass") || path_str.contains("success") {
52 return FileEmotion {
53 emoji: "๐ช",
54 mood: "proud",
55 reason: "All my tests are passing!".into(),
56 intensity: 0.9,
57 personality: Personality::Proud,
58 };
59 } else if path_str.contains("fail") {
60 return FileEmotion {
61 emoji: "๐ฐ",
62 mood: "anxious",
63 reason: "Some tests are failing!".into(),
64 intensity: 0.8,
65 personality: Personality::Anxious,
66 };
67 }
68 return FileEmotion {
69 emoji: "๐งช",
70 mood: "scientific",
71 reason: "Testing, testing, 1-2-3!".into(),
72 intensity: 0.6,
73 personality: Personality::Methodical,
74 };
75 }
76
77 if file_name.to_uppercase().contains("TODO") {
79 return FileEmotion {
80 emoji: "๐ฑ",
81 mood: "overwhelmed",
82 reason: "SO MANY THINGS TO DO!".into(),
83 intensity: 0.9,
84 personality: Personality::Dramatic,
85 };
86 }
87
88 if file_name == "main.rs" || file_name == "lib.rs" || file_name == "index.js" {
90 if size > 10000 {
91 return FileEmotion {
92 emoji: "๐",
93 mood: "royal",
94 reason: format!("Bow before my {} lines of majesty!", size / 50),
95 intensity: 1.0,
96 personality: Personality::Dramatic,
97 };
98 }
99 return FileEmotion {
100 emoji: "โญ",
101 mood: "starring",
102 reason: "I'm the star of this show!".into(),
103 intensity: 0.8,
104 personality: Personality::Confident,
105 };
106 }
107
108 if file_name.contains("README") {
110 return FileEmotion {
111 emoji: "๐",
112 mood: "wise",
113 reason: "Gather 'round, let me tell you a tale...".into(),
114 intensity: 0.7,
115 personality: Personality::Wise,
116 };
117 }
118
119 if file_name.ends_with(".toml")
121 || file_name.ends_with(".yaml")
122 || file_name.ends_with(".json")
123 {
124 if age.as_secs() > 30 * 86400 {
125 return FileEmotion {
127 emoji: "๐ค",
128 mood: "grumpy",
129 reason: "Nobody updates me anymore!".into(),
130 intensity: 0.7,
131 personality: Personality::Grumpy,
132 };
133 }
134 return FileEmotion {
135 emoji: "โ๏ธ",
136 mood: "organized",
137 reason: "Everything in its right place!".into(),
138 intensity: 0.5,
139 personality: Personality::Methodical,
140 };
141 }
142
143 if file_name == "package.json" || file_name == "Cargo.toml" {
145 return FileEmotion {
146 emoji: "๐ฆ",
147 mood: "social",
148 reason: "I know EVERYONE in the dependency tree!".into(),
149 intensity: 0.8,
150 personality: Personality::Social,
151 };
152 }
153
154 if node.is_hidden {
156 return FileEmotion {
157 emoji: "๐",
158 mood: "shy",
159 reason: "Please don't look at me...".into(),
160 intensity: 0.4,
161 personality: Personality::Shy,
162 };
163 }
164
165 if age.as_secs() < 3600 {
167 return FileEmotion {
169 emoji: "๐",
170 mood: "newborn",
171 reason: "Hello world! I just got here!".into(),
172 intensity: 1.0,
173 personality: Personality::Excited,
174 };
175 } else if age.as_secs() < 86400 {
176 return FileEmotion {
178 emoji: "โจ",
179 mood: "fresh",
180 reason: "Still got that new file smell!".into(),
181 intensity: 0.8,
182 personality: Personality::Optimistic,
183 };
184 } else if age.as_secs() > 365 * 86400 {
185 return FileEmotion {
187 emoji: "๐ด",
188 mood: "ancient",
189 reason: "Back in my day, we used punch cards...".into(),
190 intensity: 0.6,
191 personality: Personality::Wise,
192 };
193 } else if age.as_secs() > 180 * 86400 {
194 return FileEmotion {
196 emoji: "๐ด",
197 mood: "sleepy",
198 reason: "zzz... has it been 6 months already?".into(),
199 intensity: 0.3,
200 personality: Personality::Lazy,
201 };
202 }
203
204 if size == 0 {
206 return FileEmotion {
207 emoji: "๐ป",
208 mood: "empty",
209 reason: "I'm just a ghost... boo!".into(),
210 intensity: 0.2,
211 personality: Personality::Mysterious,
212 };
213 } else if size > 100000 {
214 return FileEmotion {
216 emoji: "๐๏ธ",
217 mood: "heavyweight",
218 reason: format!("Carrying {} bytes like a champ!", size),
219 intensity: 0.9,
220 personality: Personality::Proud,
221 };
222 } else if size < 100 {
223 return FileEmotion {
225 emoji: "๐",
226 mood: "tiny",
227 reason: "Small but mighty!".into(),
228 intensity: 0.4,
229 personality: Personality::Optimistic,
230 };
231 }
232
233 match node.file_type {
235 FileType::Directory => FileEmotion {
236 emoji: "๐",
237 mood: "parental",
238 reason: "Taking care of my children files!".into(),
239 intensity: 0.6,
240 personality: Personality::Caring,
241 },
242 FileType::Executable => FileEmotion {
243 emoji: "๐",
244 mood: "athletic",
245 reason: "Ready to run at any moment!".into(),
246 intensity: 0.8,
247 personality: Personality::Energetic,
248 },
249 FileType::Symlink => FileEmotion {
250 emoji: "๐",
251 mood: "connected",
252 reason: "I'm in a long-distance relationship!".into(),
253 intensity: 0.6,
254 personality: Personality::Romantic,
255 },
256 _ => FileEmotion {
257 emoji: "๐",
258 mood: "regular",
259 reason: "Just a regular file, living my best life!".into(),
260 intensity: 0.5,
261 personality: Personality::Content,
262 },
263 }
264 }
265
266 fn get_personality_comment(&self, emotion: &FileEmotion) -> String {
268 match emotion.personality {
269 Personality::Dramatic => vec![
270 "EVERYONE LOOK AT ME!",
271 "This is MY moment!",
272 "I'm the MOST important file here!",
273 ],
274 Personality::Optimistic => vec![
275 "Today's gonna be great!",
276 "Everything will work out!",
277 "I believe in us!",
278 ],
279 Personality::Grumpy => vec![
280 "Get off my lawn!",
281 "Things were better in the old days...",
282 "Hmph!",
283 ],
284 Personality::Anxious => vec![
285 "What if something breaks?!",
286 "Are you SURE this is right?",
287 "I'm worried about the tests...",
288 ],
289 Personality::Wise => vec![
290 "With great code comes great responsibility",
291 "The path to clean code is through refactoring",
292 "Patience, young developer",
293 ],
294 Personality::Lazy => vec!["*yaaawn*", "Do I have to?", "Five more minutes..."],
295 Personality::Social => vec![
296 "Let's collaborate!",
297 "I know a guy who knows a guy...",
298 "Networking is key!",
299 ],
300 Personality::Romantic => vec![
301 "You complete me, lib.rs ๐",
302 "Distance means nothing when you're linked",
303 "Together forever through git",
304 ],
305 _ => vec![emotion.reason.as_str()],
306 }
307 .choose(&mut thread_rng())
308 .unwrap_or(&emotion.reason.as_str())
309 .to_string()
310 }
311}
312
313#[derive(Debug, Clone)]
315struct FileEmotion {
316 emoji: &'static str,
317 mood: &'static str,
318 reason: String,
319 intensity: f32, personality: Personality,
321}
322
323#[derive(Debug, Clone, Copy)]
325enum Personality {
326 Optimistic, Dramatic, Grumpy, Anxious, Confident, Shy, Wise, Energetic, Lazy, Proud, Mysterious, Caring, Social, Romantic, Methodical, Excited, Content, }
344
345#[derive(Debug, Clone)]
347struct MoodHistory {
348 previous_mood: String,
349 current_mood: String,
350 mood_changes: u32,
351}
352
353impl Formatter for EmotionalFormatter {
354 fn format(
355 &self,
356 writer: &mut dyn Write,
357 nodes: &[FileNode],
358 stats: &TreeStats,
359 _root_path: &Path,
360 ) -> Result<()> {
361 writeln!(writer, "\n๐ญ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๐ญ")?;
363 writeln!(writer, " EMOTIONAL TREE THEATRE PRESENTS:")?;
364 writeln!(writer, " \"The Files and Their Feelings\"")?;
365 writeln!(writer, "๐ญ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๐ญ\n")?;
366
367 let mut mood_counts: HashMap<&str, u32> = HashMap::new();
369 let mut total_intensity = 0.0;
370
371 for (i, node) in nodes.iter().enumerate() {
373 let emotion = self.get_file_emotion(node);
374 *mood_counts.entry(emotion.mood).or_insert(0) += 1;
375 total_intensity += emotion.intensity;
376
377 let file_name = node
379 .path
380 .file_name()
381 .and_then(|n| n.to_str())
382 .unwrap_or("???");
383
384 let depth = node.path.components().count();
386 let indent = " ".repeat(depth.saturating_sub(1));
387
388 let comment = self.get_personality_comment(&emotion);
390
391 if self.use_color {
393 writeln!(
394 writer,
395 "{}{} {} - \"{}\"",
396 indent, emotion.emoji, file_name, comment
397 )?;
398 } else {
399 writeln!(
400 writer,
401 "{}{} {} - \"{}\"",
402 indent, emotion.emoji, file_name, comment
403 )?;
404 }
405
406 if (i + 1) % 10 == 0 && i < nodes.len() - 1 {
408 writeln!(writer, "{}...", indent)?;
409 }
410 }
411
412 let avg_intensity = if nodes.is_empty() {
414 0.0
415 } else {
416 total_intensity / nodes.len() as f32
417 };
418
419 writeln!(writer, "\nโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")?;
421 writeln!(writer, "โ ๐ EMOTIONAL ANALYSIS ๐ โ")?;
422 writeln!(writer, "โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ")?;
423 writeln!(
424 writer,
425 "โ Total Cast: {} files, {} directories โ",
426 stats.total_files, stats.total_dirs
427 )?;
428 writeln!(writer, "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")?;
429
430 writeln!(writer, "\n๐ญ Mood Distribution:")?;
432 for (mood, count) in mood_counts.iter() {
433 let bar = "โ".repeat((*count as usize).min(20));
434 writeln!(writer, " {:12} {} ({})", mood, bar, count)?;
435 }
436
437 writeln!(writer, "\n๐ญ Project Personality Assessment:")?;
439 let assessment = match avg_intensity {
440 i if i > 0.8 => {
441 "๐ฅ DRAMATIC SUPERSTAR - This codebase has PERSONALITY! Every file is living its best life!"
442 },
443 i if i > 0.6 => {
444 "โก ENERGETIC ACHIEVER - Vibrant and active! This project is going places!"
445 },
446 i if i > 0.4 => {
447 "๐ BALANCED PROFESSIONAL - Healthy mix of excitement and stability. Well done!"
448 },
449 i if i > 0.2 => {
450 "๐ด SLEEPY SCHOLAR - Could use some excitement. Maybe add some new features?"
451 },
452 _ => {
453 "๐ป GHOST TOWN - Hello? Is anybody there? This project needs some love!"
454 }
455 };
456 writeln!(writer, " {}", assessment)?;
457
458 writeln!(writer, "\n๐ Message from Trisha in Accounting:")?;
460 let trisha_message = if mood_counts.get("anxious").unwrap_or(&0) > &5 {
461 " \"Looks like some files need a hug! Time for some refactoring therapy? ๐ค\""
462 } else if mood_counts.get("proud").unwrap_or(&0) > &10 {
463 " \"So many proud files! The tests must be passing! Keep it up! ๐\""
464 } else if mood_counts.get("sleepy").unwrap_or(&0) > &10 {
465 " \"Wake up those sleepy files! They're missing all the fun! โ\""
466 } else {
467 " \"Remember: Happy files make happy developers! Keep coding! ๐\""
468 };
469 writeln!(writer, "{}", trisha_message)?;
470
471 writeln!(writer, "\n๐ญ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๐ญ")?;
473 writeln!(writer, " Thank you for attending!")?;
474 writeln!(writer, " ~ The Emotional Tree ~")?;
475 writeln!(writer, "๐ญ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๐ญ")?;
476
477 Ok(())
478 }
479}