cascade_cli/cli/
output.rs1use console::{style, Color, Emoji, Style};
2use std::fmt::Display;
3
4struct Theme;
7
8impl Theme {
9 const SUCCESS: Color = Color::Green;
11
12 const ERROR: Color = Color::Red;
14
15 const WARNING: Color = Color::Yellow;
17
18 fn info_style() -> Style {
21 Style::new().color256(35) }
23
24 fn tip_style() -> Style {
26 Style::new().color256(35) }
28
29 fn dim_style() -> Style {
31 Style::new().dim()
32 }
33}
34
35pub struct Output;
37
38impl Output {
39 pub fn success<T: Display>(message: T) {
41 println!("{} {}", style("✓").fg(Theme::SUCCESS), message);
42 }
43
44 pub fn error<T: Display>(message: T) {
46 println!("{} {}", style("✗").fg(Theme::ERROR), message);
47 }
48
49 pub fn warning<T: Display>(message: T) {
51 println!("{} {}", style("⚠").fg(Theme::WARNING), message);
52 }
53
54 pub fn info<T: Display>(message: T) {
56 println!("{} {}", Theme::info_style().apply_to("ℹ"), message);
57 }
58
59 pub fn sub_item<T: Display>(message: T) {
61 println!(" {} {}", Theme::dim_style().apply_to("→"), message);
62 }
63
64 pub fn bullet<T: Display>(message: T) {
66 println!(" {} {}", Theme::dim_style().apply_to("•"), message);
67 }
68
69 pub fn section<T: Display>(title: T) {
71 println!("\n{}", style(title).bold().underlined());
72 }
73
74 pub fn tip<T: Display>(message: T) {
76 println!(
77 "{} {}",
78 Theme::tip_style().apply_to("TIP:"),
79 Theme::dim_style().apply_to(message)
80 );
81 }
82
83 pub fn progress<T: Display>(message: T) {
85 println!("{} {}", Theme::info_style().apply_to("→"), message);
86 }
87
88 pub fn divider() {
90 println!("{}", Theme::dim_style().apply_to("─".repeat(50)));
91 }
92
93 pub fn stack_info(
95 name: &str,
96 id: &str,
97 base_branch: &str,
98 working_branch: Option<&str>,
99 is_active: bool,
100 ) {
101 Self::success(format!("Created stack '{name}'"));
102 Self::sub_item(format!("Stack ID: {}", Theme::dim_style().apply_to(id)));
103 Self::sub_item(format!(
104 "Base branch: {}",
105 Theme::info_style().apply_to(base_branch)
106 ));
107
108 if let Some(working) = working_branch {
109 Self::sub_item(format!(
110 "Working branch: {}",
111 Theme::info_style().apply_to(working)
112 ));
113 }
114
115 if is_active {
116 Self::sub_item(format!("Status: {}", style("Active").fg(Theme::SUCCESS)));
117 }
118 }
119
120 pub fn next_steps(steps: &[&str]) {
122 println!();
123 Self::tip("Next steps:");
124 for step in steps {
125 Self::bullet(step);
126 }
127 }
128
129 pub fn command_example<T: Display>(command: T) {
131 println!(" {}", style(command).fg(Theme::WARNING));
132 }
133
134 pub fn check_start<T: Display>(message: T) {
136 println!("\n{} {}", style("🔍").bright(), style(message).bold());
137 }
138
139 pub fn solution<T: Display>(message: T) {
141 println!(" {}: {}", style("Solution").fg(Theme::WARNING), message);
142 }
143
144 pub fn numbered_item<T: Display>(number: usize, message: T) {
146 println!(" {}. {}", Theme::info_style().apply_to(number), message);
147 }
148
149 pub fn spacing() {
151 println!();
152 }
153}
154
155pub struct Emojis;
157
158impl Emojis {
159 pub const SUCCESS: Emoji<'_, '_> = Emoji("✓", "OK");
160 pub const ERROR: Emoji<'_, '_> = Emoji("✗", "ERROR");
161 pub const WARNING: Emoji<'_, '_> = Emoji("⚠", "WARNING");
162 pub const INFO: Emoji<'_, '_> = Emoji("ℹ", "INFO");
163 pub const TIP: Emoji<'_, '_> = Emoji("💡", "TIP");
164 pub const ROCKET: Emoji<'_, '_> = Emoji("🚀", "ROCKET");
165 pub const SEARCH: Emoji<'_, '_> = Emoji("🔍", "SEARCH");
166 pub const UPLOAD: Emoji<'_, '_> = Emoji("📤", "UPLOAD");
167 pub const STACK: Emoji<'_, '_> = Emoji("📊", "STACK");
168}