A simple CPU rendered GUI IDE experience.
| -rw-r--r-- | src/bar.rs | 14 | ||||
| -rw-r--r-- | src/commands.rs | 15 | ||||
| -rw-r--r-- | src/edi.rs | 62 | ||||
| -rw-r--r-- | src/edi/input_handlers/keyboard.rs | 72 | ||||
| -rw-r--r-- | src/edi/st.rs | 14 | ||||
| -rw-r--r-- | src/killring.rs | 58 | ||||
| -rw-r--r-- | src/main.rs | 15 | ||||
| -rw-r--r-- | src/menu.rs | 6 | ||||
| -rw-r--r-- | src/menu/generic.rs | 3 | ||||
| -rw-r--r-- | src/rnd.rs | 7 | ||||
| -rw-r--r-- | src/text/cursor.rs | 10 |
11 files changed, 235 insertions, 41 deletions
@@ -4,6 +4,7 @@ use dsb::Cell; use dsb::cell::Style; use lsp_types::WorkDoneProgress; +use crate::killring::KillRM; use crate::lsp::{Client, Rq}; use crate::rnd::simplify_path; use crate::sym::Symbols; @@ -128,6 +129,19 @@ impl Bar { } }); } + State::KillRing(KillRM { tedit, .. }) => { + "filter: " + .chars() + .zip(repeat(Style::BOLD | Style::ITALIC)) + .chain(s(&tedit.rope.to_string())) + .zip(row) + .for_each(|((x, z), y)| { + *y = Cell { + letter: Some(x), + style: Style { flags: z, ..y.style }, + } + }); + } State::RequestBoolean(x) => { x.prompt() .chars() diff --git a/src/commands.rs b/src/commands.rs index 4498513..13f77fb 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -11,7 +11,6 @@ use lsp_types::*; use rootcause::{bail, report}; use rust_analyzer::lsp::ext::*; -use crate::FG; use crate::edi::{Editor, lsp}; use crate::gotolist::{At, GoToList}; use crate::lsp::{PathURI, Rq, tdpp}; @@ -19,6 +18,7 @@ use crate::menu::charc; use crate::menu::generic::{CorA, GenericMenu, MenuData}; use crate::sym::GoTo; use crate::text::{Bookmark, RopeExt, SortTedits, TextArea, col, color_}; +use crate::{FG, KillRing}; macro_rules! repl { ($x:ty, $($with:tt)+) => { @@ -115,6 +115,8 @@ commands!( @ Incoming: "callers-of", /// Functions this function calls @ Outgoing: "calling", + /// loads up the kill ring + | KillRing: "killring", /// Reloads the file from disk. | Reload: "reload", // /// View child modules @@ -225,6 +227,7 @@ impl Editor { &mut self, z: Cmd, w: Arc<dyn winit::window::Window>, + kr: &mut KillRing, ) -> rootcause::Result<()> { match z { Cmd::GoTo(Some(x)) => @@ -274,6 +277,16 @@ impl Editor { ..default() }); } + Cmd::KillRing => { + self.state = crate::edi::st::State::KillRing( + crate::killring::KillRM { + data: kr.clone(), + tedit: default(), + selection: 0, + vo: 0, + }, + ); + } Cmd::Reload => self.reload(), z if z.needs_lsp() => return self.handle_lsp_command(z, w), x => unimplemented!("{x:?}"), @@ -49,8 +49,8 @@ use crate::text::cursor::{Ronge, ceach}; use crate::text::hist::{ClickHistory, Hist}; use crate::text::{LOADER, Mapping, RopeExt, SortTedits, TextArea}; use crate::{ - BoolRequest, CDo, CompletionAction, CompletionState, Freq, alt, ctrl, - filter, hash, shift, sym, trm, + BoolRequest, CDo, CompletionAction, CompletionState, Freq, KillRing, + alt, ctrl, filter, hash, shift, sym, trm, }; impl Debug for Editor { @@ -195,7 +195,7 @@ fn rooter( } impl Editor { - pub fn new() -> rootcause::Result<(Self, Freq)> { + pub fn new() -> rootcause::Result<(Self, Freq, KillRing)> { let mut me = Self::default(); let mut o = std::env::args() @@ -294,6 +294,7 @@ impl Editor { let mut loaded_state = false; let mut freq = default(); + let mut kr = default(); if let Some(ws) = me.workspace.as_deref() && let h = hash(&ws) && let cf = cfgdir().join(format!("{h:x}")) @@ -311,6 +312,12 @@ impl Editor { let x = std::fs::read(at)?; freq = bendncode::from_bytes::<Freq>(&x)?; } + if let at = cf.join(KSTORE) + && at.exists() + { + let x = std::fs::read(at)?; + kr = bendncode::from_bytes::<KillRing>(&x)?; + } } me.language = n; me.origin = o; @@ -443,7 +450,7 @@ impl Editor { // }, // ); } - Ok((me, freq)) + Ok((me, freq, kr)) } #[must_use = "please apply this"] @@ -557,6 +564,30 @@ impl Editor { inlay!(self); } + pub fn paste_m<T: AsRef<str>>( + &mut self, + r: impl Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator, + ) { + // let bounds = unsafe { &*META.splits }; + // let pieces = bounds.windows(2).map(|w| unsafe { + // std::str::from_utf8_unchecked(&r.as_bytes()[w[0]..w[1]]) + // }); + if r.len() == self.text.cursor.iter().len() { + for (piece, cursor) in + r.rev().zip(0..self.text.cursor.iter().count()) + { + let c = self.text.cursor.iter().nth(cursor).unwrap(); + self.text.insert_at(*c, piece.as_ref()).unwrap(); + } + } else { + let new = r + .fold(String::default(), |acc, x| acc + x.as_ref() + "\n"); + + // vscode behaviour: insane? + self.text.insert(&new); + eprintln!("hrmst"); + } + } pub fn paste(&mut self) { self.hist.push_if_changed(&mut self.text); let r = clipp::paste(); @@ -565,19 +596,7 @@ impl Editor { let pieces = bounds.windows(2).map(|w| unsafe { std::str::from_utf8_unchecked(&r.as_bytes()[w[0]..w[1]]) }); - if unsafe { META.count } == self.text.cursor.iter().len() { - for (piece, cursor) in - pieces.rev().zip(0..self.text.cursor.iter().count()) - { - let c = self.text.cursor.iter().nth(cursor).unwrap(); - self.text.insert_at(*c, piece).unwrap(); - } - } else { - let new = pieces.intersperse("\n").collect::<String>(); - // vscode behaviour: insane? - self.text.insert(&new); - eprintln!("hrmst"); - } + self.paste_m(pieces); } else { self.text.insert(&clipp::paste()); } @@ -724,7 +743,11 @@ impl Editor { .map(|[wo, or]| format!("gracilaria - {wo} - {or}")) } - pub fn store(&mut self, fq: &Freq) -> rootcause::Result<()> { + pub fn store( + &mut self, + fq: &Freq, + kr: &KillRing, + ) -> rootcause::Result<()> { let ws = self.workspace.clone(); let tree = self.tree.clone(); let mtime = self.mtime.clone(); @@ -751,6 +774,8 @@ impl Editor { std::fs::write(p.join(SSTORE), &b)?; let b = bendncode::to_bytes(fq)?; std::fs::write(p.join(FSTORE), &b)?; + let b = bendncode::to_bytes(kr)?; + std::fs::write(p.join(KSTORE), &b)?; } Ok(()) } @@ -804,3 +829,4 @@ fn cfgdir() -> PathBuf { } const SSTORE: &str = "state.bendn"; const FSTORE: &str = "freq.bendn"; +const KSTORE: &str = "killring.bendn"; diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs index 97d3b3f..549cb83 100644 --- a/src/edi/input_handlers/keyboard.rs +++ b/src/edi/input_handlers/keyboard.rs @@ -19,6 +19,7 @@ use winit::window::Window; use crate::Freq; use crate::edi::*; +use crate::killring::KillRM; use crate::lsp::acceptable_duration; impl Editor { @@ -27,6 +28,7 @@ impl Editor { event: KeyEvent, window: &mut Arc<dyn Window>, freq: &mut Freq, + kr: &mut KillRing, ) -> ControlFlow<()> { let Some(mut o) = self.transition(Action::K(event.logical_key.clone())) @@ -126,7 +128,7 @@ impl Editor { } crate::menu::generic::CorA::Accept => { if let Err(e) = - self.handle_command(z, window.clone()) + self.handle_command(z, window.clone(), kr) { self.bar.last_action = format!("{e}"); } @@ -404,6 +406,7 @@ impl Editor { Do::Insert(c) => { // self.text.cursor.inner.clear(); self.hist.push_if_changed(&mut self.text); + self.kill(kr); ceach!(self.text.cursor, |cursor| { let Some(r) = cursor.sel else { return }; _ = self.text.remove(r.into()); @@ -416,12 +419,12 @@ impl Editor { } Do::Delete => { self.hist.push_if_changed(&mut self.text); + self.kill(kr); ceach!(self.text.cursor, |cursor| { let Some(r) = cursor.sel else { return }; _ = self.text.remove(r.into()); }); self.text.cursor.clear_selections(); - self.hist.push_if_changed(&mut self.text); change!(self, window.clone()); } @@ -429,15 +432,14 @@ impl Editor { self.hist.push_if_changed(&mut self.text); unsafe { take(&mut META) }; let mut clip = String::new(); - self.text.cursor.each_ref(|x| { - if let Some(x) = x.sel { - unsafe { - META.count += 1; - META.splits.push(clip.len()); - } - clip.extend(self.text.rope.slice(x).chars()); + self.kill(kr); + for sel in self.text.cursor.sels(&self.text) { + unsafe { + META.count += 1; + META.splits.push(clip.len()); } - }); + clip.extend(sel.chars()); + } unsafe { META.splits.push(clip.len()); META.hash = hash(&clip) @@ -451,15 +453,14 @@ impl Editor { self.hist.push_if_changed(&mut self.text); unsafe { take(&mut META) }; let mut clip = String::new(); - self.text.cursor.each_ref(|x| { - if let Some(x) = x.sel { - unsafe { - META.count += 1; - META.splits.push(clip.len()); - } - clip.extend(self.text.rope.slice(x).chars()); + self.kill(kr); + for sel in self.text.cursor.sels(&self.text) { + unsafe { + META.count += 1; + META.splits.push(clip.len()); } - }); + clip.extend(sel.chars()); + } unsafe { META.splits.push(clip.len()); META.hash = hash(&clip) @@ -476,6 +477,7 @@ impl Editor { } Do::PasteOver => { self.hist.push_if_changed(&mut self.text); + self.kill(kr); ceach!(self.text.cursor, |cursor| { let Some(r) = cursor.sel else { return }; _ = self.text.remove(r.into()); @@ -584,6 +586,27 @@ impl Editor { // self.text.vo = self.text.char_to_line(x.start); } } + // Do::KillRing => { + // self.state = State::KillRing(KillRM { + // data: kr.clone(), + // tedit: default(), + // selection: 0, + // vo: 0, + // }); + // } + Do::KillRMHandleKey => { + if let State::KillRing(x) = &mut self.state { + handle2( + &event.logical_key, + &mut x.tedit, + lsp!(self + p), + ); + } + } + Do::Revive(x) => + if let Some(Ok(x)) = x.sel(Some(freq)) { + self.paste_m(x.iter()) + }, } ControlFlow::Continue(()) } @@ -862,4 +885,17 @@ impl Editor { self.bar.last_action = "reloaded".into(); self.hist.push(&mut self.text) } + pub fn kill(&mut self, kr: &mut KillRing) { + if let x = self + .text + .cursor + .sels(&self.text) + .map(String::from) + .collect::<Box<[_]>>() + && !x.is_empty() + { + println!("kill {x:?}"); + kr.push(x); + } + } } diff --git a/src/edi/st.rs b/src/edi/st.rs index efe6de9..b0a38a8 100644 --- a/src/edi/st.rs +++ b/src/edi/st.rs @@ -156,6 +156,20 @@ Symbols(Rq::<Symbols, Option<SymbolsList>, (), AQErr> => _rq) => { C(_) => _, M(_) => _, }, + + +KillRing(crate::killring::KillRM => x) => { + K(Key::Named(Tab) if shift()) => KillRing({ let mut x = x; x.next(); x }), + K(Key::Named(ArrowDown)) => KillRing({ let mut x = x; x.next(); x }), + K(Key::Named(ArrowUp | Tab)) => KillRing({ let mut x = x; x.back(); x }), + K(Key::Named(Enter)) => Default [Revive(crate::killring::KillRM => x)], + K(Key::Named(Escape)) => Default, + K(_) => _ [KillRMHandleKey], + // K(_) => _ [GTLHandleKey], + C(_) => _, + M(_) => _, +}, + CodeAction(Rq { result : Some(_x), request }) => { K(Key::Named(Tab) if shift()) => _ [CASelectPrev], K(Key::Named(ArrowDown | Tab)) => _ [CASelectNext], diff --git a/src/killring.rs b/src/killring.rs new file mode 100644 index 0000000..5f6438d --- /dev/null +++ b/src/killring.rs @@ -0,0 +1,58 @@ +use std::path::Path; + +use dsb::Cell; +use dsb::cell::Style; + +use crate::menu::Key; +use crate::menu::generic::{GenericMenu, MenuData}; +use crate::text::{col, color_}; +use crate::{FG, KillRing}; +impl<'a> Key<'a> for &'a [String] { + fn key(&self) -> impl Into<std::borrow::Cow<'a, str>> { + self.join("") + } +} +pub enum KillR {} +impl MenuData for KillR { + const NAME: &'static str = "symbols"; + type Data = KillRing; + + type Element<'a> = &'a [String]; + + fn gn(d: &Self::Data) -> impl Iterator<Item = Self::Element<'_>> { + println!("x{d:?}"); + d.iter() + .inspect(|x| { + dbg!(&x); + }) + .map(|x| &**x) + } + + fn r( + _: &Self::Data, + x: Self::Element<'_>, + _: &Path, + c: usize, + selected: bool, + indices: &[u32], + to: &mut Vec<Cell>, + ) { + let bg = if selected { col!("#262d3b") } else { col!("#1c212b") }; + let ds: Style = Style::new(FG, bg); + let mut b = vec![Cell { style: ds, letter: None }; c]; + x.join("").chars().zip(&mut b).zip(1..).for_each( + |((x, y), i)| { + y.letter = Some(x); + if indices.contains(&i) { + y.style |= (Style::BOLD, color_("#ffcc66")); + } + }, + ); + to.extend(b); + } + + fn hash<'b>(x: &'b Self::Element<'_>) -> Option<impl std::hash::Hash> { + Some(x) + } +} +pub type KillRM = GenericMenu<KillR>; diff --git a/src/main.rs b/src/main.rs index f35d444..43e4d0b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,7 @@ mod edi; mod error; mod git; mod gotolist; +mod killring; mod meta; mod rnd; mod runnables; @@ -112,7 +113,8 @@ static mut CLICKING: bool = false; const BG: [u8; 3] = col!("#1f2430"); const FG: [u8; 3] = [204, 202, 194]; const BORDER: [u8; 3] = col!("#ffffff"); - +type KillRing = Vec<Box<[String]>>; +static mut __KR: MaybeUninit<KillRing> = MaybeUninit::uninit(); static mut __ED: MaybeUninit<Editor> = MaybeUninit::uninit(); static mut __FREQ: MaybeUninit<Freq> = MaybeUninit::uninit(); static mut __CLEAN: bool = false; @@ -120,7 +122,10 @@ extern "C" fn cleanup() { unsafe { if __CLEAN == false { __CLEAN = true; - match __ED.assume_init_mut().store(__FREQ.assume_init_mut()) { + match __ED + .assume_init_mut() + .store(__FREQ.assume_init_mut(), __KR.assume_init_mut()) + { Ok(_) => {} Err(e) => eprintln!("{e}"), }; @@ -135,7 +140,7 @@ type FID = u8; type Freq = FxHashMap<FID, FxHashMap<u64, u16>>; pub(crate) fn entry(event_loop: EventLoop) { unsafe { - let (ed, freq) = match Editor::new() { + let (ed, freq, kr) = match Editor::new() { Err(e) => { eprintln!("failure to launch: {e}"); return; @@ -144,11 +149,13 @@ pub(crate) fn entry(event_loop: EventLoop) { }; __ED.write(ed); __FREQ.write(freq); + __KR.write(kr); }; assert_eq!(unsafe { atexit(cleanup) }, 0); unsafe { signal(libc::SIGINT, sigint as *const () as usize) }; let ed: &'static mut Editor = unsafe { __ED.assume_init_mut() }; let freq = unsafe { __FREQ.assume_init_mut() }; + let kr = unsafe { __KR.assume_init_mut() }; let ppem = 18.0; let ls = 20.0; // let ed = Box::leak(Box::new(ed)); @@ -360,7 +367,7 @@ pub(crate) fn entry(event_loop: EventLoop) { ) { return; } - if ed.keyboard(event, window, freq).is_break() { + if ed.keyboard(event, window, freq, kr).is_break() { elwt.exit(); } window.request_redraw(); diff --git a/src/menu.rs b/src/menu.rs index ca5cb47..fb170ef 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -48,6 +48,7 @@ pub fn score<'a, T: Key<'a>, D: MenuData<Element<'a> = T> + 'static>( ); let mut v = x .map(move |y| { + println!("holy hell"); if let Some(f) = freq && filter == "" && let Some(f) = f.get(&D::ID) @@ -124,7 +125,9 @@ pub fn filter<'a, T: Key<'a>>( i: impl Iterator<Item = T>, filter: &'_ str, ) -> impl Iterator<Item = T> { + println!("omega"); i.filter(move |y| { + println!("waow?"); filter.is_empty() || y.k().chars().any(|x| filter.chars().contains(&x)) // .collect::<HashSet<_>>() @@ -132,6 +135,9 @@ pub fn filter<'a, T: Key<'a>>( // .count() // > 0 }) + .inspect(|x| { + dbg!(x.k()); + }) } pub trait Key<'a> { diff --git a/src/menu/generic.rs b/src/menu/generic.rs index d2b2395..2584f9e 100644 --- a/src/menu/generic.rs +++ b/src/menu/generic.rs @@ -68,6 +68,9 @@ impl ID for crate::runnables::Runb { impl ID for crate::sym::Symb { const ID: u8 = 3; } +impl ID for crate::killring::KillR { + const ID: u8 = 4; +} pub trait MenuData: Sized + 'static + ID { const NAME: &'static str; const HEIGHT: usize = 30; @@ -866,6 +866,13 @@ pub fn render( let c = y.cells(50, ws, None); drawb(&c, 50); } + State::KillRing(y) => { + dbg!(y); + let ws = ed.workspace.as_deref().unwrap(); + let c = y.cells(50, ws, None); + println!("???? {c:?}"); + drawb(&c, 50); + } _ => {} } let com = match ed.requests.complete { diff --git a/src/text/cursor.rs b/src/text/cursor.rs index 2594ba5..077a750 100644 --- a/src/text/cursor.rs +++ b/src/text/cursor.rs @@ -509,4 +509,14 @@ impl Cursors { // ) -> Vec<std::ops::Range<usize>> { // panic!(); // } + + pub fn sels<'a>( + &self, + text: &'a Rope, + ) -> std::iter::FilterMap< + impl Iterator<Item = Cursor> + ExactSizeIterator, + impl FnMut(Cursor) -> Option<RopeSlice<'a>>, + > { + self.iter().filter_map(|x| Some(text.get_slice(x.sel?)?)) + } } |