syncable_cli/agent/ui/
colors.rs

1//! Color theme and styling utilities for terminal UI
2//!
3//! Provides semantic colors and ANSI escape codes for consistent styling.
4
5use colored::Colorize;
6
7/// Status icons for different states
8pub mod icons {
9    pub const PENDING: &str = "○";
10    pub const EXECUTING: &str = "◐";
11    pub const SUCCESS: &str = "✓";
12    pub const ERROR: &str = "✗";
13    pub const WARNING: &str = "⚠";
14    pub const CANCELED: &str = "⊘";
15    pub const CONFIRMING: &str = "⏳";
16    pub const ARROW: &str = "→";
17    pub const THINKING: &str = "💭";
18    pub const ROBOT: &str = "🤖";
19    pub const TOOL: &str = "🔧";
20    pub const SHELL: &str = "🐚";
21    pub const EDIT: &str = "✏️";
22    pub const FILE: &str = "📄";
23    pub const FOLDER: &str = "📁";
24    pub const SECURITY: &str = "🔒";
25    pub const SEARCH: &str = "🔍";
26}
27
28/// ANSI escape codes for direct terminal control
29pub mod ansi {
30    /// Clear current line
31    pub const CLEAR_LINE: &str = "\x1b[2K\r";
32    /// Move cursor up one line
33    pub const CURSOR_UP: &str = "\x1b[1A";
34    /// Hide cursor
35    pub const HIDE_CURSOR: &str = "\x1b[?25l";
36    /// Show cursor
37    pub const SHOW_CURSOR: &str = "\x1b[?25h";
38    /// Reset all styles
39    pub const RESET: &str = "\x1b[0m";
40    /// Bold
41    pub const BOLD: &str = "\x1b[1m";
42    /// Dim
43    pub const DIM: &str = "\x1b[2m";
44
45    // 256-color codes for Syncable brand
46    pub const PURPLE: &str = "\x1b[38;5;141m";
47    pub const ORANGE: &str = "\x1b[38;5;216m";
48    pub const PINK: &str = "\x1b[38;5;212m";
49    pub const MAGENTA: &str = "\x1b[38;5;207m";
50    pub const CYAN: &str = "\x1b[38;5;51m";
51    pub const GRAY: &str = "\x1b[38;5;245m";
52    pub const WHITE: &str = "\x1b[38;5;255m";
53    pub const SUCCESS: &str = "\x1b[38;5;114m"; // Green for success
54}
55
56/// Format a tool name for display
57pub fn format_tool_name(name: &str) -> String {
58    name.cyan().bold().to_string()
59}
60
61/// Format a status message based on success/failure
62pub fn format_status(success: bool, message: &str) -> String {
63    if success {
64        format!("{} {}", icons::SUCCESS.green(), message.green())
65    } else {
66        format!("{} {}", icons::ERROR.red(), message.red())
67    }
68}
69
70/// Format elapsed time for display
71pub fn format_elapsed(seconds: u64) -> String {
72    if seconds < 60 {
73        format!("{}s", seconds)
74    } else {
75        let mins = seconds / 60;
76        let secs = seconds % 60;
77        format!("{}m {}s", mins, secs)
78    }
79}
80
81/// Format a thinking/reasoning message
82pub fn format_thinking(subject: &str) -> String {
83    format!(
84        "{} {}",
85        icons::THINKING,
86        subject.cyan().italic()
87    )
88}
89
90/// Format an info message
91pub fn format_info(message: &str) -> String {
92    format!("{} {}", icons::ARROW.cyan(), message)
93}
94
95/// Format a warning message
96pub fn format_warning(message: &str) -> String {
97    format!("⚠ {}", message.yellow())
98}
99
100/// Format an error message
101pub fn format_error(message: &str) -> String {
102    format!("{} {}", icons::ERROR.red(), message.red())
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_format_elapsed() {
111        assert_eq!(format_elapsed(5), "5s");
112        assert_eq!(format_elapsed(30), "30s");
113        assert_eq!(format_elapsed(65), "1m 5s");
114        assert_eq!(format_elapsed(125), "2m 5s");
115    }
116}