1use std::io::{self, Write};
2
3use crate::{
4 Pane,
5 crossterm::{cursor, style, terminal},
6};
7
8pub struct Terminal {
9 pub position: (u16, u16),
11}
12
13impl Terminal {
14 pub fn draw(&mut self, panes: &[Pane]) -> anyhow::Result<()> {
15 let height = terminal::size()?.1;
16
17 let viewable_panes = panes
18 .iter()
19 .filter(|pane| !pane.is_empty())
20 .collect::<Vec<&Pane>>();
21
22 if height < viewable_panes.len() as u16 {
23 return Err(anyhow::anyhow!("Insufficient space to display all panes"));
24 }
25
26 crossterm::queue!(
27 io::stdout(),
28 cursor::MoveTo(self.position.0, self.position.1),
29 terminal::Clear(terminal::ClearType::FromCursorDown),
30 )?;
31
32 let mut used = 0;
33
34 let mut remaining_lines = height.saturating_sub(self.position.1);
35
36 for (pane_index, pane) in viewable_panes.iter().enumerate() {
37 let max_rows = 1.max(
39 (height as usize).saturating_sub(used + viewable_panes.len() - 1 - pane_index),
40 );
41
42 let rows = pane.extract(max_rows);
43 used += rows.len();
44
45 for (row_index, row) in rows.iter().enumerate() {
46 crossterm::queue!(io::stdout(), style::Print(row.styled_display()))?;
47
48 remaining_lines = remaining_lines.saturating_sub(1);
49
50 let is_last_pane = pane_index == viewable_panes.len() - 1;
54 let is_last_row_in_pane = row_index == rows.len() - 1;
55 let has_more_content = !(is_last_pane && is_last_row_in_pane);
56
57 if has_more_content && remaining_lines == 0 {
58 crossterm::queue!(io::stdout(), terminal::ScrollUp(1))?;
59 self.position.1 = self.position.1.saturating_sub(1);
60 }
61
62 crossterm::queue!(io::stdout(), cursor::MoveToNextLine(1))?;
63 }
64 }
65 io::stdout().flush()?;
66 Ok(())
67 }
68}