A simple CPU rendered GUI IDE experience.
add output struct
bendn 4 months ago
parent ec58855 · commit a365674
-rw-r--r--src/main.rs26
-rw-r--r--src/text.rs264
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]
+ }
+}