1use comfy_table::{Cell, Color};
2use console::Style;
3use indicatif::ProgressStyle;
4use std::sync::Arc;
5
6pub const DEFAULT_TABLE_WIDTH: u16 = 80;
7
8pub fn terminal_width() -> u16 {
9 terminal_size::terminal_size()
10 .map(|(terminal_size::Width(width), _)| width)
11 .unwrap_or(DEFAULT_TABLE_WIDTH)
12}
13
14pub const SPINNER_TICK_MS: u64 = 80;
15
16const SPINNER_TEMPLATE_COLOR: &str = "{spinner:.green} {msg}";
17const SPINNER_TEMPLATE_PLAIN: &str = "{spinner} {msg}";
18
19const PROGRESS_TEMPLATE_COLOR: &str =
20 "{spinner:.green} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})";
21const PROGRESS_TEMPLATE_PLAIN: &str = "{spinner} [{bar:40}] {bytes}/{total_bytes} ({eta})";
22
23const PROGRESS_CHARS: &str = "█▉▊▋▌▍▎▏ ";
24
25pub fn header_cell(label: &str, color_enabled: bool, fg: Color) -> Cell {
26 let cell = Cell::new(label);
27 if color_enabled { cell.fg(fg) } else { cell }
28}
29
30pub fn make_spinner_style(color_enabled: bool) -> Arc<ProgressStyle> {
31 let template = if color_enabled {
32 SPINNER_TEMPLATE_COLOR
33 } else {
34 SPINNER_TEMPLATE_PLAIN
35 };
36
37 let ticks: &[&str] = if color_enabled {
38 &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", ""]
39 } else {
40 &["-", "\\", "|", "/", "-"]
41 };
42
43 Arc::new(
44 ProgressStyle::with_template(template)
45 .expect("spinner template must be valid")
46 .tick_strings(ticks),
47 )
48}
49
50pub fn make_progress_style(color_enabled: bool) -> Arc<ProgressStyle> {
51 let template = if color_enabled {
52 PROGRESS_TEMPLATE_COLOR
53 } else {
54 PROGRESS_TEMPLATE_PLAIN
55 };
56
57 Arc::new(
58 ProgressStyle::with_template(template)
59 .expect("progress template must be valid")
60 .progress_chars(PROGRESS_CHARS),
61 )
62}
63
64pub fn styled_line(value: bool, icon: &str, msg: &str, style: Style) -> String {
65 if value {
66 let level = style.clone().bold().apply_to(icon);
67 let body = style.apply_to(msg);
68 format!("{level} {body}")
69 } else {
70 format!("{icon} {msg}")
71 }
72}