iota_aws_orchestrator/
display.rs1use std::{
6 fmt::Display,
7 io::{self, Write, stdout},
8};
9
10use crossterm::{
11 cursor::{RestorePosition, SavePosition},
12 style::{Print, PrintStyledContent, Stylize},
13 terminal::{Clear, ClearType},
14};
15use prettytable::format::{self};
16
17use crate::logger;
18
19pub fn header<S: Display>(message: S) {
20 let msg = format!("\n{message}\n");
21 logger::log(&msg);
22 crossterm::execute!(stdout(), PrintStyledContent(msg.green().bold()),).unwrap();
23}
24
25pub fn error<S: Display>(message: S) {
26 let msg = format!("\n{message}\n");
27 logger::log(&msg);
28 crossterm::execute!(stdout(), PrintStyledContent(msg.red().bold()),).unwrap();
29}
30
31pub fn warn<S: Display>(message: S) {
32 let msg = format!("\n{message}\n");
33 logger::log(&msg);
34 crossterm::execute!(stdout(), PrintStyledContent(msg.bold()),).unwrap();
35}
36
37pub fn config<N: Display, V: Display>(name: N, value: V) {
38 logger::log(&format!("{name}: {value}\n"));
39 crossterm::execute!(
40 stdout(),
41 PrintStyledContent(format!("{name}: ").bold()),
42 Print(format!("{value}\n"))
43 )
44 .unwrap();
45}
46
47pub fn confirm<S: Display>(message: S) -> bool {
48 crossterm::execute!(
50 stdout(),
51 PrintStyledContent(format!("{message} ").bold()),
52 Print("[y/N]: ")
53 )
54 .unwrap();
55
56 stdout().flush().unwrap();
58
59 let mut input = String::new();
61 match io::stdin().read_line(&mut input) {
62 Ok(_) => {
63 let normalized = input.trim().to_lowercase();
64 matches!(normalized.as_str(), "y" | "yes")
65 }
66 Err(_) => false,
67 }
68}
69
70pub fn action<S: Display>(message: S) {
71 let msg: String = format!("{message} ... ");
72 logger::log(&msg);
73 crossterm::execute!(stdout(), Print(&msg), SavePosition).unwrap();
74}
75
76pub fn status<S: Display>(status: S) {
77 let msg = format!("[{status}]");
78 logger::log(&msg);
79 crossterm::execute!(
80 stdout(),
81 RestorePosition,
82 SavePosition,
83 Clear(ClearType::UntilNewLine),
84 Print(&msg)
85 )
86 .unwrap();
87}
88
89pub fn done() {
90 logger::log("[Ok]\n");
91 crossterm::execute!(
92 stdout(),
93 RestorePosition,
94 Clear(ClearType::UntilNewLine),
95 Print(format!("[{}]\n", "Ok".green()))
96 )
97 .unwrap();
98}
99
100pub fn newline() {
101 logger::log("\n");
102 crossterm::execute!(stdout(), Print("\n")).unwrap();
103}
104
105pub fn default_table_format() -> format::TableFormat {
107 format::FormatBuilder::new()
108 .separators(
109 &[
110 format::LinePosition::Top,
111 format::LinePosition::Bottom,
112 format::LinePosition::Title,
113 ],
114 format::LineSeparator::new('-', '-', '-', '-'),
115 )
116 .padding(1, 1)
117 .build()
118}
119
120#[cfg(test)]
121mod test {
122 use std::time::Duration;
123
124 use tokio::time::sleep;
125
126 use super::{action, config, done, error, header, newline, warn};
127 use crate::display::status;
128
129 #[tokio::test]
130 #[ignore = "only used to manually check if prints work correctly"]
131 async fn display() {
132 header("This is a header");
133 config("This is a config", 2);
134 action("Running a long function");
135 for i in 0..5 {
136 sleep(Duration::from_secs(1)).await;
137 if i == 2 {
138 warn("This is a warning!");
139 }
140 status(format!("{}/5", i + 1));
141 }
142 done();
143 error("This is an error!");
144 warn("This is a warning!");
145 newline();
146 }
147}