git_plumber/tui/widget/
scrollable_text.rs1use crate::tui::helpers::render_styled_paragraph_with_scrollbar;
2use ratatui::text::Text;
3
4#[derive(Debug, Clone)]
7pub struct ScrollableTextWidget {
8 text_cache: Option<Text<'static>>,
9 scroll_position: usize,
10 max_scroll: usize,
11}
12
13impl ScrollableTextWidget {
14 pub fn new() -> Self {
16 Self {
17 text_cache: None,
18 scroll_position: 0,
19 max_scroll: 0,
20 }
21 }
22
23 pub fn set_text(&mut self, text: Text<'static>) {
25 self.text_cache = Some(text);
26 self.scroll_position = 0;
28 self.max_scroll = 0;
29 }
30
31 pub fn text(&self) -> Text<'static> {
33 self.text_cache
34 .as_ref()
35 .cloned()
36 .unwrap_or_else(|| Text::from("Loading..."))
37 }
38
39 pub fn scroll_up(&mut self) {
41 self.scroll_position = self.scroll_position.saturating_sub(1);
42 }
43
44 pub fn scroll_down(&mut self) {
46 self.scroll_position = (self.scroll_position + 1).min(self.max_scroll);
47 }
48
49 pub fn scroll_to_top(&mut self) {
51 self.scroll_position = 0;
52 }
53
54 pub fn scroll_to_bottom(&mut self) {
56 self.scroll_position = self.max_scroll;
57 }
58
59 pub fn scroll_position(&self) -> usize {
61 self.scroll_position
62 }
63
64 pub fn render(
66 &mut self,
67 f: &mut ratatui::Frame,
68 area: ratatui::layout::Rect,
69 title: &str,
70 is_focused: bool,
71 ) {
72 let content = self.text();
73
74 let total_lines = content.lines.len();
76 let visible_height = area.height.saturating_sub(2) as usize; self.max_scroll = total_lines.saturating_sub(visible_height);
78
79 render_styled_paragraph_with_scrollbar(
80 f,
81 area,
82 content,
83 self.scroll_position,
84 title,
85 is_focused,
86 );
87 }
88
89 pub fn has_content(&self) -> bool {
91 self.text_cache.is_some()
92 }
93
94 pub fn clear(&mut self) {
96 self.text_cache = None;
97 self.scroll_position = 0;
98 self.max_scroll = 0;
99 }
100}
101
102impl Default for ScrollableTextWidget {
103 fn default() -> Self {
104 Self::new()
105 }
106}