1use std::marker::PhantomData;
2
3use ratatui::{
4 buffer::Buffer,
5 layout::{Constraint, Flex, Layout, Rect},
6 style::{Color, Stylize},
7 text::{Line, Span, Text},
8 widgets::{StatefulWidget, Widget},
9};
10
11#[derive(Default, Clone, PartialEq)]
12pub struct StatusBarState<'a> {
13 active_component_name: &'a str,
14 word_count: usize,
15 char_count: usize,
16}
17
18impl<'a> StatusBarState<'a> {
19 pub fn new(active_component_name: &'a str, word_count: usize, char_count: usize) -> Self {
20 Self {
21 active_component_name,
22 word_count,
23 char_count,
24 }
25 }
26}
27
28#[derive(Default)]
29pub struct StatusBar<'a> {
30 _lifetime: PhantomData<&'a ()>,
31}
32
33impl<'a> StatefulWidget for StatusBar<'a> {
34 type State = StatusBarState<'a>;
35
36 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
37 let [left, right] = Layout::horizontal([Constraint::Fill(1), Constraint::Length(28)])
38 .flex(Flex::SpaceBetween)
39 .areas(area);
40
41 let active_component = [
42 Span::from("").dark_gray(),
43 Span::from(" ").bg(Color::DarkGray),
44 Span::from(state.active_component_name)
45 .dark_gray()
46 .reversed()
47 .bold(),
48 Span::from(" ").bg(Color::DarkGray),
49 Span::from("").dark_gray(),
50 ]
51 .to_vec();
52
53 Text::from(Line::from(active_component)).render(left, buf);
54
55 let [word_count, char_count] =
56 Layout::horizontal([Constraint::Fill(1), Constraint::Fill(1)])
57 .flex(Flex::End)
58 .areas(right);
59
60 Text::from(format!(
61 "{} word{}",
62 state.word_count,
63 if state.word_count == 1 { "" } else { "s" }
64 ))
65 .right_aligned()
66 .render(word_count, buf);
67
68 Text::from(format!(
69 "{} char{}",
70 state.char_count,
71 if state.char_count == 1 { "" } else { "s" }
72 ))
73 .right_aligned()
74 .render(char_count, buf);
75 }
76}