papergrid/records/
cell_info.rs
1use std::{borrow::Cow, cmp::max};
6
7use crate::{
8 records::vec_records::{Cell, CellMut},
9 util::{count_lines, get_lines},
10 width::WidthFunc,
11};
12
13#[derive(Debug, Default)]
15pub struct CellInfo<'a> {
16 text: Cow<'a, str>,
17 width: usize,
18 lines: Vec<StrWithWidth<'a>>,
19 count_lines: usize,
20}
21
22impl<'a> CellInfo<'a> {
23 pub fn new<S, W>(text: S, width_ctrl: W) -> Self
25 where
26 S: Into<Cow<'a, str>>,
27 W: WidthFunc,
28 {
29 create_cell_info(text.into(), width_ctrl)
30 }
31
32 pub fn is_empty(&self) -> bool {
34 self.text.is_empty()
35 }
36}
37
38impl Cell for CellInfo<'_> {
39 fn get_line(&self, i: usize) -> &str {
40 if i == 0 && self.lines.is_empty() {
41 return &self.text;
42 }
43
44 &self.lines[i].text
45 }
46
47 fn count_lines(&self) -> usize {
48 self.count_lines
49 }
50
51 fn width<W>(&self, _: W) -> usize
52 where
53 W: WidthFunc,
54 {
55 self.width
56 }
57
58 fn line_width<W>(&self, i: usize, _: W) -> usize
59 where
60 W: WidthFunc,
61 {
62 if i == 0 && self.lines.is_empty() {
63 return self.width;
64 }
65
66 self.lines[i].width
67 }
68}
69
70impl<'a, T> CellMut<T> for CellInfo<'a>
71where
72 T: Into<Cow<'a, str>>,
73{
74 fn update<W>(&mut self, width_ctrl: W)
75 where
76 W: WidthFunc,
77 {
78 self.width = 0;
79 update_cell_info(self, width_ctrl);
80 }
81
82 fn set<W>(&mut self, text: T, width_ctrl: W)
83 where
84 W: WidthFunc,
85 {
86 let text = text.into();
87 *self = create_cell_info(text, width_ctrl);
88 }
89}
90
91impl AsRef<str> for CellInfo<'_> {
92 fn as_ref(&self) -> &str {
93 &self.text
94 }
95}
96
97impl Clone for CellInfo<'_> {
98 fn clone(&self) -> Self {
99 let mut cell = Self {
100 text: self.text.clone(),
101 width: self.width,
102 lines: vec![StrWithWidth::default(); self.lines.len()],
103 count_lines: self.count_lines,
104 };
105
106 for (i, line) in self.lines.iter().enumerate() {
107 cell.lines[i].width = line.width;
108
109 cell.lines[i].text = match &line.text {
110 Cow::Owned(line) => Cow::Owned(line.clone()),
111 Cow::Borrowed(s) => {
112 let text = unsafe {
119 let text_ptr = self.text.as_ptr();
120 let line_ptr = s.as_ptr();
121 let text_shift = line_ptr as isize - text_ptr as isize;
122
123 let new_text_shifted_ptr = cell.text.as_ptr().offset(text_shift);
124
125 std::str::from_utf8_unchecked(std::slice::from_raw_parts(
126 new_text_shifted_ptr,
127 s.len(),
128 ))
129 };
130
131 Cow::Borrowed(text)
132 }
133 }
134 }
135
136 cell
137 }
138}
139
140#[derive(Debug, Clone, Default)]
141struct StrWithWidth<'a> {
142 text: Cow<'a, str>,
143 width: usize,
144}
145
146impl<'a> StrWithWidth<'a> {
147 fn new(text: Cow<'a, str>, width: usize) -> Self {
148 Self { text, width }
149 }
150}
151
152fn create_cell_info<W>(text: Cow<'_, str>, width_fn: W) -> CellInfo<'_>
153where
154 W: WidthFunc,
155{
156 let mut info = CellInfo {
157 text,
158 count_lines: 1,
159 ..Default::default()
160 };
161
162 let count_lines = count_lines(&info.text);
165 if count_lines < 2 {
166 info.width = width_fn.width(&info.text);
167 return info;
168 }
169
170 let text = unsafe {
180 std::str::from_utf8_unchecked(std::slice::from_raw_parts(
181 info.text.as_ptr(),
182 info.text.len(),
183 ))
184 };
185
186 info.count_lines = count_lines;
187 info.lines = vec![StrWithWidth::new(Cow::Borrowed(""), 0); count_lines];
188 for (line, i) in get_lines(text).zip(info.lines.iter_mut()) {
189 i.width = width_fn.width(line.as_ref());
190 i.text = line;
191 info.width = max(info.width, i.width);
192 }
193
194 info
195}
196
197fn update_cell_info<W>(info: &mut CellInfo<'_>, width_fn: W)
198where
199 W: WidthFunc,
200{
201 if info.text.is_empty() {
202 return;
203 }
204
205 if info.lines.is_empty() && !info.text.is_empty() {
206 info.width = width_fn.width(&info.text);
207 return;
208 }
209
210 for line in &mut info.lines {
211 line.width = width_fn.width(&line.text);
212 info.width = max(info.width, line.width);
213 }
214}