A simple CPU rendered GUI IDE experience.
implement save
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/bar.rs | 55 | ||||
| -rw-r--r-- | src/main.rs | 99 | ||||
| -rw-r--r-- | src/text.rs | 10 |
4 files changed, 133 insertions, 32 deletions
@@ -22,6 +22,7 @@ lower = "0.2.0" amap = "0.1.2" run_times = "0.1.0" array_chunks = "1.0.0" +rust-fsm = { version = "0.8.0", features = ["diagram"] } [build-dependencies] cc = "*" @@ -2,11 +2,28 @@ use std::iter::{once, repeat}; use dsb::Cell; use dsb::cell::Style; -use winit::keyboard::{Key, NamedKey}; pub struct Bar { - pub holding: Option<Key>, - pub fname: String, + pub state: state::StateMachine, + pub text: crate::text::TextArea, + pub last_action: String, +} + +rust_fsm::state_machine! { + #[derive(Debug, PartialEq, Eq, Copy, Clone)] + pub(crate) state(Inactive) + + Inactive => { + Control => Control, + }, + Control => { + Saved => Inactive, + WaitingForFname => InputFname, + Released => Inactive, + }, + InputFname => { + Enter => Inactive, + } } impl Bar { @@ -16,6 +33,7 @@ impl Bar { bg: [u8; 3], (into, (w, _)): (&mut [Cell], (usize, usize)), oy: usize, + fname: &str, ) { let row = &mut into[oy * w..oy * w + w]; row.fill(Cell { @@ -25,19 +43,23 @@ impl Bar { fn s(s: &str) -> impl Iterator<Item = (char, u8)> { s.chars().zip(repeat(0)) } - match self.holding { - None => { + match self.state.state() { + state::State::Inactive => { row[1.."gracilaria".len() + 1] .iter_mut() .zip("gracilaria".chars()) .for_each(|(x, y)| x.letter = Some(y)); - row[w / 2 - self.fname.len() / 2 - ..w / 2 - self.fname.len() / 2 + self.fname.len()] + row[w / 2 - fname.len() / 2 + ..w / 2 - fname.len() / 2 + fname.len()] .iter_mut() - .zip(self.fname.chars()) + .zip(fname.chars()) + .for_each(|(x, y)| x.letter = Some(y)); + row.iter_mut() + .rev() + .zip(self.last_action.chars().rev()) .for_each(|(x, y)| x.letter = Some(y)); } - Some(Key::Named(NamedKey::Control)) => { + state::State::Control => { let x = s("C + { ") .chain(once(('S', Style::BOLD))) .chain(s("ave, ")) @@ -52,7 +74,20 @@ impl Bar { } }); } - Some(_) => panic!(), + state::State::InputFname => { + "write to file: " + .chars() + .zip(repeat(Style::BOLD | Style::ITALIC)) + .chain(s(&self.text.rope.to_string())) + .zip(row) + .for_each(|((x, z), y)| { + *y = Cell { + letter: Some(x), + style: Style { flags: z, ..y.style }, + ..*y + } + }); + } } } } diff --git a/src/main.rs b/src/main.rs index 354a2a2..5935a9f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![feature(tuple_trait, unboxed_closures, fn_traits)] #![feature( if_let_guard, deref_patterns, @@ -8,6 +9,7 @@ )] #![allow(incomplete_features, redundant_semicolons)] use std::convert::identity; +use std::fs::File; use std::hint::assert_unchecked; use std::iter::zip; use std::num::NonZeroU32; @@ -20,12 +22,14 @@ use atools::prelude::*; use dsb::cell::Style; use dsb::{Cell, F}; use fimg::Image; +use rust_fsm::StateMachineImpl; use swash::{FontRef, Instance}; use winit::event::{ElementState, Event, MouseScrollDelta, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::keyboard::{Key, NamedKey}; use crate::bar::Bar; +use crate::bar::state::{Input, State}; use crate::text::TextArea; mod bar; mod text; @@ -42,20 +46,34 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let ls = 20.0; let mut text = TextArea::default(); - let fname = std::env::args().nth(1).unwrap_or("new buffer".into()); + let mut origin = std::env::args().nth(1); let mut fonts = dsb::Fonts::new( *FONT, F::instance(*FONT, *BFONT), *IFONT, F::instance(*IFONT, *BIFONT), ); - let mut bar = Bar { holding: None, fname }; + let mut bar = Bar { + text: TextArea::default(), + state: bar::state::StateMachine::new(), + last_action: String::default(), + }; let mut i = Image::build(1, 1).fill(BG); let mut cells = vec![]; std::env::args().nth(1).map(|x| { text.insert(&std::fs::read_to_string(x).unwrap()); text.cursor = 0; }); + macro_rules! save { + () => {{ + std::fs::write( + origin.as_ref().unwrap(), + &text.rope.to_string(), + ) + .unwrap(); + bar.last_action = "saved".into(); + }}; + } let app = winit_app::WinitAppBuilder::with_init( |elwt| { let window = winit_app::make_window(elwt, identity); @@ -83,6 +101,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { window.inner_size().height as _, ), ); + dbg!(&bar.state); match event { Event::WindowEvent { window_id, @@ -140,15 +159,21 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { BG, (&mut cells, (c, r)), (1, 0), - ); + ) + 1; text.write_to( (c - t_ox, r - 1), FG, BG, (&mut cells, (c, r)), - (1 + t_ox, 0), + (t_ox, 0), + ); + bar.write_to( + BG, + FG, + (&mut cells, (c, r)), + r - 1, + &origin.as_deref().unwrap_or("new buffer"), ); - bar.write_to(BG, FG, (&mut cells, (c, r)), r - 1); println!("cell="); dbg!(now.elapsed()); @@ -179,7 +204,8 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { .fill([0xFF, 0xCC, 0x66, 255]); unsafe { let (x, y) = text.cursor(); - let y = y; + let x = x + t_ox; + if (text.vo..text.vo + r).contains(&y) { i.as_mut().overlay_at( &cursor, @@ -236,32 +262,49 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let rows = rows.floor() as usize; text.vo = text.vo.saturating_sub(rows); } - window.request_redraw(); } Event::WindowEvent { event: WindowEvent::KeyboardInput { event, .. }, .. } if event.state == ElementState::Released - && bar - .holding - .as_ref() - .is_some_and(|x| x == &event.logical_key) => + && *bar.state.state() == State::Control + && event.logical_key == NamedKey::Control => { - bar.holding = None; + bar.state.consume(&Input::Released).unwrap(); window.request_redraw(); } Event::WindowEvent { event: WindowEvent::KeyboardInput { event, .. }, .. - } if let Some(Key::Named(NamedKey::Control)) = - bar.holding + } if *bar.state.state() == State::Control && event.state == ElementState::Pressed => { use Key::*; match event.logical_key { - Character(x) if x == "s" => {} + Character(x) if x == "s" => match &origin { + Some(_) => { + bar.state.consume(&Input::Saved).unwrap(); + save!(); + } + None => { + bar.state + .consume(&Input::WaitingForFname) + .unwrap(); + } + }, + // Character(x) + // if x == "s" + // && => + // { + // bar.state.consume(State::Save); + // text.rope + // .write_to(File::open(origin).unwrap()) + // .unwrap(); + // } + // Character(x) if x == "s" => {} _ => panic!(), } + window.request_redraw(); } Event::WindowEvent { @@ -270,6 +313,11 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { } if event.state == ElementState::Pressed => { use Key::*; use NamedKey::*; + let text = if bar.state.state() == &State::InputFname { + &mut bar.text + } else { + &mut text + }; match event.logical_key { Named(Space) => text.insert(" "), Named(Backspace) => text.backspace(), @@ -279,19 +327,30 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { Named(ArrowRight) => text.right(), Named(ArrowUp) => text.up(), Named(ArrowDown) => text.down(r), + Named(Enter) + if bar.state.state() == &State::InputFname => + { + bar.state.consume(&Input::Enter).unwrap(); + origin = Some( + std::mem::take(&mut bar.text) + .rope + .to_string(), + ); + save!(); + } Named(Enter) => text.enter(), - Named(Control) => - bar.holding = Some(event.logical_key), + Named(Control) => { + bar.state.consume(&Input::Control).unwrap(); + } Character(x) => { text.insert(&*x); } _ => {} - } - + }; window.request_redraw(); } _ => {} - } + }; }, ); diff --git a/src/text.rs b/src/text.rs index cb6518a..1f92481 100644 --- a/src/text.rs +++ b/src/text.rs @@ -7,6 +7,7 @@ use ropey::Rope; use tree_sitter_highlight::{ HighlightConfiguration, HighlightEvent, Highlighter, }; +use winit::keyboard::SmolStr; #[rustfmt::skip] const NAMES: [&str; 13] = ["attribute", "comment", "constant", "function", "keyword", "number", "operator", "punctuation", "string", "tag", "type", "variable", "variable.parameter"]; @@ -34,7 +35,7 @@ const fn color(x: &[u8; 6]) -> [u8; 3] { #[derive(Default)] pub struct TextArea { - rope: Rope, + pub rope: Rope, pub cursor: usize, highlighter: Highlighter, column: usize, @@ -46,8 +47,13 @@ impl TextArea { self.rope.len_lines() } + pub fn insert_(&mut self, c: SmolStr) { + self.rope.insert(self.cursor, &c); + self.cursor += c.chars().count(); + self.setc(); + } pub fn insert(&mut self, c: &str) { - self.rope.insert(self.cursor, c); + self.rope.insert(self.cursor, &c); self.cursor += c.chars().count(); self.setc(); } |