A simple CPU rendered GUI IDE experience.
| -rw-r--r-- | src/main.rs | 58 | ||||
| -rw-r--r-- | src/text.rs | 90 |
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 } } |