A simple CPU rendered GUI IDE experience.
-rw-r--r--src/bar.rs14
-rw-r--r--src/commands.rs15
-rw-r--r--src/edi.rs62
-rw-r--r--src/edi/input_handlers/keyboard.rs72
-rw-r--r--src/edi/st.rs14
-rw-r--r--src/killring.rs58
-rw-r--r--src/main.rs15
-rw-r--r--src/menu.rs6
-rw-r--r--src/menu/generic.rs3
-rw-r--r--src/rnd.rs7
-rw-r--r--src/text/cursor.rs10
11 files changed, 235 insertions, 41 deletions
diff --git a/src/bar.rs b/src/bar.rs
index 909ca0b..a1554ae 100644
--- a/src/bar.rs
+++ b/src/bar.rs
@@ -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:?}"),
diff --git a/src/edi.rs b/src/edi.rs
index 3abe7e2..04f2ab5 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -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;
diff --git a/src/rnd.rs b/src/rnd.rs
index 41d877c..a89dede 100644
--- a/src/rnd.rs
+++ b/src/rnd.rs
@@ -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?)?))
+ }
}