A simple CPU rendered GUI IDE experience.
add output struct
| -rw-r--r-- | src/main.rs | 26 | ||||
| -rw-r--r-- | src/text.rs | 264 |
2 files changed, 199 insertions, 91 deletions
diff --git a/src/main.rs b/src/main.rs index c0a0e7f..92e95b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -380,23 +380,18 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { (&mut cells, (c, r)), (t_ox, 0), x, - |(c, r), text, x| { + |(c, r), text, mut x| { if let State::Search(re, j, _) = &state { re.find_iter(&text.rope.to_string()) .enumerate() .for_each(|(i, m)| { - for x in text.slice( - (c, r), - x, - text.rope.byte_to_char( - m.start(), - ) - ..text + for x in x.get_char_range( + text.rope.byte_to_char(m.start()), text .rope .byte_to_char( m.end(), - ), - ) { + )) + { x.style.bg = if i == *j { [105, 83, 128] } else { @@ -437,7 +432,6 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { &cells, (c, r), ppem, - BG, &mut fonts, ls, true, @@ -449,7 +443,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let fac = ppem / met.units_per_em as f32; let [(_x, _y), (_x2, _)] = text.position(sp); let [_x, _x2] = [_x, _x2].add(text.line_number_offset()+1); - let _y = _y - text.vo; + let _y = _y.wrapping_sub(text.vo); if !(cursor_position.1 == _y && (_x..=_x2).contains(&cursor_position.0)) { return; } @@ -460,21 +454,23 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let ppem = 18.0; let ls = 10.0; - let r = x.item.l().min(15); - let c = x.item.displayable(r); + let mut r = x.item.l().min(15); let (w, h) = dsb::size(&fonts.regular, ppem, ls, (x.item.c, r)); let top = position.1.checked_sub(h).unwrap_or((((_y + 1) as f32) * (fh + ls * fac)).round() as usize,); + let (_, y) = dsb::fit(&fonts.regular, ppem, ls, (window.inner_size().width as _ /* - left */,( window.inner_size().height as usize - top ) )); + r = r.min(y); + let c = x.item.displayable(r); let left = if position.0 + w as usize > window.inner_size().width as usize { window.inner_size().width as usize- w as usize } else { position.0 }; + let (w, h) = dsb::size(&fonts.regular, ppem, ls, (x.item.c, r)); // let mut i2 = Image::build(w as _, h as _).fill(BG); unsafe{ dsb::render( &c, (x.item.c, 0), ppem, - hov::BG, &mut fonts, ls, true, diff --git a/src/text.rs b/src/text.rs index cd22f64..4751dda 100644 --- a/src/text.rs +++ b/src/text.rs @@ -1,6 +1,7 @@ use std::cmp::min; use std::fmt::{Debug, Display}; -use std::ops::{Deref, Not as _, Range, RangeBounds}; +use std::marker::Tuple; +use std::ops::{Deref, Index, IndexMut, Not as _, Range, RangeBounds}; use std::path::Path; use std::pin::pin; use std::sync::{Arc, LazyLock}; @@ -179,7 +180,7 @@ impl Diff { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct TextArea { pub rope: Rope, pub cursor: usize, @@ -195,6 +196,7 @@ pub struct TextArea { /// └─────────────────┘ default to 5 more lines /// pub vo: usize, + pub ho: usize, pub r: usize, pub c: usize, @@ -235,19 +237,6 @@ impl Debug for TextArea { } } -impl Clone for TextArea { - fn clone(&self) -> Self { - Self { - rope: self.rope.clone(), - cursor: self.cursor, - column: self.column, - vo: self.vo, - r: self.r, - c: self.c, - } - } -} - impl TextArea { pub fn position( &self, @@ -535,7 +524,7 @@ impl TextArea { } } - pub fn tree_sit<'c>(&self, path: Option<&Path>, cell: &'c mut [Cell]) { + pub fn tree_sit<'c>(&self, path: Option<&Path>, cell: &mut Output) { let language = path .and_then(|x| LOADER.language_for_filename(x)) .unwrap_or_else(|| LOADER.language_for_name("rust").unwrap()); @@ -548,8 +537,7 @@ impl TextArea { for ((x1, y1), (x2, y2), s, _) in std::iter::from_coroutine(pin!( hl(language, &self.rope, s as u32..e as u32, self.c) )) { - cell.get_mut(y1 * self.c + x1..y2 * self.c + x2) - .map(|x| x.iter_mut().for_each(|x| x.style |= s)); + cell.get_range((x1, y1), (x2, y2)).for_each(|x| x.style |= s); } // let mut highlight_stack = Vec::with_capacity(8); @@ -612,10 +600,10 @@ impl TextArea { &mut self, color: [u8; 3], bg: [u8; 3], - (into, (w, _)): (&mut [Cell], (usize, usize)), + (into, into_s): (&mut [Cell], (usize, usize)), (ox, oy): (usize, usize), selection: Option<Range<usize>>, - apply: impl FnOnce((usize, usize), &mut Self, &mut [Cell]), + apply: impl FnOnce((usize, usize), &mut Self, Output), path: Option<&Path>, tokens: Option<( arc_swap::Guard<Arc<Box<[SemanticToken]>>>, @@ -623,21 +611,37 @@ impl TextArea { )>, ) { let (c, r) = (self.c, self.r); - let mut cells = vec![ - Cell { - style: Style { color, bg, flags: 0 }, - letter: None, - }; - (self.l().max(r) + r - 1) * c - ]; - - for (l, y) in self.rope.lines().zip(0..) { - for (e, x) in l.chars().take(c).zip(0..) { + let mut cells = Output { + into, + output: Output_ { + into_s, + ox, + oy, + from_c: c, + from_r: r, + vo: self.vo, + ho: self.ho, + }, + }; + // let mut cells = vec![ + // Cell { + // style: Style { color, bg, flags: 0 }, + // letter: None, + // }; + // (self.l().max(r) + r - 1) * c + // ]; + let lns = self.vo..self.vo + r; + for (l, y) in lns.clone().map(self.rope.get_line(_)).zip(lns) { + for (e, x) in l.iter().flat_map(|x| x.chars()).take(c).zip(0..) + { if e != '\n' { - cells[y * c + x].letter = Some(e); + cells[(x, y)].letter = Some(e); + cells[(x, y)].style.color = crate::FG; + cells[(x, y)].style.bg = crate::BG; } } } + // let tokens = None::<( // arc_swap::Guard<Arc<Box<[SemanticToken]>>>, // &SemanticTokensLegend, @@ -673,9 +677,6 @@ impl TextArea { } else if ln as usize * c + x1 > self.vo * c + r * c { break; } - let slice = cells - .get_mut(ln as usize * c + x1..ln as usize * c + x2) - .expect("good slice"); let Some(tty) = leg.token_types.get(t.token_type as usize) else { error!( @@ -687,10 +688,12 @@ impl TextArea { if let Some(f) = semantic::NAMES.iter().position(|&x| x == tty.as_str()) { - slice.iter_mut().for_each(|x| { - x.style.color = semantic::COLORS[f]; - x.style.flags |= semantic::STYLES[f]; - }); + cells + .get_range((x1, ln as _), (x2, ln as _)) + .for_each(|x| { + x.style.color = semantic::COLORS[f]; + x.style.flags |= semantic::STYLES[f]; + }); } // println!( // "{tty:?}: {}", @@ -711,10 +714,12 @@ impl TextArea { }) }) .map(|i| { - slice.iter_mut().for_each(|x| { - x.style.color = MCOLORS[i]; - x.style.flags |= MSTYLE[i]; - }); + cells + .get_range((x1, ln as _), (x2, ln as _)) + .for_each(|x| { + x.style.color = MCOLORS[i]; + x.style.flags |= MSTYLE[i]; + }); }); modi &= !(1 << bit); @@ -724,41 +729,31 @@ impl TextArea { self.tree_sit(path, &mut cells); } - selection.map(|x| self.position(x)).map(|[(x1, y1), (x2, y2)]| { - (y1 * c + x1..y2 * c + x2).for_each(|x| { - cells - .get_mut(x) - .filter( - _.letter.is_some() - || (x % c == 0) - || (self - .rope - .get_line(x / c) - .map(_.len_chars()) - .unwrap_or_default() - .saturating_sub(1) - == x % c), - ) - .map(|x| { - if x.letter == Some(' ') { - x.letter = Some('·'); // tabs? what are those - x.style.color = [0x4e, 0x62, 0x79]; - } - x.style.bg = [0x27, 0x43, 0x64]; - // 0x23, 0x34, 0x4B - }); - }); + selection.map(|x| { + let [a, b] = self.position(x); + cells + .get_range_enumerated(a, b) + .filter(|(c, (x, y))| { + c.letter.is_some() + || *x == 0 + || (self + .rope + .get_line(*y) + .map(_.len_chars()) + .unwrap_or_default() + .saturating_sub(1) + == *x) + }) + .for_each(|(x, _)| { + if x.letter == Some(' ') { + x.letter = Some('·'); // tabs? what are those + x.style.color = [0x4e, 0x62, 0x79]; + } + x.style.bg = [0x27, 0x43, 0x64]; + // 0x23, 0x34, 0x4B + }) }); - apply((c, r), self, &mut cells); - - let cells = &cells[self.vo * c..self.vo * c + r * c]; - assert_eq!(cells.len(), c * r); - - for y in 0..r { - for x in 0..c { - into[(y + oy) * w + (x + ox)] = cells[y * c + x]; - } - } + apply((c, r), self, cells); } pub fn line_number_offset(&self) -> usize { self.l().ilog10() as usize + 2 @@ -1110,3 +1105,120 @@ pub fn hl( // Some(Pin::new(&mut x).resume(())) // }) } + +#[derive(Copy, Clone)] +/// ╎ text above view offset +/// ├╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶ view offset +/// ┏━━━━┿━━━━━━━━━━━━┓ +/// ┃ ╎← offset y ┃ +/// ┃ ┏╺╺┿╺╺╺╺╺╺╺╺╺╺╺╺┃ +/// ┃ ╏ ╎valid output┃ +/// ┃ ╏ ╎goes here ┃ +/// ┃ ╏ ╎ ┃ +/// ┃ ╏ ╎ ┃ +/// ┃ ╏ ╎ ┃ +/// ┗━━━━━━━━━━━━━━━━━┛ +/// ═ ══╎ +/// ↑ ↑ ╎ +/// │ ╰ horiz scroll +/// ╰ horizontal offset +pub struct Output_ { + /// c, r + pub into_s: (usize, usize), + pub ox: usize, + pub oy: usize, + + pub from_c: usize, + pub from_r: usize, + pub vo: usize, + pub ho: usize, +} +pub struct Output<'a> { + pub into: &'a mut [Cell], + pub output: Output_, +} +impl Deref for Output<'_> { + type Target = Output_; + + fn deref(&self) -> &Self::Target { + &self.output + } +} + +impl Output_ { + fn translate(&self, index: usize) -> (usize, usize) { + (index % self.from_c, index / self.from_c) + } + fn translate_(&self, (x, y): (usize, usize)) -> usize { + (y + self.oy - self.vo) * self.into_s.0 + x + self.ox - self.ho + } + fn etalsnart(&self, index: usize) -> (usize, usize) { + (index % self.into_s.0, index / self.into_s.0) + } + fn etalsnart_( + &self, + (x, y): (usize, usize), + ) -> Option<(usize, usize)> { + Some(( + x.checked_sub(self.ho)?.checked_sub(self.ox)?, + y.checked_sub(self.oy)? + self.vo, + )) + } +} +impl<'a> Output<'a> { + pub fn get_range( + &mut self, + a: (usize, usize), + b: (usize, usize), + ) -> impl Iterator<Item = &mut Cell> { + self.get_range_enumerated(a, b).map(|x| x.0) + } + pub fn get_char_range( + &mut self, + a: usize, + b: usize, + ) -> impl Iterator<Item = &mut Cell> { + self.get_range(self.translate(a), self.translate(b)) + } + pub fn get_range_enumerated( + &mut self, + a: (usize, usize), + b: (usize, usize), + ) -> impl Iterator<Item = (&mut Cell, (usize, usize))> { + let o = self.output; + let r = self.translate_(a)..self.translate_(b); + + self.into.get_mut(r.clone()).into_iter().flatten().zip(r).flat_map( + move |(c, i)| o.etalsnart_(o.etalsnart(i)).map(|x| (c, x)), + ) + } +} + +impl<'a> Index<usize> for Output<'a> { + type Output = Cell; + + fn index(&self, index: usize) -> &Self::Output { + &self[self.translate(index)] + } +} + +impl<'a> IndexMut<usize> for Output<'a> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + let x = self.translate(index); + &mut self[x] + } +} + +impl<'a> Index<(usize, usize)> for Output<'a> { + type Output = Cell; + + fn index(&self, p: (usize, usize)) -> &Self::Output { + &self.into[self.translate_(p)] + } +} +impl<'a> IndexMut<(usize, usize)> for Output<'a> { + fn index_mut(&mut self, p: (usize, usize)) -> &mut Self::Output { + let x = self.translate_(p); + &mut self.into[x] + } +} |