1#![allow(unused)]
2
3use super::{
4 window::{Window, WindowOffset},
5 HlId,
6};
7use neophyte_linalg::{CellVec, Vec2};
8use neophyte_ui_event::{grid_line, hl_attr_define::Attributes, Anchor, GridScroll, HlAttrDefine};
9use packed_char::{Contents, PackedChar, U22};
10use std::{
11 collections::HashMap,
12 fmt::{self, Debug, Display, Formatter},
13 io::Write,
14 iter::TakeWhile,
15 marker::PhantomData,
16 mem::transmute,
17 ops::Not,
18 str::Chars,
19 vec::IntoIter,
20};
21
22pub type Id = u32;
23
24#[derive(Debug, Default, Clone)]
25pub struct Grid {
26 pub id: Id,
27 pub scroll_delta: i32,
28 pub dirty: DirtyFlags,
29 window: Window,
30 contents: GridContents,
31}
32
33#[derive(PartialEq, Eq, Debug, Default, Clone, Copy, PartialOrd, Ord)]
34pub struct DirtyFlags(u8);
35
36#[rustfmt::skip]
37impl DirtyFlags {
38 const CONTENTS: u8 = 0b01;
39 const WINDOW: u8 = 0b10;
40}
41
42impl DirtyFlags {
43 pub fn set_contents(&mut self) {
44 self.0 |= Self::CONTENTS
45 }
46
47 pub fn contents(self) -> bool {
48 self.0 & Self::CONTENTS > 0
49 }
50
51 pub fn set_window(&mut self) {
52 self.0 |= Self::WINDOW
53 }
54
55 pub fn window(self) -> bool {
56 self.0 & Self::WINDOW > 0
57 }
58
59 pub fn clear(&mut self) {
60 self.0 = 0;
61 }
62}
63
64impl Grid {
65 pub fn new(id: Id) -> Self {
66 Self {
67 id,
68 ..Default::default()
69 }
70 }
71
72 pub fn contents(&self) -> &GridContents {
73 &self.contents
74 }
75
76 pub fn contents_mut(&mut self) -> &mut GridContents {
77 self.dirty.set_contents();
78 &mut self.contents
79 }
80
81 pub fn window(&self) -> &Window {
82 &self.window
83 }
84
85 pub fn window_mut(&mut self) -> &mut Window {
86 self.dirty.set_window();
87 &mut self.window
88 }
89
90 pub fn clear_dirty(&mut self) {
92 self.dirty.clear();
93 self.scroll_delta = 0;
94 }
95}
96
97#[derive(Default, Clone)]
99pub struct GridContents {
100 pub size: CellVec<u16>,
102 buffer: Vec<Cell>,
104 overflow: Vec<String>,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
111pub struct Cell {
112 pub text: PackedChar,
113 pub highlight: HlId,
114}
115
116impl GridContents {
117 pub fn new() -> Self {
118 Self::default()
119 }
120
121 pub fn resize(&mut self, size: CellVec<u16>) {
123 let mut old = std::mem::take(&mut self.buffer);
124 self.buffer = vec![Cell::default(); size.0.area() as usize];
125 for (new, old) in self
126 .buffer
127 .chunks_mut(size.0.x as usize)
128 .zip(old.chunks(self.size.0.x.max(1) as usize))
129 {
130 for (new, old) in new.iter_mut().zip(old.iter()) {
131 *new = *old;
132 }
133 }
134 self.size = size;
135 }
136
137 pub fn scroll(&mut self, top: u16, bot: u16, left: u16, right: u16, rows: i32) {
139 let left = left as usize;
140 let right = right as usize;
141 let size: Vec2<usize> = self.size.0.cast_as();
142 let dst_top = top as i32 - rows;
143 let dst_bot = bot as i32 - rows;
144 if rows > 0 {
145 let rows = rows as usize;
147 let top = top as usize + rows;
148 let bot = bot as usize;
149 for src_y in top..bot {
150 let dst_y = src_y - rows;
151 let (dst, src) = self.buffer.split_at_mut(src_y * size.x);
152 let dst = &mut dst[dst_y * size.x..];
153 let dst = &mut dst[left..right];
154 let src = &src[left..right];
155 dst.copy_from_slice(src);
156 }
157 } else {
158 let rows = (-rows) as usize;
160 let top = top as usize;
161 let bot = bot as usize - rows;
162 for src_y in (top..bot).rev() {
163 let dst_y = src_y + rows;
164 let (src, dst) = self.buffer.split_at_mut(dst_y * size.x);
165 let src = &src[src_y * size.x..];
166 let src = &src[left..right];
167 let dst = &mut dst[left..right];
168 dst.copy_from_slice(src);
169 }
170 }
171 }
172
173 pub fn grid_line(&mut self, row: u16, col_start: u16, cells: Vec<grid_line::Cell>) {
175 let w = self.size.0.x as usize;
176 let start = row as usize * w;
177 let end = start + w;
178 let mut row = self.buffer[start..end].iter_mut().skip(col_start as usize);
179
180 let mut highlight = 0;
181 for cell in cells {
182 if let Some(hl_id) = cell.hl_id {
183 highlight = hl_id;
184 }
185
186 let repeat = cell.repeat.unwrap_or(1);
187 let mut chars = cell.text.chars();
188 let packed = match (chars.next(), chars.next()) {
189 (None, None) => PackedChar::from_char('\0'),
190 (None, Some(c)) => unreachable!(),
191 (Some(c), None) => PackedChar::from_char(c),
192 (Some(c1), Some(c2)) => {
193 let i = self.overflow.len().try_into().unwrap();
194 self.overflow.push(cell.text);
195 PackedChar::from_u22(U22::from_u32(i).unwrap())
196 }
197 };
198 let cell = Cell {
199 text: packed,
200 highlight,
201 };
202
203 for _ in 0..repeat {
204 *row.next().unwrap() = cell;
205 }
206 }
207 }
208
209 pub fn clear(&mut self) {
211 for dst in self.buffer.iter_mut() {
212 *dst = Cell::default();
213 }
214 }
215
216 pub fn rows(
218 &self,
219 ) -> impl Iterator<Item = impl Iterator<Item = CellContents<'_>> + '_ + Clone> + '_ + Clone
220 {
221 self.buffer.chunks(self.size.0.x as usize).map(|chunk| {
222 chunk.iter().map(|cell| {
223 let text = match cell.text.contents() {
224 Contents::Char(c) => c.into(),
225 Contents::U22(u22) => self.overflow[u22.as_u32() as usize].chars().into(),
226 };
227 CellContents {
228 text,
229 highlight: cell.highlight,
230 }
231 })
232 })
233 }
234}
235
236impl Debug for GridContents {
237 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
238 writeln!(f, "┏{:━<1$}┓", "", self.size.0.x as usize);
239 for row in self.rows() {
240 write!(f, "┃");
241 for mut cell in row {
242 let c = cell
243 .text
244 .next()
245 .map(|c| if c == '\0' { ' ' } else { c })
246 .unwrap_or(' ');
247 write!(f, "{}", c)?;
248 }
249 writeln!(f, "┃")?;
250 }
251 write!(f, "┗{:━<1$}┛", "", self.size.0.x as usize);
252 Ok(())
253 }
254}
255
256#[derive(Clone)]
257pub enum OnceOrChars<'a> {
258 Char(std::iter::Once<char>),
259 Chars(std::str::Chars<'a>),
260}
261
262impl From<char> for OnceOrChars<'_> {
263 fn from(c: char) -> Self {
264 Self::Char(std::iter::once(c))
265 }
266}
267
268impl<'a> From<std::str::Chars<'a>> for OnceOrChars<'a> {
269 fn from(value: std::str::Chars<'a>) -> Self {
270 Self::Chars(value)
271 }
272}
273
274impl Iterator for OnceOrChars<'_> {
275 type Item = char;
276
277 fn next(&mut self) -> Option<Self::Item> {
278 match self {
279 OnceOrChars::Char(iter) => iter.next(),
280 OnceOrChars::Chars(iter) => iter.next(),
281 }
282 }
283}
284
285#[derive(Clone)]
286pub struct CellContents<'a> {
287 pub highlight: u32,
288 pub text: OnceOrChars<'a>,
289}