A simple CPU rendered GUI IDE experience.
-rw-r--r--src/main.rs58
-rw-r--r--src/text.rs90
2 files changed, 72 insertions, 76 deletions
diff --git a/src/main.rs b/src/main.rs
index 378cdcf..99ccab7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,11 +2,11 @@
#![allow(incomplete_features, redundant_semicolons)]
use std::num::NonZeroU32;
use std::sync::LazyLock;
+use std::time::Instant;
-use dsb::cell::Style;
use fimg::Image;
use swash::FontRef;
-use winit::event::{ElementState, Event, KeyEvent, WindowEvent};
+use winit::event::{ElementState, Event, MouseScrollDelta, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::keyboard::{Key, NamedKey};
@@ -21,7 +21,8 @@ fn main() {
#[implicit_fn::implicit_fn]
pub(crate) fn entry(event_loop: EventLoop<()>) {
let ppem = 20.0;
- let ls = 20.0;
+ let ls = 20.0; let mut vo = 0;
+
let mut text = TextArea::default();
std::env::args().nth(1).map(|x| {
text.insert(&std::fs::read_to_string(x).unwrap());
@@ -30,6 +31,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) {
|elwt| {
let window = winit_app::make_window(elwt, |w| w);
window.set_ime_allowed(true);
+ window.set_ime_purpose(winit::window::ImePurpose::Terminal);
let context =
softbuffer::Context::new(window.clone()).unwrap();
@@ -73,38 +75,45 @@ pub(crate) fn entry(event_loop: EventLoop<()>) {
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
{
let (c, r) = dsb::fit(&FONT,ppem,ls, (size.width as _,size.height as _));
- let cells =text.cells((c, r),[204, 202, 194], [36, 41, 54],);
- let mut r = unsafe {
+ let now = Instant::now();
+ let cells =text.cells((c, r),[204, 202, 194], [36, 41, 54], vo);
+ println!("cell=");
+ dbg!(now.elapsed());
+ let now = Instant::now();
+
+ let mut res = unsafe {
dsb::render(&cells, (c, r), ppem, [36, 41, 54],dsb::Fonts::new(*FONT, *FONT, *FONT, *FONT),
ls, true)};
-
-
+ eprint!("rend=");
+ dbg!(now.elapsed());
let met = FONT.metrics(&[]);
let fac = ppem / met.units_per_em as f32;
+ let now = Instant::now();
// if x.view_o == Some(x.cells.row) || x.view_o.is_none() {
- let cell =
- Image::<_, 4>::build(3, (ppem * 1.25).ceil() as u32).fill([0xFF, 0xCC, 0x66, 255]);
- use fimg::OverlayAt;
+ use fimg::OverlayAt;
let (fw, fh) = dsb::dims(&FONT, ppem);
+ let cell = Image::<_, 4>::build(3, (fh).ceil() as u32).fill([0xFF, 0xCC, 0x66, 255]);
unsafe {
let (x, y) = text.cursor();
-
- r.as_mut().overlay_at(
+ if (vo..vo+r-1).contains(&y) {
+ res.as_mut().overlay_at(
&cell,
(x as f32 * fw).floor() as u32,
- (y as f32 * (fh + ls * fac)).floor()
+ ((y-vo) as f32 * (fh + ls * fac)).floor()
as u32,
// 4 + ((x - 1) as f32 * sz) as u32,
// (x as f32 * (ppem * 1.25)) as u32 - 20,
- )
- };
+ );}
+ eprint!("conv = ")
+ }; dbg!(now.elapsed());
+
// }
let mut buffer = surface.buffer_mut().unwrap();
for y in 0..height.get() {
for x in 0..width.get() {
- let [red, green, blue] =r.get_pixel(x, y).unwrap_or_default().map(_ as u32);
+ let [red, green, blue] =res.get_pixel(x, y).unwrap_or_default().map(_ as u32);
let index = y as usize * width.get() as usize + x as usize;
buffer[index] = blue | (green << 8) | (red << 16);
}
@@ -122,13 +131,28 @@ pub(crate) fn entry(event_loop: EventLoop<()>) {
} if window_id == window.id() => {
elwt.exit();
}
+ Event::WindowEvent { window_id:_, event:
+ WindowEvent::MouseWheel { device_id:_, delta: MouseScrollDelta::LineDelta(_, rows), phase }
+ } => {
+ if rows < 0.0 {
+ let rows = rows.ceil().abs() as usize;
+ let (_, r) = dsb::fit(&FONT,ppem,ls, (window.inner_size() .width as _,window.inner_size().height as _));
+ vo = (vo + rows).min(text.l() - r);
+ } else {
+ let rows = rows.floor() as usize;
+ vo = vo.saturating_sub(rows);
+ }
+ window.request_redraw();
+ dbg!(vo);
+ }
Event::WindowEvent{
event:WindowEvent::KeyboardInput { device_id, event, is_synthetic }, window_id
} if event.state == ElementState::Pressed => {
use NamedKey::*;
use Key::*;
- match (event.logical_key ){
+ match event.logical_key {
+
Named(Space)=>
text.insert(" "),
Named(Backspace) => text.backspace(),
diff --git a/src/text.rs b/src/text.rs
index 35b87a3..f2e3c42 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -34,6 +34,10 @@ pub struct TextArea {
}
impl TextArea {
+ pub fn l(&self) -> usize {
+ self.rope.len_lines()
+ }
+
pub fn insert(&mut self, c: &str) {
self.rope.insert(self.cursor, c);
self.cursor += c.chars().count();
@@ -107,12 +111,13 @@ impl TextArea {
_ = self.rope.try_remove(self.cursor - 1..self.cursor);
self.cursor = self.cursor.saturating_sub(1);
}
-
+ #[implicit_fn::implicit_fn]
pub fn cells(
&mut self,
(c, r): (usize, usize),
color: [u8; 3],
bg: [u8; 3],
+ vo: usize,
) -> Vec<Cell> {
let mut x = HighlightConfiguration::new(
tree_sitter_rust::LANGUAGE.into(),
@@ -134,7 +139,7 @@ impl TextArea {
},
letter: None,
};
- c * r
+ self.l().max(r) * c
];
// dbg!(unsafe {
@@ -155,31 +160,26 @@ impl TextArea {
.map(Result::unwrap)
{
match hl {
- HighlightEvent::Source { start, end } => drop::<
- ropey::Result<()>,
- >(
- try {
- // for elem in start..end {
- // styles[elem] = s;
- // }
- let y1 = self.rope.try_char_to_line(start)?;
- let y2 = self.rope.try_char_to_line(start)?;
- let x1 = start - self.rope.try_line_to_char(y1)?;
- let x2 = end - self.rope.try_line_to_char(y2)?;
- // dbg!((x1, y1), (x2, y2));
- cells.get_mut(y1 * c + x1..y2 * c + x2).map(|x| {
- x.iter_mut()
- .for_each(|x| x.style.color = COLORS[s])
- });
- // println!(
- // "highlight {} {s} {}: {:?}",
- // self.rope.byte_slice(start..end),
- // NAMES[s],
- // COLORS[s],
- // )
- ()
- },
- ),
+ HighlightEvent::Source { start, end } => {
+ // for elem in start..end {
+ // styles[elem] = s;
+ // }
+ let y1 = self.rope.byte_to_line(start);
+ let y2 = self.rope.byte_to_line(start);
+ let x1 = start - self.rope.line_to_char(y1);
+ let x2 = end - self.rope.line_to_char(y2);
+ // dbg!((x1, y1), (x2, y2));
+ cells.get_mut(y1 * c + x1..y2 * c + x2).map(|x| {
+ x.iter_mut()
+ .for_each(|x| x.style.color = COLORS[s])
+ });
+ // println!(
+ // "highlight {} {s} {}: {:?}",
+ // self.rope.byte_slice(start..end),
+ // NAMES[s],
+ // COLORS[s],
+ // )
+ }
HighlightEvent::HighlightStart(s_) => s = s_.0,
HighlightEvent::HighlightEnd => s = 0,
}
@@ -205,44 +205,16 @@ impl TextArea {
// i += 1;
// }
- for (l, y) in self.rope.lines().take(r).zip(0..) {
+ for (l, y) in self.rope.lines().zip(0..) {
for (e, x) in l.chars().take(c).zip(0..) {
if e != '\n' {
cells[y * c + x].letter = Some(e);
}
}
}
- cells
- }
-}
-
-pub trait TakeLine<'b> {
- fn take_line<'a>(&'a mut self) -> Option<&'b [u8]>;
- fn take_backline<'a>(&'a mut self) -> Option<&'b [u8]>;
-}
-
-impl<'b> TakeLine<'b> for &'b [u8] {
- fn take_line<'a>(&'a mut self) -> Option<&'b [u8]> {
- match memchr::memchr(b'\n', self) {
- None if self.is_empty() => None,
- None => Some(std::mem::replace(self, b"")),
- Some(end) => {
- let line = &self[..end];
- *self = &self[end + 1..];
- Some(line)
- }
- }
- }
+ let cells = cells[vo * c..vo * c + r * c].to_vec();
+ assert_eq!(cells.len(), c * r);
- fn take_backline<'a>(&'a mut self) -> Option<&'b [u8]> {
- let end = self.len().checked_sub(1)?;
- match memchr::memrchr(b'\n', &self[..end]) {
- None => Some(std::mem::replace(self, b"")),
- Some(end) => {
- let line = &self[end + 1..];
- *self = &self[..end];
- Some(line)
- }
- }
+ cells
}
}