A simple CPU rendered GUI IDE experience.
-rw-r--r--Cargo.toml7
-rw-r--r--src/bar.rs6
-rw-r--r--src/commands.rs1
-rw-r--r--src/edi.rs40
-rw-r--r--src/edi/input_handlers/click.rs26
-rw-r--r--src/edi/input_handlers/keyboard.rs12
-rw-r--r--src/edi/st.rs2
-rw-r--r--src/gotolist.rs1
-rw-r--r--src/hov.rs2
-rw-r--r--src/main.rs30
-rw-r--r--src/menu.rs3
-rw-r--r--src/menu/generic.rs27
-rw-r--r--src/runnables.rs1
-rw-r--r--src/sym.rs1
-rw-r--r--src/text.rs11
-rw-r--r--src/text/inlay.rs6
-rw-r--r--src/text/semantic_tokens.rs3
17 files changed, 114 insertions, 65 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 00303e4..d4fa4d2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,9 +39,9 @@ rust-analyzer = { git = "https://git.bendn.org/rust-analyzer" }
serde_json = "1.0.150"
serde = { version = "1.0.228", features = ["unstable"] }
serde_derive = "1.0.228"
-log = "0.4.30"
+log = "0.4.31"
crossbeam = { version = "0.8.4", features = ["nightly", "crossbeam-channel"] }
-test-log = "0.2.20"
+test-log = "0.2.21"
env_logger = "0.11.10"
url = "2.5.8"
tokio = { version = "1.52.3", features = ["rt-multi-thread", "sync", "time"] }
@@ -61,7 +61,6 @@ walkdir = "2.5.0"
niri = { package = "niri-ipc", version = "25.11.0" }
libc = "0.2.186"
rustc-hash = "=2.1.1"
-bendy = { version = "0.6.1", features = ["serde"] }
git2 = "0.20.4"
imara-diff = "0.2.0"
vecto = "0.1.1"
@@ -77,6 +76,7 @@ ftools = { git = "https://git.bendn.org/ftools" }
json_value_merge = "2.0.1"
annotate-snippets = "0.12.16"
toml = "1.1.2"
+bendncode = { git = "https://git.bendn.org/bendncode" }
[profile.dev.package]
rust-analyzer.opt-level = 3
fimg.opt-level = 3
@@ -89,7 +89,6 @@ debug-assertions = false
[profile.release.package]
fimg.debug-assertions = true
rust-analyzer.debug-assertions = false
-hir-ty.debug-assertions = false
[profile.release]
debug = 2
diff --git a/src/bar.rs b/src/bar.rs
index c4d9009..909ca0b 100644
--- a/src/bar.rs
+++ b/src/bar.rs
@@ -164,6 +164,12 @@ impl Bar {
x.letter = Some(c);
});
}
+ State::GoToL(x) => format!("list of {}", x.name())
+ .chars()
+ .zip(row)
+ .for_each(|(c, x)| {
+ x.letter = Some(c);
+ }),
State::Save => unreachable!(),
_ => {}
}
diff --git a/src/commands.rs b/src/commands.rs
index 1273cfe..2a56aac 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -129,6 +129,7 @@ commands!(
pub enum Cmds {}
impl MenuData for Cmds {
+ const NAME: &'static str = "commands";
const HEIGHT: usize = 30;
type Data = ();
type Element<'a> = Cmd;
diff --git a/src/edi.rs b/src/edi.rs
index d648885..fabe5d1 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -49,7 +49,7 @@ 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, alt, ctrl,
+ BoolRequest, CDo, CompletionAction, CompletionState, Freq, alt, ctrl,
filter, hash, shift, sym, trm,
};
@@ -184,7 +184,7 @@ fn rooter(
}
impl Editor {
- pub fn new() -> rootcause::Result<Self> {
+ pub fn new() -> rootcause::Result<(Self, Freq)> {
let mut me = Self::default();
let o = std::env::args()
@@ -219,16 +219,24 @@ impl Editor {
.and_then(|(ws, x)| (vsc_settings::load(&x, &ws)).ok());
let mut loaded_state = false;
+ let mut freq = default();
if let Some(ws) = me.workspace.as_deref()
&& let h = hash(&ws)
- && let at = cfgdir().join(format!("{h:x}")).join(STORE)
+ && let cf = cfgdir().join(format!("{h:x}"))
+ && let at = cf.join(SSTORE)
&& at.exists()
{
let x = std::fs::read(at)?;
- let x = bendy::serde::from_bytes::<Editor>(&x)?;
+ let x = bendncode::from_bytes::<Editor>(&x)?;
me = x;
loaded_state = true;
assert!(me.workspace.is_some());
+ if let at = cf.join(FSTORE)
+ && at.exists()
+ {
+ let x = std::fs::read(at)?;
+ freq = bendncode::from_bytes::<Freq>(&x)?;
+ }
}
me.language = n;
me.git_dir = me
@@ -358,7 +366,7 @@ impl Editor {
// },
// );
}
- Ok(me)
+ Ok((me, freq))
}
#[must_use = "please apply this"]
@@ -625,7 +633,7 @@ impl Editor {
.map(|[wo, or]| format!("gracilaria - {wo} - {or}"))
}
- pub fn store(&mut self) -> rootcause::Result<()> {
+ pub fn store(&mut self, fq: &Freq) -> rootcause::Result<()> {
let ws = self.workspace.clone();
let tree = self.tree.clone();
let mtime = self.mtime.clone();
@@ -647,9 +655,11 @@ impl Editor {
let cfgdir = cfgdir();
let p = cfgdir.join(format!("{hash:x}"));
std::fs::create_dir_all(&p)?;
- let b = bendy::serde::to_bytes(&self).unwrap();
- bendy::serde::from_bytes::<Editor>(&b)?;
- std::fs::write(p.join(STORE), &b)?;
+ let b = bendncode::to_bytes(&self)?;
+ bendncode::from_bytes::<Editor>(&b)?;
+ std::fs::write(p.join(SSTORE), &b)?;
+ let b = bendncode::to_bytes(fq)?;
+ std::fs::write(p.join(FSTORE), &b)?;
}
Ok(())
}
@@ -701,13 +711,5 @@ fn cfgdir() -> PathBuf {
.unwrap_or("/tmp/".into())
.join("gracilaria")
}
-const STORE: &str = "state.torrent";
-#[track_caller]
-#[allow(dead_code)]
-fn rtt<T: serde::Serialize + serde::Deserialize<'static>>(
- x: &T,
-) -> Result<T, bendy::serde::Error> {
- bendy::serde::from_bytes::<T>(
- bendy::serde::to_bytes(x).unwrap().leak(),
- )
-}
+const SSTORE: &str = "state.bendn";
+const FSTORE: &str = "freq.bendn";
diff --git a/src/edi/input_handlers/click.rs b/src/edi/input_handlers/click.rs
index 80e4065..4b0857d 100644
--- a/src/edi/input_handlers/click.rs
+++ b/src/edi/input_handlers/click.rs
@@ -17,10 +17,16 @@ impl Editor {
.complete
.consume(CompletionAction::Click)
.inspect_err(|x| log::error!("transition comact {x:?}"));
- let r = self.transition(Action::M(bt));
+
+ let Some(mut o) = self.transition(Action::M(bt)) else { return };
+ if let Do::Reinsert = o {
+ let Some(o2) = self.transition(Action::M(bt)) else { return };
+ o = o2;
+ };
+
let text = &mut self.text;
- match r {
- Some(Do::ClickedHover | Do::MoveCursor) => {
+ match o {
+ Do::MoveCursor => {
text.cursor.just(
text.mapped_index_at(cursor_position),
&text.rope,
@@ -37,13 +43,13 @@ impl Editor {
text.cursor.first().setc(&text.rope);
self.refresh_document_highlights();
}
- Some(Do::NavForward) => self.nav_forward(),
- Some(Do::NavBack) => self.nav_back(),
- Some(Do::ExtendSelectionToMouse) => {
+ Do::NavForward => self.nav_forward(),
+ Do::NavBack => self.nav_back(),
+ Do::ExtendSelectionToMouse => {
let p = text.mapped_index_at(cursor_position);
text.cursor.first_mut().extend_selection_to(p, &text.rope);
}
- Some(Do::StartSelection) => {
+ Do::StartSelection => {
let p = text.mapped_index_at(cursor_position);
let x = *text.cursor.first();
@@ -51,7 +57,7 @@ impl Editor {
text.cursor.first_mut().extend_selection_to(p, &text.rope);
self.hist.lc = text.cursor.clone();
}
- Some(Do::GoToDefinition(tdpp)) => {
+ Do::GoToDefinition(tdpp) => {
dbg!(&tdpp);
if let Some(x) = self.requests.def.result.clone().or_else(|| {
tdpp.zip(lsp!(self)).and_then(|(tdpp, lsp)| {
@@ -72,7 +78,7 @@ impl Editor {
log::error!("gtd: {e}");
}
}
- Some(Do::InsertCursorAtMouse) => {
+ Do::InsertCursorAtMouse => {
text.cursor.add(
text.mapped_index_at(cursor_position),
&text.rope,
@@ -81,7 +87,7 @@ impl Editor {
self.chist.push(text.primary_cursor());
text.cursor.first().setc(&text.rope);
}
- None => {}
+
_ => unreachable!(),
}
}
diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs
index 8250068..6001c60 100644
--- a/src/edi/input_handlers/keyboard.rs
+++ b/src/edi/input_handlers/keyboard.rs
@@ -38,6 +38,7 @@ impl Editor {
else {
return ControlFlow::Continue(());
};
+ dbg!(&o2);
o = o2;
};
@@ -141,12 +142,10 @@ impl Editor {
}
}
Do::SymbolsHandleKey => {
- if let Some(lsp) = lsp!(self) {
- let State::Symbols(Rq { result: Some(x), request }) =
+ if let Some(lsp) = lsp!(self)
+ && let State::Symbols(Rq { result: Some(x), request }) =
&mut self.state
- else {
- unreachable!()
- };
+ {
let ptedit = x.tedit.rope.clone();
if handle2(
&event.logical_key,
@@ -328,8 +327,7 @@ impl Editor {
| Do::ExtendSelectionToMouse
| Do::Hover
| Do::InsertCursorAtMouse
- | Do::SetHovering
- | Do::ClickedHover => panic!(),
+ | Do::SetHovering => panic!(),
Do::Save => match &self.origin {
Some(_) => {
self.transition(Action::Saved);
diff --git a/src/edi/st.rs b/src/edi/st.rs
index c145f21..673d652 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -96,7 +96,7 @@ Hovering(x) => {
K(_) => Default [Reinsert],
M(MouseButton::Left if ctrl()) => Default [GoToDefinition(x.request.map(|x| x.1.1).or(x.result.and_then(|x| x.of.iter().find_map(|x| x.tdpp()))))],
- M(_) => _ [ClickedHover],
+ M(_) => Default [Reinsert],
},
Command(_) => K(Key::Named(Escape)) => Default,
Command(t) => K(Key::Named(Enter) if let Some(Ok(x)) = t.sel(None)) => Default [ProcessCommand((Commands, crate::commands::Cmd) => (t, x))],
diff --git a/src/gotolist.rs b/src/gotolist.rs
index 2e7b304..bed2abf 100644
--- a/src/gotolist.rs
+++ b/src/gotolist.rs
@@ -38,6 +38,7 @@ impl<'a> Key<'a> for (GoTo<'a>, Option<&'a str>) {
}
impl MenuData for GTL {
+ const NAME: &'static str = "!";
type Data = (Vec<(GoTo<'static>, Option<String>)>, Option<O>);
type Element<'a> = (GoTo<'a>, Option<&'a str>);
diff --git a/src/hov.rs b/src/hov.rs
index 48ab1cd..47192e7 100644
--- a/src/hov.rs
+++ b/src/hov.rs
@@ -310,7 +310,7 @@ fn t() {
let (w, h) = (400, 8000);
let (c, r) = dsb::fit(&crate::FONT, ppem, lh, (w, h));
- let cells = markdown2(c, &p(include_str!("vec.md")).unwrap());
+ let cells = markdown2(c, &p(include_str!("vec.md")).unwrap(), None);
dbg!(l(&p(include_str!("vec.md")).unwrap()));
dbg!(cells.len() / c);
dbg!(w, h);
diff --git a/src/main.rs b/src/main.rs
index 9f46bc6..f35d444 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -51,7 +51,6 @@ mod runnables;
mod sym;
mod trm;
-use std::any::TypeId;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::mem::MaybeUninit;
@@ -115,33 +114,44 @@ const FG: [u8; 3] = [204, 202, 194];
const BORDER: [u8; 3] = col!("#ffffff");
static mut __ED: MaybeUninit<Editor> = MaybeUninit::uninit();
+static mut __FREQ: MaybeUninit<Freq> = MaybeUninit::uninit();
+static mut __CLEAN: bool = false;
extern "C" fn cleanup() {
- unsafe { __ED.assume_init_mut().store().unwrap() };
+ unsafe {
+ if __CLEAN == false {
+ __CLEAN = true;
+ match __ED.assume_init_mut().store(__FREQ.assume_init_mut()) {
+ Ok(_) => {}
+ Err(e) => eprintln!("{e}"),
+ };
+ }
+ }
}
extern "C" fn sigint(_: i32) {
cleanup();
std::process::exit(12);
}
-type Freq = FxHashMap<TypeId, FxHashMap<u64, u16>>;
+type FID = u8;
+type Freq = FxHashMap<FID, FxHashMap<u64, u16>>;
pub(crate) fn entry(event_loop: EventLoop) {
unsafe {
- __ED.write(match Editor::new() {
+ let (ed, freq) = match Editor::new() {
Err(e) => {
eprintln!("failure to launch: {e}");
return;
}
Ok(x) => x,
- })
+ };
+ __ED.write(ed);
+ __FREQ.write(freq);
};
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 mut freq: Freq = default();
+ let freq = unsafe { __FREQ.assume_init_mut() };
let ppem = 18.0;
let ls = 20.0;
// let ed = Box::leak(Box::new(ed));
-
let mut fonts = dsb::Fonts::new(
F::FontRef(*FONT, &[]),
F::FontRef(*BFONT, &[]),
@@ -313,7 +323,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
WindowEvent::PointerButton {
button: ButtonSource::Mouse(MouseButton::Left),
..
- } => unsafe { CLICKING = false },
+ } => unsafe { CLICKING = false },
WindowEvent::MouseWheel {
device_id: _,
delta: MouseScrollDelta::LineDelta(_, rows),
@@ -350,7 +360,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
) {
return;
}
- if ed.keyboard(event, window,&mut freq).is_break() {
+ if ed.keyboard(event, window, freq).is_break() {
elwt.exit();
}
window.request_redraw();
diff --git a/src/menu.rs b/src/menu.rs
index 7186908..ca5cb47 100644
--- a/src/menu.rs
+++ b/src/menu.rs
@@ -1,5 +1,4 @@
pub mod generic;
-use std::any::TypeId;
use std::borrow::Cow;
use std::cmp::Reverse;
use std::sync::LazyLock;
@@ -51,7 +50,7 @@ pub fn score<'a, T: Key<'a>, D: MenuData<Element<'a> = T> + 'static>(
.map(move |y| {
if let Some(f) = freq
&& filter == ""
- && let Some(f) = f.get(&TypeId::of::<D>())
+ && let Some(f) = f.get(&D::ID)
{
return (
f.get(&D::hashed(&y).unwrap())
diff --git a/src/menu/generic.rs b/src/menu/generic.rs
index 51be7e7..d2b2395 100644
--- a/src/menu/generic.rs
+++ b/src/menu/generic.rs
@@ -1,4 +1,3 @@
-use std::any::TypeId;
use std::fmt::Debug;
use std::hash::Hash;
use std::path::Path;
@@ -6,9 +5,9 @@ use std::path::Path;
use Default::default;
use dsb::Cell;
-use crate::Freq;
use crate::menu::{Key, back, filter, next, score};
use crate::text::TextArea;
+use crate::{FID, Freq};
pub struct GenericMenu<T: MenuData> {
pub data: T::Data,
@@ -53,7 +52,24 @@ pub enum CorA {
Complete,
Accept,
}
-pub trait MenuData: Sized + 'static {
+
+pub trait ID {
+ const ID: FID;
+}
+impl ID for crate::commands::Cmds {
+ const ID: u8 = 0;
+}
+impl ID for crate::gotolist::GTL {
+ const ID: u8 = 1;
+}
+impl ID for crate::runnables::Runb {
+ const ID: u8 = 2;
+}
+impl ID for crate::sym::Symb {
+ const ID: u8 = 3;
+}
+pub trait MenuData: Sized + 'static + ID {
+ const NAME: &'static str;
const HEIGHT: usize = 30;
type Data;
type Element<'a>: Key<'a>;
@@ -127,6 +143,9 @@ impl<T: MenuData + 'static> GenericMenu<T> {
// coz its bottom up
back::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo);
}
+ pub fn name(&self) -> &'static str {
+ T::NAME
+ }
pub fn sel(
&self,
@@ -144,7 +163,7 @@ impl<T: MenuData + 'static> GenericMenu<T> {
"if calling with freq, please impl hash",
);
- *fq.entry(TypeId::of::<T>())
+ *fq.entry(T::ID)
.or_default()
.entry(x)
.or_default() += 1;
diff --git a/src/runnables.rs b/src/runnables.rs
index ee3970d..287868c 100644
--- a/src/runnables.rs
+++ b/src/runnables.rs
@@ -16,6 +16,7 @@ use crate::trm;
pub enum Runb {}
impl MenuData for Runb {
+ const NAME: &'static str = "runnables";
type Data = Vec<Runnable>;
type Element<'a> = &'a Runnable;
diff --git a/src/sym.rs b/src/sym.rs
index c569741..1ceb2b4 100644
--- a/src/sym.rs
+++ b/src/sym.rs
@@ -17,6 +17,7 @@ use crate::rnd::simplify_path;
use crate::text::{Bookmarks, col, color_, set_a};
pub enum Symb {}
impl MenuData for Symb {
+ const NAME: &'static str = "symbols";
type Data = (
SymbolsList,
Vec<SymbolInformation>,
diff --git a/src/text.rs b/src/text.rs
index 923a23d..4c56712 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -1353,7 +1353,7 @@ fn apply() {
}
"#,
);
-
+ use lsp_types::*;
t.apply_snippet(&TextEdit {
range: lsp_types::Range {
start: Position { line: 0, character: 8 },
@@ -1386,7 +1386,7 @@ fn apply2() {
}",
);
- use lsp_types::Range;
+ use lsp_types::*;
let mut th = [
TextEdit {
range: Range {
@@ -1468,7 +1468,7 @@ fn inlays() {
let mut t = TextArea::default();
_ = t.insert("let x = 4;");
t.set_inlay(&[InlayHint {
- position: Position { line: 0, character: 4 },
+ position: lsp_types::Position { line: 0, character: 4 },
label: InlayHintLabel::String("u".into()),
kind: Some(lsp_types::InlayHintKind::TYPE),
text_edits: None,
@@ -1486,7 +1486,10 @@ fn inlays() {
Char('t', 2, 2),
Char(' ', 3, 3),
Fake(
- &Marking { position: 4, data: Box::new([('u', None)]) },
+ Cow::Owned(Marking {
+ position: 4,
+ data: vec![('u', None)].into_boxed_slice(),
+ }),
0,
4,
'u'
diff --git a/src/text/inlay.rs b/src/text/inlay.rs
index 37b98cf..6712069 100644
--- a/src/text/inlay.rs
+++ b/src/text/inlay.rs
@@ -37,7 +37,7 @@ impl TextArea {
pub fn set_inlay(&mut self, inlay: &[InlayHint]) {
self.inlays = inlay
.iter()
- .map(|i| {
+ .filter_map(|i| {
let mut label = match &i.label {
InlayHintLabel::String(x) =>
x.chars().map(|x| (x, None)).collect::<Vec<_>>(),
@@ -56,8 +56,8 @@ impl TextArea {
if i.padding_right == Some(true) {
label.push((' ', None));
}
- let position = self.l_position(i.position).unwrap() as _;
- Marking { position, data: label.into() }
+ let position = self.l_position(i.position)? as _;
+ Some(Marking { position, data: label.into() })
})
.collect();
}
diff --git a/src/text/semantic_tokens.rs b/src/text/semantic_tokens.rs
index f7c414a..8b09851 100644
--- a/src/text/semantic_tokens.rs
+++ b/src/text/semantic_tokens.rs
@@ -14,8 +14,11 @@ use crate::text::manipulations::Manip;
Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct TokenD {
+ #[serde(rename = "0")]
pub range: (u32, u32),
+ #[serde(rename = "1")]
pub ty: u32,
+ #[serde(rename = "2")]
pub modifiers: u32,
}
impl TokenD {