1use std::sync::LazyLock;
2
3use crate::grapheme::StyledGraphemes;
4
5pub static EMPTY_PANE: LazyLock<Pane> = LazyLock::new(|| Pane::new(vec![], 0));
6
7#[derive(Clone)]
8pub struct Pane {
9 layout: Vec<StyledGraphemes>,
12 offset: usize,
15}
16
17impl Pane {
18 pub fn new(layout: Vec<StyledGraphemes>, offset: usize) -> Self {
22 Pane { layout, offset }
23 }
24
25 pub fn visible_row_count(&self) -> usize {
26 self.layout.len()
27 }
28
29 pub fn is_empty(&self) -> bool {
31 self.layout.is_empty()
32 }
33
34 pub fn extract(&self, viewport_height: usize) -> Vec<StyledGraphemes> {
35 let lines = self.layout.len().min(viewport_height);
36 let mut start = self.offset;
37 let end = self.offset + lines;
38 if end > self.layout.len() {
39 start = self.layout.len().saturating_sub(lines);
40 }
41
42 self.layout
43 .iter()
44 .enumerate()
45 .filter(|(i, _)| start <= *i && *i < end)
46 .map(|(_, row)| row.clone())
47 .collect::<Vec<_>>()
48 }
49}
50
51#[cfg(test)]
52mod test {
53 use super::*;
54
55 mod visible_row_count {
56 use super::*;
57
58 #[test]
59 fn test() {
60 let pane = Pane::new(vec![], 0);
61 assert_eq!(0, pane.visible_row_count())
62 }
63 }
64
65 mod is_empty {
66 use super::*;
67
68 #[test]
69 fn test() {
70 assert_eq!(
71 true,
72 Pane {
73 layout: StyledGraphemes::from("").matrixify(10, 10, 0).0,
74 offset: 0,
75 }
76 .is_empty()
77 );
78 }
79 }
80 mod extract {
81 use super::*;
82
83 #[test]
84 fn test_with_less_extraction_size_than_layout() {
85 let expect = vec![
86 StyledGraphemes::from("aa"),
87 StyledGraphemes::from("bb"),
88 StyledGraphemes::from("cc"),
89 ];
90 assert_eq!(
91 expect,
92 Pane {
93 layout: vec![
94 StyledGraphemes::from("aa"),
95 StyledGraphemes::from("bb"),
96 StyledGraphemes::from("cc"),
97 StyledGraphemes::from("dd"),
98 StyledGraphemes::from("ee"),
99 ],
100 offset: 0,
101 }
102 .extract(3)
103 );
104 }
105
106 #[test]
107 fn test_with_much_extraction_size_than_layout() {
108 let expect = vec![
109 StyledGraphemes::from("aa"),
110 StyledGraphemes::from("bb"),
111 StyledGraphemes::from("cc"),
112 StyledGraphemes::from("dd"),
113 StyledGraphemes::from("ee"),
114 ];
115 assert_eq!(
116 expect,
117 Pane {
118 layout: vec![
119 StyledGraphemes::from("aa"),
120 StyledGraphemes::from("bb"),
121 StyledGraphemes::from("cc"),
122 StyledGraphemes::from("dd"),
123 StyledGraphemes::from("ee"),
124 ],
125 offset: 0,
126 }
127 .extract(10)
128 );
129 }
130
131 #[test]
132 fn test_with_within_extraction_size_and_offset_non_zero() {
133 let expect = vec![StyledGraphemes::from("cc"), StyledGraphemes::from("dd")];
134 assert_eq!(
135 expect,
136 Pane {
137 layout: vec![
138 StyledGraphemes::from("aa"),
139 StyledGraphemes::from("bb"),
140 StyledGraphemes::from("cc"),
141 StyledGraphemes::from("dd"),
142 StyledGraphemes::from("ee"),
143 ],
144 offset: 2, }
146 .extract(2)
147 );
148 }
149
150 #[test]
151 fn test_with_beyond_extraction_size_and_offset_non_zero() {
152 let expect = vec![
153 StyledGraphemes::from("cc"),
154 StyledGraphemes::from("dd"),
155 StyledGraphemes::from("ee"),
156 ];
157 assert_eq!(
158 expect,
159 Pane {
160 layout: vec![
161 StyledGraphemes::from("aa"),
162 StyledGraphemes::from("bb"),
163 StyledGraphemes::from("cc"),
164 StyledGraphemes::from("dd"),
165 StyledGraphemes::from("ee"),
166 ],
167 offset: 3, }
169 .extract(3)
170 );
171 }
172 }
173}