view/
view_line.rs

1use display::DisplayColor;
2
3use super::LineSegment;
4
5/// Represents a line in the view.
6#[derive(Debug)]
7pub struct ViewLine {
8	pinned_segments: usize,
9	segments: Vec<LineSegment>,
10	selected: bool,
11	padding: Option<LineSegment>,
12}
13
14impl ViewLine {
15	/// Create a new instance that contains no content.
16	#[must_use]
17	#[inline]
18	pub fn new_empty_line() -> Self {
19		Self::new_with_pinned_segments(vec![], 1)
20	}
21
22	/// Create a new instance with all segments pinned.
23	#[must_use]
24	#[inline]
25	pub fn new_pinned(segments: Vec<LineSegment>) -> Self {
26		let segments_length = segments.len();
27		Self::new_with_pinned_segments(segments, segments_length)
28	}
29
30	/// Create a new instance with a number of pinned leading segments.
31	#[must_use]
32	#[inline]
33	pub fn new_with_pinned_segments(segments: Vec<LineSegment>, pinned_segments: usize) -> Self {
34		Self {
35			selected: false,
36			segments,
37			pinned_segments,
38			padding: None,
39		}
40	}
41
42	/// Set that this line is selected.
43	#[must_use]
44	#[inline]
45	pub const fn set_selected(mut self, selected: bool) -> Self {
46		self.selected = selected;
47		self
48	}
49
50	/// Set a padding character.
51	#[must_use]
52	#[inline]
53	pub fn set_padding(mut self, c: char) -> Self {
54		self.padding = Some(LineSegment::new(String::from(c).as_str()));
55		self
56	}
57
58	/// Set the padding character with a related color and style.
59	#[must_use]
60	#[inline]
61	pub fn set_padding_with_color_and_style(
62		mut self,
63		c: char,
64		color: DisplayColor,
65		dim: bool,
66		underline: bool,
67		reverse: bool,
68	) -> Self {
69		self.padding = Some(LineSegment::new_with_color_and_style(
70			String::from(c).as_str(),
71			color,
72			dim,
73			underline,
74			reverse,
75		));
76		self
77	}
78
79	/// Get the number of pinned line segments.
80	#[must_use]
81	#[inline]
82	pub const fn get_number_of_pinned_segment(&self) -> usize {
83		self.pinned_segments
84	}
85
86	/// Get the view line segments.
87	#[must_use]
88	#[inline]
89	pub const fn get_segments(&self) -> &Vec<LineSegment> {
90		&self.segments
91	}
92
93	/// Is the line selected.
94	#[must_use]
95	#[inline]
96	pub const fn get_selected(&self) -> bool {
97		self.selected
98	}
99
100	pub(crate) const fn get_padding(&self) -> &Option<LineSegment> {
101		&self.padding
102	}
103}
104
105impl From<&str> for ViewLine {
106	#[inline]
107	fn from(line: &str) -> Self {
108		Self::from(LineSegment::new(line))
109	}
110}
111
112impl From<String> for ViewLine {
113	#[inline]
114	fn from(line: String) -> Self {
115		Self::from(LineSegment::new(line.as_str()))
116	}
117}
118
119impl From<LineSegment> for ViewLine {
120	#[inline]
121	fn from(line_segment: LineSegment) -> Self {
122		Self::from(vec![line_segment])
123	}
124}
125
126impl From<Vec<LineSegment>> for ViewLine {
127	#[inline]
128	fn from(line_segment: Vec<LineSegment>) -> Self {
129		Self::new_with_pinned_segments(line_segment, 0)
130	}
131}
132
133#[cfg(test)]
134mod tests {
135	use super::*;
136
137	#[test]
138	fn from_str() {
139		let view_line = ViewLine::from("foo");
140
141		assert_eq!(view_line.get_number_of_pinned_segment(), 0);
142		assert_eq!(view_line.get_segments().len(), 1);
143		assert_eq!(view_line.get_segments().first().unwrap().get_content(), "foo");
144		assert!(!view_line.get_selected());
145	}
146
147	#[test]
148	fn from_string() {
149		let view_line = ViewLine::from(String::from("foo"));
150
151		assert_eq!(view_line.get_number_of_pinned_segment(), 0);
152		assert_eq!(view_line.get_segments().len(), 1);
153		assert_eq!(view_line.get_segments().first().unwrap().get_content(), "foo");
154		assert!(!view_line.get_selected());
155	}
156
157	#[test]
158	fn from_line_segment() {
159		let view_line = ViewLine::from(LineSegment::new("foo"));
160
161		assert_eq!(view_line.get_number_of_pinned_segment(), 0);
162		assert_eq!(view_line.get_segments().len(), 1);
163		assert_eq!(view_line.get_segments().first().unwrap().get_content(), "foo");
164		assert!(!view_line.get_selected());
165	}
166
167	#[test]
168	fn from_list_line_segment() {
169		let view_line = ViewLine::from(vec![LineSegment::new("foo"), LineSegment::new("bar")]);
170
171		assert_eq!(view_line.get_number_of_pinned_segment(), 0);
172		assert_eq!(view_line.get_segments().len(), 2);
173		assert_eq!(view_line.get_segments().first().unwrap().get_content(), "foo");
174		assert_eq!(view_line.get_segments().last().unwrap().get_content(), "bar");
175		assert!(!view_line.get_selected());
176	}
177
178	#[test]
179	fn new_selected() {
180		let view_line = ViewLine::from(vec![LineSegment::new("foo"), LineSegment::new("bar")]).set_selected(true);
181
182		assert_eq!(view_line.get_number_of_pinned_segment(), 0);
183		assert_eq!(view_line.get_segments().len(), 2);
184		assert!(view_line.get_selected());
185	}
186
187	#[test]
188	fn new_pinned() {
189		let view_line = ViewLine::new_pinned(vec![
190			LineSegment::new("foo"),
191			LineSegment::new("bar"),
192			LineSegment::new("baz"),
193			LineSegment::new("foobar"),
194		]);
195
196		assert_eq!(view_line.get_number_of_pinned_segment(), 4);
197		assert_eq!(view_line.get_segments().len(), 4);
198		assert!(!view_line.get_selected());
199	}
200
201	#[test]
202	fn new_with_pinned_segments() {
203		let view_line = ViewLine::new_with_pinned_segments(
204			vec![
205				LineSegment::new("foo"),
206				LineSegment::new("bar"),
207				LineSegment::new("baz"),
208				LineSegment::new("foobar"),
209			],
210			2,
211		);
212
213		assert_eq!(view_line.get_number_of_pinned_segment(), 2);
214		assert_eq!(view_line.get_segments().len(), 4);
215		assert!(!view_line.get_selected());
216	}
217
218	#[test]
219	fn set_padding_with_color_and_style() {
220		let view_line =
221			ViewLine::from("foo").set_padding_with_color_and_style(' ', DisplayColor::IndicatorColor, true, true, true);
222
223		let padding = view_line.get_padding().as_ref().unwrap();
224		assert_eq!(padding.get_content(), " ");
225		assert_eq!(padding.get_color(), DisplayColor::IndicatorColor);
226		assert!(padding.is_dimmed());
227		assert!(padding.is_underlined());
228		assert!(padding.is_reversed());
229	}
230
231	#[test]
232	fn set_padding() {
233		let view_line = ViewLine::from("foo").set_padding('@');
234
235		assert_eq!(view_line.get_padding().as_ref().unwrap().get_content(), "@");
236	}
237}