intelli_shell/widgets/
loading.rs1use std::borrow::Cow;
2
3use ratatui::{
4 backend::FromCrossterm,
5 Frame,
6 layout::Rect,
7 style::Style,
8 widgets::{Clear, Paragraph},
9};
10
11use crate::config::Theme;
12
13pub const SPINNER_CHARS: [&str; 10] = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
15
16pub struct LoadingSpinner<'a> {
18 spinner_state: usize,
20 style: Style,
22 message: Option<Cow<'a, str>>,
24}
25
26impl<'a> LoadingSpinner<'a> {
27 pub fn new(theme: &Theme) -> Self {
29 Self {
30 spinner_state: 0,
31 style: Style::from_crossterm(theme.primary),
32 message: None,
33 }
34 }
35
36 pub fn with_message(mut self, message: impl Into<Cow<'a, str>>) -> Self {
38 self.set_message(message);
39 self
40 }
41
42 pub fn set_message(&mut self, message: impl Into<Cow<'a, str>>) {
44 self.message = Some(message.into());
45 }
46
47 pub fn tick(&mut self) {
49 self.spinner_state = (self.spinner_state + 1) % SPINNER_CHARS.len();
50 }
51
52 pub fn render_in(&self, frame: &mut Frame, area: Rect) {
54 let spinner_char = SPINNER_CHARS[self.spinner_state];
55 let loading_text = if let Some(ref msg) = self.message {
56 format!("{spinner_char} {msg}")
57 } else {
58 spinner_char.to_string()
59 };
60
61 let loading_paragraph = Paragraph::new(loading_text).style(self.style);
63
64 frame.render_widget(Clear, area);
66 frame.render_widget(loading_paragraph, area);
67 }
68}