Skip to main content

scarab_plugin_api/
delight.rs

1//! Delightful messages, ASCII art, and celebrations for the plugin system
2//!
3//! Making plugin development and usage more enjoyable, one message at a time.
4
5use rand::Rng;
6
7/// Loading messages to show when plugins are being loaded
8pub const LOADING_MESSAGES: &[&str] = &[
9    "Summoning plugin spirits...",
10    "Warming up the Fusabi engine...",
11    "Compiling joy into bytecode...",
12    "Sprinkling some plugin magic...",
13    "Waking up the terminal wizards...",
14    "Brewing fresh plugin goodness...",
15    "Initializing awesomeness modules...",
16    "Loading super powers...",
17    "Charging plugin batteries...",
18    "Consulting the plugin oracle...",
19    "Calibrating terminal enhancers...",
20    "Activating plugin neurons...",
21];
22
23/// Success messages for plugin loading
24pub const SUCCESS_MESSAGES: &[&str] = &[
25    "Plugin loaded successfully!",
26    "And we're live!",
27    "That's what I'm talking about!",
28    "Nailed it!",
29    "Plugin is ready to roll!",
30    "Successfully deployed!",
31    "Good to go!",
32    "All systems green!",
33    "Plugin successfully summoned!",
34    "Welcome aboard!",
35];
36
37/// Friendly error message prefixes
38pub const ERROR_PREFIXES: &[&str] = &[
39    "Oops, something went sideways:",
40    "Well, this is awkward:",
41    "Houston, we have a problem:",
42    "Not quite what we expected:",
43    "Hmm, that didn't work:",
44    "Plot twist:",
45    "Yikes:",
46    "Oh no:",
47];
48
49/// ASCII art for celebrations
50pub const CONFETTI: &str = r#"
51    *  .  *    .  *  .    *
52  .  *  .  *  .  *  .  *  .
53*  .  *  .  *  .  *  .  *  .
54  .  *  .  *  .  *  .  *  .
55"#;
56
57pub const PARTY_POPPER: &str = r#"
58    \  |  /
59     \ | /
60      \|/
61   --- * ---
62      /|\
63     / | \
64    /  |  \
65"#;
66
67pub const TROPHY: &str = r#"
68       ___
69      |   |
70      |___|
71     /|   |\
72    /_|___|_\
73      |   |
74      |___|
75"#;
76
77pub const ROCKET: &str = r#"
78      /\
79     /  \
80    |    |
81    | ** |
82    |    |
83   /|    |\
84  / |    | \
85 /  |    |  \
86    |    |
87   /|    |\
88  / '--' |
89 /________\
90"#;
91
92/// Get a random loading message
93pub fn random_loading_message() -> &'static str {
94    let mut rng = rand::thread_rng();
95    LOADING_MESSAGES[rng.gen_range(0..LOADING_MESSAGES.len())]
96}
97
98/// Get a random success message
99pub fn random_success_message() -> &'static str {
100    let mut rng = rand::thread_rng();
101    SUCCESS_MESSAGES[rng.gen_range(0..SUCCESS_MESSAGES.len())]
102}
103
104/// Get a random error prefix
105pub fn random_error_prefix() -> &'static str {
106    let mut rng = rand::thread_rng();
107    ERROR_PREFIXES[rng.gen_range(0..ERROR_PREFIXES.len())]
108}
109
110/// Achievement system for plugin milestones
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub enum Achievement {
113    FirstPlugin,
114    TenPlugins,
115    FiftyPlugins,
116    HundredPlugins,
117    FirstCustomPlugin,
118    PluginDeveloper,
119    PluginMaster,
120    ZeroFailures,
121}
122
123impl Achievement {
124    /// Get achievement title
125    pub fn title(&self) -> &'static str {
126        match self {
127            Achievement::FirstPlugin => "Plugin Pioneer",
128            Achievement::TenPlugins => "Plugin Enthusiast",
129            Achievement::FiftyPlugins => "Plugin Collector",
130            Achievement::HundredPlugins => "Plugin Legend",
131            Achievement::FirstCustomPlugin => "Plugin Creator",
132            Achievement::PluginDeveloper => "Plugin Developer",
133            Achievement::PluginMaster => "Plugin Master",
134            Achievement::ZeroFailures => "Flawless Execution",
135        }
136    }
137
138    /// Get achievement description
139    pub fn description(&self) -> &'static str {
140        match self {
141            Achievement::FirstPlugin => "Loaded your very first plugin!",
142            Achievement::TenPlugins => "Running 10 plugins like a boss!",
143            Achievement::FiftyPlugins => "Wow, 50 plugins! Your terminal is a powerhouse!",
144            Achievement::HundredPlugins => "100 plugins!? You're absolutely legendary!",
145            Achievement::FirstCustomPlugin => "Created and loaded your own custom plugin!",
146            Achievement::PluginDeveloper => "Successfully built 5 custom plugins!",
147            Achievement::PluginMaster => "Built 25 custom plugins. You're a plugin wizard!",
148            Achievement::ZeroFailures => "Plugin running smoothly with zero failures!",
149        }
150    }
151
152    /// Get achievement emoji
153    pub fn emoji(&self) -> &'static str {
154        match self {
155            Achievement::FirstPlugin => "šŸŽ‰",
156            Achievement::TenPlugins => "⭐",
157            Achievement::FiftyPlugins => "šŸ’Ž",
158            Achievement::HundredPlugins => "šŸ‘‘",
159            Achievement::FirstCustomPlugin => "šŸ› ļø",
160            Achievement::PluginDeveloper => "šŸš€",
161            Achievement::PluginMaster => "šŸ§™",
162            Achievement::ZeroFailures => "✨",
163        }
164    }
165
166    /// Format achievement for display
167    pub fn format(&self) -> String {
168        format!("{} {} - {}", self.emoji(), self.title(), self.description())
169    }
170
171    /// Get ASCII art for this achievement
172    pub fn ascii_art(&self) -> Option<&'static str> {
173        match self {
174            Achievement::FirstPlugin => Some(PARTY_POPPER),
175            Achievement::HundredPlugins => Some(TROPHY),
176            Achievement::PluginMaster => Some(ROCKET),
177            _ => None,
178        }
179    }
180}
181
182/// Plugin mood indicator based on performance
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum PluginMood {
185    Happy,
186    Content,
187    Worried,
188    Struggling,
189    Disabled,
190}
191
192impl PluginMood {
193    /// Determine mood from failure count
194    pub fn from_failure_count(failures: u32, max_failures: u32, enabled: bool) -> Self {
195        if !enabled {
196            return PluginMood::Disabled;
197        }
198
199        match failures {
200            0 => PluginMood::Happy,
201            1 => PluginMood::Content,
202            f if f < max_failures - 1 => PluginMood::Worried,
203            _ => PluginMood::Struggling,
204        }
205    }
206
207    /// Get emoji representation
208    pub fn emoji(&self) -> &'static str {
209        match self {
210            PluginMood::Happy => "😊",
211            PluginMood::Content => "šŸ™‚",
212            PluginMood::Worried => "😟",
213            PluginMood::Struggling => "😰",
214            PluginMood::Disabled => "šŸ’¤",
215        }
216    }
217
218    /// Get descriptive text
219    pub fn description(&self) -> &'static str {
220        match self {
221            PluginMood::Happy => "Running perfectly!",
222            PluginMood::Content => "Doing well",
223            PluginMood::Worried => "Having some trouble",
224            PluginMood::Struggling => "Needs attention",
225            PluginMood::Disabled => "Taking a break",
226        }
227    }
228}
229
230/// Tips and tricks for plugin developers
231pub const DEVELOPER_TIPS: &[&str] = &[
232    "Pro tip: Use ctx.log() to debug your plugin hooks!",
233    "Did you know? Plugins can communicate via shared state in PluginContext.",
234    "Hot reload tip: .fsx scripts reload automatically, no rebuild needed!",
235    "Performance tip: Keep your hooks lightweight for snappy terminal response.",
236    "Debug trick: Check plugin.failure_count to see if your hooks are erroring.",
237    "Cool feature: Plugins can define custom emojis and colors for personality!",
238    "Remember: on_output runs for every line, so optimize for speed!",
239    "Quick win: Add a catchphrase to your plugin metadata for extra charm.",
240    "Testing tip: Use on_attach to show debug overlays when clients connect.",
241    "Style guide: Choose a unique emoji that represents your plugin's purpose.",
242];
243
244/// Get a random developer tip
245pub fn random_developer_tip() -> &'static str {
246    let mut rng = rand::thread_rng();
247    DEVELOPER_TIPS[rng.gen_range(0..DEVELOPER_TIPS.len())]
248}
249
250/// Format a friendly error message with suggestions
251pub fn friendly_error(error: &str, suggestions: Vec<&str>) -> String {
252    let mut msg = format!("{} {}\n", random_error_prefix(), error);
253
254    if !suggestions.is_empty() {
255        msg.push_str("\nšŸ’” Suggestions:\n");
256        for (i, suggestion) in suggestions.iter().enumerate() {
257            msg.push_str(&format!("  {}. {}\n", i + 1, suggestion));
258        }
259    }
260
261    msg
262}
263
264/// Format a celebration message for special occasions
265pub fn celebration_message(occasion: &str, ascii_art: Option<&str>) -> String {
266    let mut msg = format!("\nšŸŽŠ {} šŸŽŠ\n", occasion);
267
268    if let Some(art) = ascii_art {
269        msg.push_str(art);
270        msg.push('\n');
271    }
272
273    msg
274}
275
276/// Check if today is a special date and return a message
277pub fn special_date_message() -> Option<String> {
278    use chrono::{Datelike, Local};
279
280    let today = Local::now();
281    let month = today.month();
282    let day = today.day();
283
284    match (month, day) {
285        (1, 1) => Some("šŸŽ† Happy New Year! May your plugins be bug-free! šŸŽ†".to_string()),
286        (3, 14) => Some("🄧 Happy Pi Day! 3.14159... plugins loaded! 🄧".to_string()),
287        (4, 1) => Some("🤔 April Fools! Just kidding, your plugins are real. 🤔".to_string()),
288        (5, 4) => Some("⭐ May the 4th be with you! Plugin Force activated! ⭐".to_string()),
289        (10, 31) => Some("šŸŽƒ Happy Halloween! Your plugins are spooktacular! šŸŽƒ".to_string()),
290        (12, 25) => Some("šŸŽ„ Merry Christmas! Unwrapping plugin presents! šŸŽ„".to_string()),
291        _ => None,
292    }
293}
294
295#[cfg(test)]
296mod tests {
297    use super::*;
298
299    #[test]
300    fn test_plugin_mood() {
301        assert_eq!(
302            PluginMood::from_failure_count(0, 3, true),
303            PluginMood::Happy
304        );
305        assert_eq!(
306            PluginMood::from_failure_count(1, 3, true),
307            PluginMood::Content
308        );
309        assert_eq!(
310            PluginMood::from_failure_count(2, 3, true),
311            PluginMood::Struggling
312        );
313        assert_eq!(
314            PluginMood::from_failure_count(0, 3, false),
315            PluginMood::Disabled
316        );
317    }
318
319    #[test]
320    fn test_achievement_formatting() {
321        let achievement = Achievement::FirstPlugin;
322        let formatted = achievement.format();
323        assert!(formatted.contains("Plugin Pioneer"));
324        assert!(formatted.contains("šŸŽ‰"));
325    }
326
327    #[test]
328    fn test_friendly_error() {
329        let error = friendly_error(
330            "Plugin failed to load",
331            vec!["Check the file path", "Verify plugin format"],
332        );
333        assert!(error.contains("Plugin failed to load"));
334        assert!(error.contains("Check the file path"));
335    }
336}