1use owo_colors::OwoColorize;
4
5pub fn header(text: &str) {
7 println!();
8 println!("{}", text.bold().cyan());
9 println!("{}", "─".repeat(text.len()).dimmed());
10 println!();
11}
12
13pub fn logo() {
15 let logo = r#"
16 ██████╗ ██████╗ █████╗ ██╗ ██╗
17 ██╔══██╗██╔══██╗██╔══██╗╚██╗██╔╝
18 ██████╔╝██████╔╝███████║ ╚███╔╝
19 ██╔═══╝ ██╔══██╗██╔══██║ ██╔██╗
20 ██║ ██║ ██║██║ ██║██╔╝ ██╗
21 ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
22 "#;
23 println!("{}", logo.bright_cyan().bold());
24}
25
26pub fn section(text: &str) {
28 println!("{}", text.bold().white());
29}
30
31pub fn kv(key: &str, value: &str) {
33 println!(" {}: {}", key.dimmed(), value);
34}
35
36pub fn success(text: &str) {
38 println!("{} {}", "✔".green().bold(), text.green());
39}
40
41pub fn info(text: &str) {
43 println!("{} {}", "ℹ".blue().bold(), text);
44}
45
46pub fn warn(text: &str) {
48 println!("{} {}", "⚠".yellow().bold(), text.yellow());
49}
50
51pub fn error(text: &str) {
53 eprintln!("{} {}", "✖".red().bold(), text.red());
54}
55
56pub fn step(current: usize, total: usize, text: &str) {
58 println!("{} {}", format!("[{}/{}]", current, total).dimmed(), text);
59}
60
61pub fn list(text: &str) {
63 println!("{}", text);
64}
65
66pub fn list_item(text: &str) {
68 println!(" {} {}", "•".dimmed(), text);
69}
70
71pub fn numbered_item(number: usize, text: &str) {
73 println!(" {}. {}", number.to_string().dimmed(), text);
74}
75
76pub fn newline() {
78 println!();
79}
80
81pub fn dim(text: &str) {
83 println!("{}", text.dimmed());
84}
85
86pub fn code(code: &str, _language: &str) {
88 println!();
89 for line in code.lines() {
90 println!(" {}", line.bright_white());
91 }
92 println!();
93}
94
95pub fn style_success(text: &str) -> String {
97 text.green().to_string()
98}
99
100pub fn style_pending(text: &str) -> String {
102 text.yellow().to_string()
103}
104
105pub fn style_error(text: &str) -> String {
107 text.red().to_string()
108}
109
110pub fn confirm(prompt: &str) -> bool {
112 use std::io::{self, Write};
113
114 print!("{} {} ", prompt, "[y/N]".dimmed());
115 io::stdout().flush().ok();
116
117 let mut input = String::new();
118 if io::stdin().read_line(&mut input).is_err() {
119 return false;
120 }
121
122 matches!(input.trim().to_lowercase().as_str(), "y" | "yes")
123}
124
125pub fn input(prompt: &str) -> Option<String> {
127 use std::io::{self, Write};
128
129 print!("{}: ", prompt);
130 io::stdout().flush().ok();
131
132 let mut input = String::new();
133 if io::stdin().read_line(&mut input).is_err() {
134 return None;
135 }
136
137 let trimmed = input.trim();
138 if trimmed.is_empty() {
139 None
140 } else {
141 Some(trimmed.to_string())
142 }
143}
144
145pub fn select(prompt: &str, options: &[&str]) -> Option<usize> {
147 use std::io::{self, Write};
148
149 println!("{}", prompt);
150 for (i, option) in options.iter().enumerate() {
151 println!(" {} {}", format!("{})", i + 1).dimmed(), option);
152 }
153
154 print!("{}: ", "Select".dimmed());
155 io::stdout().flush().ok();
156
157 let mut input = String::new();
158 if io::stdin().read_line(&mut input).is_err() {
159 return None;
160 }
161
162 input
163 .trim()
164 .parse::<usize>()
165 .ok()
166 .filter(|&n| n > 0 && n <= options.len())
167 .map(|n| n - 1)
168}