1use crate::models::DisplayItem;
2use crate::ui::markdown_streamer::MarkdownStreamer;
3use std::io::Write;
4
5pub struct LiveDisplay {
6 engine: MarkdownStreamer,
7 last_rendered_tail: String,
8 has_started_content: bool,
9 last_status_len: usize,
10 width: u16,
11}
12
13impl LiveDisplay {
14 pub fn new(width: u16) -> Self {
15 let mut engine = MarkdownStreamer::new();
16 engine.set_width(width as usize);
17 engine.set_margin(2);
18 Self {
19 engine,
20 last_rendered_tail: String::new(),
21 has_started_content: false,
22 last_status_len: 0,
23 width,
24 }
25 }
26
27 pub fn update_status(&mut self, text: &str) {
28 if self.has_started_content {
29 return;
30 }
31 let width = self.width as usize;
32 let limit = width.saturating_sub(10);
33
34 let truncated_owned: String;
35 let truncated = if text.chars().count() > limit {
36 truncated_owned = text.chars().take(limit).collect();
37 &truncated_owned
38 } else {
39 text
40 };
41
42 let mut stdout = std::io::stdout();
43 let _ = write!(stdout, "\r{}\r", " ".repeat(self.last_status_len));
45
46 let status = format!("\x1b[2m{}...\x1b[0m", truncated);
47 let _ = write!(stdout, "{}", status);
48 let _ = stdout.flush();
49 self.last_status_len = truncated.chars().count() + 3;
50 }
51
52 pub fn render(&mut self, items: &[DisplayItem]) {
53 if items.is_empty() {
54 return;
55 }
56
57 if !self.has_started_content {
58 self.has_started_content = true;
59 let mut stdout = std::io::stdout();
60 let _ = write!(stdout, "\r{}\r", " ".repeat(self.last_status_len));
62 let _ = stdout.flush();
63 }
64
65 let mut stdout = std::io::stdout();
66
67 for item in items {
68 match item {
69 DisplayItem::Markdown(m) => {
70 let to_print = if m.starts_with(&self.last_rendered_tail)
73 && !self.last_rendered_tail.is_empty()
74 {
75 &m[self.last_rendered_tail.len()..]
76 } else {
77 m.as_str()
78 };
79
80 if !to_print.is_empty() {
81 let _ = self.engine.print_chunk(&mut stdout, to_print);
82 }
83 self.last_rendered_tail = m.clone();
84 }
85 DisplayItem::Diff(d) => {
86 let _ = self.engine.print_chunk(&mut stdout, "\n~~~~~diff\n");
87 let _ = self.engine.print_chunk(&mut stdout, d);
88 let _ = self.engine.print_chunk(&mut stdout, "\n~~~~~\n");
89 self.last_rendered_tail.clear();
91 }
92 }
93 }
94 let _ = stdout.flush();
95 }
96
97 pub fn finish(&mut self, items: &[DisplayItem]) {
98 self.render(items);
101
102 let mut stdout = std::io::stdout();
103 let _ = self.engine.flush(&mut stdout);
104 let _ = stdout.flush();
105 }
106}