1use crate::console::{Console, ConsoleOptions};
9use crate::protocol::Renderable;
10use crate::segment::Segment;
11use crate::spinner::Spinner;
12use crate::style::Style;
13
14pub struct Status {
16 message: String,
17 spinner: String,
18 spinner_style: Style,
19 speed: f64,
20}
21
22impl Status {
23 pub fn new(message: impl Into<String>) -> Self {
25 Status {
26 message: message.into(),
27 spinner: "dots".to_string(),
28 spinner_style: Style::parse("green").expect("valid built-in style"),
29 speed: 1.0,
30 }
31 }
32
33 pub fn spinner(mut self, name: impl Into<String>) -> Self {
35 self.spinner = name.into();
36 self
37 }
38
39 pub fn spinner_style(mut self, style: Style) -> Self {
41 self.spinner_style = style;
42 self
43 }
44
45 pub fn speed(mut self, speed: f64) -> Self {
47 self.speed = speed;
48 self
49 }
50
51 pub fn renderable(&self) -> Spinner {
53 Spinner::new(&self.spinner)
54 .text(&self.message)
55 .style(self.spinner_style.clone())
56 .speed(self.speed)
57 }
58}
59
60impl Renderable for Status {
61 fn rich_render(&self, console: &Console, options: &ConsoleOptions) -> Vec<Segment> {
62 self.renderable().render(0.0).rich_render(console, options)
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::color::ColorSystem;
71
72 fn render(status: &Status) -> String {
73 Console::builder()
74 .force_terminal(true)
75 .color_system(Some(ColorSystem::Truecolor))
76 .width(30)
77 .no_color(false)
78 .build()
79 .render_to_string(status)
80 }
81
82 #[test]
83 fn default_status_frame() {
84 assert_eq!(
86 render(&Status::new("Loading data")),
87 "\x1b[32m⠋\x1b[0m Loading data"
88 );
89 }
90
91 #[test]
92 fn custom_spinner() {
93 assert_eq!(
94 render(&Status::new("Building").spinner("line")),
95 "\x1b[32m-\x1b[0m Building"
96 );
97 }
98}