Go · 5466 bytes Raw Blame History
1 package colors
2
3 import (
4 "fmt"
5 "os"
6 "strings"
7 )
8
9 // ANSI color codes
10 const (
11 Reset = "\033[0m"
12 Bold = "\033[1m"
13 Dim = "\033[2m"
14
15 // Regular colors
16 Red = "\033[31m"
17 Green = "\033[32m"
18 Yellow = "\033[33m"
19 Blue = "\033[34m"
20 Magenta = "\033[35m"
21 Cyan = "\033[36m"
22 White = "\033[37m"
23
24 // Bright colors
25 BrightRed = "\033[91m"
26 BrightGreen = "\033[92m"
27 BrightYellow = "\033[93m"
28 BrightBlue = "\033[94m"
29 BrightMagenta = "\033[95m"
30 BrightCyan = "\033[96m"
31 BrightWhite = "\033[97m"
32 )
33
34 // ParrotStyle represents different visual styles for parrot output
35 type ParrotStyle struct {
36 Parrot string // Color for the parrot emoji/prefix
37 Response string // Color for the response text
38 Accent string // Color for emphasis
39 }
40
41 // Predefined styles for different personalities
42 var Styles = map[string]ParrotStyle{
43 "mild": {
44 Parrot: BrightBlue,
45 Response: Blue,
46 Accent: BrightCyan,
47 },
48 "sarcastic": {
49 Parrot: BrightYellow,
50 Response: Yellow,
51 Accent: BrightMagenta,
52 },
53 "savage": {
54 Parrot: BrightRed,
55 Response: Red,
56 Accent: BrightYellow,
57 },
58 "default": {
59 Parrot: BrightGreen,
60 Response: Green,
61 Accent: BrightCyan,
62 },
63 }
64
65 // ColorEnabled checks if color output should be enabled
66 func ColorEnabled() bool {
67 // Disable colors if NO_COLOR is set
68 if os.Getenv("NO_COLOR") != "" {
69 return false
70 }
71
72 // Disable colors if not a terminal
73 if os.Getenv("TERM") == "dumb" {
74 return false
75 }
76
77 // Check if stdout is a terminal (simplified check)
78 stat, err := os.Stdout.Stat()
79 if err != nil {
80 return false
81 }
82
83 // Check if it's a character device (terminal)
84 return (stat.Mode() & os.ModeCharDevice) != 0
85 }
86
87 // Colorize adds color to text if colors are enabled
88 func Colorize(color, text string) string {
89 if !ColorEnabled() {
90 return text
91 }
92 return color + text + Reset
93 }
94
95 // FormatParrotOutput formats the parrot response with personality-based colors
96 func FormatParrotOutput(personality, response string, enhanced bool) string {
97 if !ColorEnabled() {
98 return fmt.Sprintf("🦜 %s", response)
99 }
100
101 style, exists := Styles[personality]
102 if !exists {
103 style = Styles["default"]
104 }
105
106 if enhanced {
107 return formatEnhancedOutput(style, response)
108 }
109
110 // Simple colored output
111 parrotEmoji := Colorize(style.Parrot, "🦜")
112 coloredResponse := Colorize(style.Response, response)
113
114 return fmt.Sprintf("%s %s", parrotEmoji, coloredResponse)
115 }
116
117 // formatEnhancedOutput creates fancy formatted output with personality-specific styling
118 func formatEnhancedOutput(style ParrotStyle, response string) string {
119 var output strings.Builder
120
121 // Fancy parrot prefix with personality
122 parrotPrefix := Colorize(style.Parrot, "🦜 ▶")
123
124 // Add some visual flair based on personality
125 border := Colorize(style.Accent, "━")
126
127 // Format the response with potential emphasis
128 coloredResponse := enhanceResponseText(style, response)
129
130 output.WriteString(fmt.Sprintf("%s %s %s", border, parrotPrefix, coloredResponse))
131
132 return output.String()
133 }
134
135 // enhanceResponseText adds emphasis to certain words in responses
136 func enhanceResponseText(style ParrotStyle, response string) string {
137 if !ColorEnabled() {
138 return response
139 }
140
141 // Words to emphasize for extra sass
142 emphasisWords := []string{
143 "failed", "error", "disaster", "incompetent", "broken",
144 "genius", "classic", "impressive", "amazing", "brilliant",
145 "404", "rejected", "crashed", "destroyed",
146 }
147
148 result := response
149 for _, word := range emphasisWords {
150 // Case-insensitive replacement with emphasis
151 lowerWord := strings.ToLower(word)
152 if strings.Contains(strings.ToLower(result), lowerWord) {
153 // Find and replace with emphasized version
154 result = replaceWordWithEmphasis(result, word, style.Accent)
155 }
156 }
157
158 // Color the main response
159 return Colorize(style.Response, result)
160 }
161
162 // replaceWordWithEmphasis replaces words with emphasized versions (case-insensitive)
163 func replaceWordWithEmphasis(text, word, accentColor string) string {
164 words := strings.Fields(text)
165 for i, w := range words {
166 // Remove punctuation for comparison
167 cleanWord := strings.Trim(strings.ToLower(w), ".,!?;:")
168 if cleanWord == strings.ToLower(word) {
169 // Keep original punctuation, but emphasize the word
170 punctuation := ""
171 if len(w) > len(cleanWord) {
172 punctuation = w[len(w)-1:]
173 }
174 words[i] = Colorize(accentColor+Bold, strings.ToUpper(word)) + punctuation + Reset
175 }
176 }
177 return strings.Join(words, " ")
178 }
179
180 // GetAvailableStyles returns list of available color styles
181 func GetAvailableStyles() []string {
182 styles := make([]string, 0, len(Styles))
183 for style := range Styles {
184 if style != "default" {
185 styles = append(styles, style)
186 }
187 }
188 return styles
189 }
190
191 // Demo shows color samples for all personalities
192 func Demo() {
193 fmt.Println("🎨 Parrot Color Demo")
194 fmt.Println("━━━━━━━━━━━━━━━━━━━")
195
196 responses := map[string]string{
197 "mild": "Git command failed. Maybe check your remote branch?",
198 "sarcastic": "Git good? More like git wrecked!",
199 "savage": "Your git skills are as non-existent as your social life.",
200 }
201
202 for personality, response := range responses {
203 fmt.Printf("\n%s personality:\n", strings.Title(personality))
204 fmt.Printf(" Simple: %s\n", FormatParrotOutput(personality, response, false))
205 fmt.Printf(" Enhanced: %s\n", FormatParrotOutput(personality, response, true))
206 }
207
208 fmt.Printf("\nColors enabled: %t\n", ColorEnabled())
209 }