modern_terminal/core/
segment.rs1#[derive(Clone, Debug)]
2pub enum SegmentPortion {
3 Style(crate::core::style::Style),
4 Text(String),
5}
6
7#[derive(Clone, Copy, Debug, PartialEq)]
8pub enum SegmentPadding {
9 Center(usize),
10 Left(usize),
11 None,
12 Right(usize),
13}
14
15#[derive(Clone, Debug)]
16pub struct Segment {
17 pub portions: Vec<SegmentPortion>,
18}
19
20pub type RenderedSegment = String;
21pub type RenderedSegments = Vec<RenderedSegment>;
22
23impl Segment {
24 pub fn new() -> Segment {
25 Segment { portions: vec![] }
26 }
27
28 pub fn add_text(
29 &mut self,
30 text: &str,
31 ) {
32 self.portions.push(SegmentPortion::Text(String::from(text)));
33 }
34
35 pub fn add_style(
36 &mut self,
37 style: crate::core::style::Style,
38 ) {
39 self.portions.push(SegmentPortion::Style(style));
40 }
41
42 pub fn render(
43 &self,
44 padding: SegmentPadding,
45 storage: Option<crate::core::color::storage::Storage>,
46 ) -> String {
47 let mut rendered = String::new();
48
49 let rendered_length: usize = self
50 .portions
51 .iter()
52 .map(|portion| match portion {
53 SegmentPortion::Text(text) => text.len(),
54 SegmentPortion::Style(_) => 0,
55 })
56 .sum();
57
58 match padding {
59 SegmentPadding::Center(desired_length) => {
60 if desired_length > rendered_length {
61 rendered.push_str(&whitespace(
62 (desired_length - rendered_length) / 2,
63 ));
64 };
65 },
66 SegmentPadding::Right(desired_length) => {
67 if desired_length > rendered_length {
68 rendered.push_str(&whitespace(
69 desired_length - rendered_length,
70 ));
71 }
72 },
73 _ => {},
74 };
75
76 for portion in self.portions.iter() {
77 match portion {
78 SegmentPortion::Text(text) => {
79 rendered.push_str(&text);
80 },
81 SegmentPortion::Style(style) => match storage {
82 Some(storage) => {
83 rendered.push_str(&style.ansi_escape_code(storage));
84 },
85 None => {},
86 },
87 }
88 }
89
90 match storage {
91 Some(storage) => rendered.push_str(
92 &crate::core::style::Style::None.ansi_escape_code(storage),
93 ),
94 None => (),
95 };
96
97 match padding {
98 SegmentPadding::Left(desired_length) => {
99 if desired_length > rendered_length {
100 rendered.push_str(&whitespace(
101 desired_length - rendered_length,
102 ));
103 }
104 },
105 SegmentPadding::Center(desired_length) => {
106 if desired_length > rendered_length {
107 rendered.push_str(&whitespace(
108 desired_length
109 - rendered_length
110 - (desired_length - rendered_length) / 2,
111 ));
112 }
113 },
114 _ => {},
115 }
116
117 rendered
118 }
119}
120
121fn whitespace(length: usize) -> String {
122 std::iter::repeat(" ").take(length).collect::<String>()
123}
124
125#[cfg(test)]
126mod test_segment {
127 use super::{Segment, SegmentPadding};
128
129 #[test]
130 fn new() {
131 let mut segment = Segment::new();
132 segment.add_style(crate::core::style::Style::Bold);
133 segment.add_text("a b c d");
134
135 assert_eq!(segment.render(SegmentPadding::None, None), "a b c d");
136 assert_eq!(segment.render(SegmentPadding::Center(8), None), "a b c d ");
137 assert_eq!(segment.render(SegmentPadding::Left(8), None), "a b c d ");
138 assert_eq!(segment.render(SegmentPadding::Right(8), None), " a b c d");
139 assert_eq!(
140 segment.render(
141 SegmentPadding::Center(9),
142 Some(crate::core::color::storage::Storage::Bits24)
143 ),
144 " \u{1b}[1ma b c d\u{1b}[0m "
145 );
146 }
147}