1use std::sync::Arc;
9
10use crate::console::{Console, ConsoleOptions, Justify, Overflow};
11use crate::measure::Measurement;
12use crate::protocol::Renderable;
13use crate::segment::Segment;
14use crate::style::StyleType;
15use crate::text::Text;
16
17#[derive(Clone, Default)]
20pub struct Renderables {
21 renderables: Vec<Arc<dyn Renderable + Send + Sync>>,
22}
23
24impl Renderables {
25 pub fn new(renderables: Vec<Arc<dyn Renderable + Send + Sync>>) -> Self {
27 Renderables { renderables }
28 }
29
30 pub fn append(&mut self, renderable: Arc<dyn Renderable + Send + Sync>) {
32 self.renderables.push(renderable);
33 }
34
35 pub fn renderables(&self) -> &[Arc<dyn Renderable + Send + Sync>] {
37 &self.renderables
38 }
39}
40
41impl Renderable for Renderables {
42 fn rich_render(&self, console: &Console, options: &ConsoleOptions) -> Vec<Segment> {
48 let options = options.reset_height();
49 let mut segments: Vec<Segment> = Vec::new();
50 let mut first = true;
51 for renderable in &self.renderables {
52 let rendered = console.render(renderable.as_ref(), Some(&options));
53 if rendered.is_empty() {
54 continue;
55 }
56 if !first {
57 segments.push(Segment::line());
58 }
59 first = false;
60 segments.extend(rendered);
61 }
62 segments
63 }
64
65 fn measure(&self, console: &Console, options: &ConsoleOptions) -> Measurement {
68 let dimensions: Vec<Measurement> = self
69 .renderables
70 .iter()
71 .map(|renderable| Measurement::get(console, options, renderable.as_ref()))
72 .collect();
73 if dimensions.is_empty() {
74 return Measurement::new(1, 1);
75 }
76 Measurement::new(
77 dimensions.iter().map(|d| d.minimum).max().unwrap_or(0),
78 dimensions.iter().map(|d| d.maximum).max().unwrap_or(0),
79 )
80 }
81}
82
83#[derive(Clone, Debug, Default)]
86pub struct Lines {
87 lines: Vec<Text>,
88}
89
90impl Lines {
91 pub fn new(lines: Vec<Text>) -> Self {
93 Lines { lines }
94 }
95
96 pub fn lines(&self) -> &[Text] {
98 &self.lines
99 }
100
101 pub fn lines_mut(&mut self) -> &mut Vec<Text> {
103 &mut self.lines
104 }
105
106 pub fn len(&self) -> usize {
108 self.lines.len()
109 }
110
111 pub fn is_empty(&self) -> bool {
113 self.lines.is_empty()
114 }
115
116 pub fn append(&mut self, line: Text) {
118 self.lines.push(line);
119 }
120
121 pub fn extend(&mut self, lines: impl IntoIterator<Item = Text>) {
123 self.lines.extend(lines);
124 }
125
126 pub fn pop(&mut self, index: Option<usize>) -> Option<Text> {
129 match index {
130 None => self.lines.pop(),
131 Some(index) if index < self.lines.len() => Some(self.lines.remove(index)),
132 Some(_) => None,
133 }
134 }
135
136 pub fn justify(
142 &mut self,
143 console: &Console,
144 width: usize,
145 justify: Justify,
146 overflow: Overflow,
147 ) {
148 let cells = |line: &Text| crate::cells::cell_len(line.plain());
149 match justify {
150 Justify::Left => {
151 for line in &mut self.lines {
152 line.truncate(width, Some(overflow), true);
153 }
154 }
155 Justify::Center => {
156 for line in &mut self.lines {
157 line.rstrip();
158 line.truncate(width, Some(overflow), false);
159 line.pad_left(width.saturating_sub(cells(line)) / 2, ' ');
160 line.pad_right(width.saturating_sub(cells(line)), ' ');
161 }
162 }
163 Justify::Right => {
164 for line in &mut self.lines {
165 line.rstrip();
166 line.truncate(width, Some(overflow), false);
167 line.pad_left(width.saturating_sub(cells(line)), ' ');
168 }
169 }
170 Justify::Full => {
171 let last = self.lines.len().saturating_sub(1);
172 for line_index in 0..last {
173 let line = &self.lines[line_index];
174 let words = line.split(" ", false, false);
175 let words_size: usize = words.iter().map(cells).sum();
176 let mut num_spaces = words.len().saturating_sub(1);
177 let mut spaces = vec![1usize; num_spaces];
178 let mut index = 0;
179 if !spaces.is_empty() {
180 while words_size + num_spaces < width {
181 let slot = spaces.len() - index - 1;
182 spaces[slot] += 1;
183 num_spaces += 1;
184 index = (index + 1) % spaces.len();
185 }
186 }
187 let mut tokens: Vec<Text> = Vec::with_capacity(words.len() * 2);
188 for (index, word) in words.iter().enumerate() {
189 tokens.push(word.clone());
190 if index < spaces.len() {
191 let style = word.get_style_at_offset(console, -1);
192 let next_style = words[index + 1].get_style_at_offset(console, 0);
193 let space_style: StyleType = if style == next_style {
194 style.into()
195 } else {
196 line.base_style().clone()
197 };
198 tokens.push(Text::styled(" ".repeat(spaces[index]), space_style));
199 }
200 }
201 self.lines[line_index] = Text::new("").join(&tokens);
202 }
203 }
204 Justify::Default => {}
205 }
206 }
207}
208
209impl std::ops::Index<usize> for Lines {
210 type Output = Text;
211
212 fn index(&self, index: usize) -> &Text {
213 &self.lines[index]
214 }
215}
216
217impl std::ops::IndexMut<usize> for Lines {
218 fn index_mut(&mut self, index: usize) -> &mut Text {
219 &mut self.lines[index]
220 }
221}
222
223impl IntoIterator for Lines {
224 type Item = Text;
225 type IntoIter = std::vec::IntoIter<Text>;
226
227 fn into_iter(self) -> Self::IntoIter {
228 self.lines.into_iter()
229 }
230}
231
232impl<'a> IntoIterator for &'a Lines {
233 type Item = &'a Text;
234 type IntoIter = std::slice::Iter<'a, Text>;
235
236 fn into_iter(self) -> Self::IntoIter {
237 self.lines.iter()
238 }
239}
240
241impl Renderable for Lines {
242 fn rich_render(&self, console: &Console, options: &ConsoleOptions) -> Vec<Segment> {
244 let renderables: Vec<Arc<dyn Renderable + Send + Sync>> = self
245 .lines
246 .iter()
247 .map(|line| Arc::new(line.clone()) as Arc<dyn Renderable + Send + Sync>)
248 .collect();
249 Renderables::new(renderables).rich_render(console, options)
250 }
251}