1use ratatui::{
2 buffer::Buffer,
3 layout::Rect,
4 style::{Color, Modifier},
5 widgets::Widget,
6};
7
8pub const BOLD: &str = "\x1b[1m";
11pub const DIM: &str = "\x1b[2m";
12pub const GREEN: &str = "\x1b[32m";
13pub const RED: &str = "\x1b[31m";
14pub const CYAN: &str = "\x1b[36m";
15pub const YELLOW: &str = "\x1b[33m";
16pub const RESET: &str = "\x1b[0m";
17
18pub fn print_widget(widget: impl Widget, height: u16) {
21 let width = ratatui::crossterm::terminal::size().map_or(120, |(w, _)| w);
22 let area = Rect::new(0, 0, width, height);
23 let mut buf = Buffer::empty(area);
24 widget.render(area, &mut buf);
25
26 let mut out = String::new();
27 for y in 0..height {
28 let mut cur_fg = Color::Reset;
29 let mut cur_bg = Color::Reset;
30 let mut cur_mod = Modifier::empty();
31
32 for x in 0..width {
33 let cell = &buf[(x, y)];
34 if cell.skip {
35 continue;
36 }
37
38 if cell.fg != cur_fg || cell.bg != cur_bg || cell.modifier != cur_mod {
39 out.push_str("\x1b[0m");
40 push_ansi_fg(&mut out, cell.fg);
41 push_ansi_bg(&mut out, cell.bg);
42 push_ansi_mod(&mut out, cell.modifier);
43 cur_fg = cell.fg;
44 cur_bg = cell.bg;
45 cur_mod = cell.modifier;
46 }
47
48 out.push_str(cell.symbol());
49 }
50 out.push_str("\x1b[0m\n");
51 }
52
53 print!("{out}");
54}
55
56pub fn push_ansi_fg(out: &mut String, color: Color) {
57 use std::fmt::Write as _;
58 match color {
59 Color::Reset => {}
60 Color::Black => out.push_str("\x1b[30m"),
61 Color::Red => out.push_str("\x1b[31m"),
62 Color::Green => out.push_str("\x1b[32m"),
63 Color::Yellow => out.push_str("\x1b[33m"),
64 Color::Blue => out.push_str("\x1b[34m"),
65 Color::Magenta => out.push_str("\x1b[35m"),
66 Color::Cyan => out.push_str("\x1b[36m"),
67 Color::Gray => out.push_str("\x1b[37m"),
68 Color::DarkGray => out.push_str("\x1b[90m"),
69 Color::LightRed => out.push_str("\x1b[91m"),
70 Color::LightGreen => out.push_str("\x1b[92m"),
71 Color::LightYellow => out.push_str("\x1b[93m"),
72 Color::LightBlue => out.push_str("\x1b[94m"),
73 Color::LightMagenta => out.push_str("\x1b[95m"),
74 Color::LightCyan => out.push_str("\x1b[96m"),
75 Color::White => out.push_str("\x1b[97m"),
76 Color::Rgb(r, g, b) => {
77 let _ = write!(out, "\x1b[38;2;{r};{g};{b}m");
78 }
79 Color::Indexed(i) => {
80 let _ = write!(out, "\x1b[38;5;{i}m");
81 }
82 }
83}
84
85pub fn push_ansi_bg(out: &mut String, color: Color) {
86 use std::fmt::Write as _;
87 match color {
88 Color::Reset => {}
89 Color::Black => out.push_str("\x1b[40m"),
90 Color::Red => out.push_str("\x1b[41m"),
91 Color::Green => out.push_str("\x1b[42m"),
92 Color::Yellow => out.push_str("\x1b[43m"),
93 Color::Blue => out.push_str("\x1b[44m"),
94 Color::Magenta => out.push_str("\x1b[45m"),
95 Color::Cyan => out.push_str("\x1b[46m"),
96 Color::Gray => out.push_str("\x1b[47m"),
97 Color::DarkGray => out.push_str("\x1b[100m"),
98 Color::LightRed => out.push_str("\x1b[101m"),
99 Color::LightGreen => out.push_str("\x1b[102m"),
100 Color::LightYellow => out.push_str("\x1b[103m"),
101 Color::LightBlue => out.push_str("\x1b[104m"),
102 Color::LightMagenta => out.push_str("\x1b[105m"),
103 Color::LightCyan => out.push_str("\x1b[106m"),
104 Color::White => out.push_str("\x1b[107m"),
105 Color::Rgb(r, g, b) => {
106 let _ = write!(out, "\x1b[48;2;{r};{g};{b}m");
107 }
108 Color::Indexed(i) => {
109 let _ = write!(out, "\x1b[48;5;{i}m");
110 }
111 }
112}
113
114pub fn push_ansi_mod(out: &mut String, modifier: Modifier) {
115 if modifier.contains(Modifier::BOLD) {
116 out.push_str("\x1b[1m");
117 }
118 if modifier.contains(Modifier::DIM) {
119 out.push_str("\x1b[2m");
120 }
121 if modifier.contains(Modifier::ITALIC) {
122 out.push_str("\x1b[3m");
123 }
124 if modifier.contains(Modifier::UNDERLINED) {
125 out.push_str("\x1b[4m");
126 }
127 if modifier.contains(Modifier::REVERSED) {
128 out.push_str("\x1b[7m");
129 }
130 if modifier.contains(Modifier::CROSSED_OUT) {
131 out.push_str("\x1b[9m");
132 }
133}
134
135pub fn print_section(title: &str) {
136 let pad = 46usize.saturating_sub(title.len());
137 println!(
138 "\n{DIM}──{RESET} {BOLD}{title}{RESET} {DIM}{}{RESET}",
139 "─".repeat(pad)
140 );
141}