A simple CPU rendered GUI IDE experience.
-rw-r--r--Cargo.toml38
-rw-r--r--src/edi/input_handlers.rs10
-rw-r--r--src/edi/input_handlers/click.rs7
-rw-r--r--src/edi/input_handlers/cursor.rs18
-rw-r--r--src/edi/input_handlers/keyboard.rs151
-rw-r--r--src/edi/st.rs38
-rw-r--r--src/main.rs8
7 files changed, 126 insertions, 144 deletions
diff --git a/Cargo.toml b/Cargo.toml
index a51fc46..00303e4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,19 +9,19 @@ fimg = { git = "https://git.bendn.org/fimg" }
pattypan = { git = "https://git.bendn.org/pattypan" }
implicit-fn = "0.1.0"
ropey = "1.6.1"
-softbuffer = "0.4.6"
-swash = "0.2.5"
+softbuffer = "0.4.8"
+swash = "0.2.7"
winit = "0.31.0-beta.2"
-tree-sitter = "0.25.0"
-memchr = "2.7.5"
-lower = "0.2.0"
+tree-sitter = "0.25.10"
+memchr = "2.8.1"
+lower = "0.2.1"
amap = "0.1.4"
run_times = "0.1.0"
array_chunks = "1.0.0"
rust-fsm = { git = "https://git.bendn.org/rust-fsm", features = ["diagram"] }
-clipp = "0.1.0"
-regex = { version = "1.11.3", features = ["unstable", "use_std"] }
+clipp = "0.1.1"
+regex = { version = "1.12.3", features = ["unstable", "use_std"] }
tree-house = { version = "0.3.0", features = ["fixtures"] }
# for tree house grammar loading
@@ -36,30 +36,30 @@ rust-analyzer = { git = "https://git.bendn.org/rust-analyzer" }
# lsp-server = { path = "../rust-analyzer/lib/lsp-server" }
# rust-analyzer = { path = "../rust-analyzer/crates/rust-analyzer" }
-serde_json = "1.0.145"
+serde_json = "1.0.150"
serde = { version = "1.0.228", features = ["unstable"] }
serde_derive = "1.0.228"
-log = "0.4.28"
+log = "0.4.30"
crossbeam = { version = "0.8.4", features = ["nightly", "crossbeam-channel"] }
-test-log = "0.2.18"
-env_logger = "0.11.8"
-url = "2.5.7"
-tokio = { version = "1.47.1", features = ["rt-multi-thread", "sync", "time"] }
+test-log = "0.2.20"
+env_logger = "0.11.10"
+url = "2.5.8"
+tokio = { version = "1.52.3", features = ["rt-multi-thread", "sync", "time"] }
regex-cursor = "0.1.5"
-papaya = "0.2.3"
+papaya = "0.2.4"
markdown = "1.0.0"
itertools = "0.14.0"
-pin-project = "1.1.10"
+pin-project = "1.1.13"
replace_with = "0.1.8"
nucleo = "0.5.0"
-tokio-util = { version = "0.7.17", features = ["rt"] }
+tokio-util = { version = "0.7.18", features = ["rt"] }
scopeguard = "1.2.0"
-arc-swap = "1.7.1"
-atools = "0.1.10"
+arc-swap = "1.9.1"
+atools = "0.1.12"
swizzle = "0.1.0"
walkdir = "2.5.0"
niri = { package = "niri-ipc", version = "25.11.0" }
-libc = "0.2.180"
+libc = "0.2.186"
rustc-hash = "=2.1.1"
bendy = { version = "0.6.1", features = ["serde"] }
git2 = "0.20.4"
diff --git a/src/edi/input_handlers.rs b/src/edi/input_handlers.rs
index 6457787..e169edb 100644
--- a/src/edi/input_handlers.rs
+++ b/src/edi/input_handlers.rs
@@ -58,3 +58,13 @@ pub fn handle2<'a>(
};
None
}
+impl Editor {
+ #[track_caller]
+ pub fn transition(&mut self, a: Action) -> Option<Do> {
+ self.state
+ .consume(a)
+ .inspect_err(|e| log::error!("transition failed: {e}"))
+ .ok()
+ .flatten()
+ }
+}
diff --git a/src/edi/input_handlers/click.rs b/src/edi/input_handlers/click.rs
index d687c60..80e4065 100644
--- a/src/edi/input_handlers/click.rs
+++ b/src/edi/input_handlers/click.rs
@@ -12,13 +12,14 @@ impl Editor {
cursor_position: (usize, usize),
w: Arc<dyn Window>,
) {
- let text = &mut self.text;
_ = self
.requests
.complete
.consume(CompletionAction::Click)
- .unwrap();
- match self.state.consume(Action::M(bt)).unwrap() {
+ .inspect_err(|x| log::error!("transition comact {x:?}"));
+ let r = self.transition(Action::M(bt));
+ let text = &mut self.text;
+ match r {
Some(Do::ClickedHover | Do::MoveCursor) => {
text.cursor.just(
text.mapped_index_at(cursor_position),
diff --git a/src/edi/input_handlers/cursor.rs b/src/edi/input_handlers/cursor.rs
index 092bc5d..ce44657 100644
--- a/src/edi/input_handlers/cursor.rs
+++ b/src/edi/input_handlers/cursor.rs
@@ -26,7 +26,7 @@ impl Editor {
w: Arc<dyn Window>,
c: usize,
) {
- match self.state.consume(Action::C(cursor_position)).unwrap() {
+ match self.transition(Action::C(cursor_position)) {
Some(Do::ExtendSelectionToMouse) => {
let p = self.text.mapped_index_at(cursor_position);
self.text
@@ -53,9 +53,7 @@ impl Editor {
&& !e.is_whitespace() =>
'out: {
match self
- .state
- .consume(Action::HOnSomething(cursor_position))
- .unwrap()
+ .transition(Action::HOnSomething(cursor_position))
{
Some(Do::SetHovering) => {
let State::Hovering(l) = &mut self.state else {
@@ -358,13 +356,11 @@ impl Editor {
});
let diags = self.find_diags(cursor_position, &w);
println!("requesting hover");
- self.state
- .consume(Action::SetHovering(
- diags.map(|of| Hovring { of, ..default() }),
- handle,
- (cursor_position, tdpp),
- ))
- .unwrap();
+ self.transition(Action::SetHovering(
+ diags.map(|of| Hovring { of, ..default() }),
+ handle,
+ (cursor_position, tdpp),
+ ));
// self.requests.hovering.request =
// (DropH::new(handle), cursor_position).into();
// requests.hovering.result = None;
diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs
index f61a338..8250068 100644
--- a/src/edi/input_handlers/keyboard.rs
+++ b/src/edi/input_handlers/keyboard.rs
@@ -27,26 +27,27 @@ impl Editor {
window: &mut Arc<dyn Window>,
freq: &mut Freq,
) -> ControlFlow<()> {
- let mut o: Option<Do> = self
- .state
- .consume(Action::K(event.logical_key.clone()))
- .unwrap();
+ let Some(mut o) =
+ self.transition(Action::K(event.logical_key.clone()))
+ else {
+ return ControlFlow::Continue(());
+ };
+ if let Do::Reinsert = o {
+ let Some(o2) =
+ self.transition(Action::K(event.logical_key.clone()))
+ else {
+ return ControlFlow::Continue(());
+ };
+ o = o2;
+ };
match o {
- Some(Do::Reinsert) =>
- o = self
- .state
- .consume(Action::K(event.logical_key.clone()))
- .unwrap(),
- _ => {}
- }
- match o {
- Some(Do::Escape) => {
+ Do::Escape => {
take(&mut self.requests.complete);
take(&mut self.requests.sig_help);
self.text.cursor.alone();
}
- Some(Do::Comment(p)) => {
+ Do::Comment(p) => {
ceach!(self.text.cursor, |cursor| {
Some(
if let Some(x) = cursor.sel
@@ -62,7 +63,7 @@ impl Editor {
self.text.cursor.clear_selections();
change!(self, window.clone());
}
- Some(Do::SpawnTerminal) => {
+ Do::SpawnTerminal => {
if let Err(e) = trm::toggle(
self.workspace
.as_deref()
@@ -71,12 +72,12 @@ impl Editor {
log::error!("opening terminal failed {e}");
}
}
- Some(Do::MatchingBrace) =>
+ Do::MatchingBrace =>
if let Some((l, f)) = lsp!(self + p) {
l.matching_brace(f, &mut self.text)
},
- Some(Do::DeleteBracketPair) => self.delete_bracket_pair(),
- Some(Do::Symbols) =>
+ Do::DeleteBracketPair => self.delete_bracket_pair(),
+ Do::Symbols =>
if let Some((lsp, o)) = lsp!(self + p)
&& let Ok(syms) = lsp.workspace_symbols("".into())
{
@@ -92,7 +93,7 @@ impl Editor {
));
self.state = State::Symbols(q);
},
- Some(Do::SwitchType) =>
+ Do::SwitchType =>
if let Some((lsp, p)) = lsp!(self + p) {
let State::Symbols(Rq { result: Some(x), request }) =
&mut self.state
@@ -113,7 +114,7 @@ impl Editor {
));
}
},
- Some(Do::ProcessCommand(mut x, z)) =>
+ Do::ProcessCommand(mut x, z) =>
match Cmds::complete_or_accept(&z) {
crate::menu::generic::CorA::Complete => {
x.tedit.rope =
@@ -129,7 +130,7 @@ impl Editor {
}
}
},
- Some(Do::CmdTyped) => {
+ Do::CmdTyped => {
let State::Command(x) = &self.state else {
unreachable!()
};
@@ -139,7 +140,7 @@ impl Editor {
self.text.scroll_to_ln_centering(x as _);
}
}
- Some(Do::SymbolsHandleKey) => {
+ Do::SymbolsHandleKey => {
if let Some(lsp) = lsp!(self) {
let State::Symbols(Rq { result: Some(x), request }) =
&mut self.state
@@ -183,7 +184,7 @@ impl Editor {
}
}
}
- Some(Do::SymbolsSelectNext) => {
+ Do::SymbolsSelectNext => {
let State::Symbols(Rq { result: Some(x), .. }) =
&mut self.state
else {
@@ -203,7 +204,7 @@ impl Editor {
}
}
}
- Some(Do::SymbolsSelectPrev) => {
+ Do::SymbolsSelectPrev => {
let State::Symbols(Rq { result: Some(x), .. }) =
&mut self.state
else {
@@ -223,15 +224,15 @@ impl Editor {
}
}
}
- Some(Do::SymbolsSelect(x)) =>
+ Do::SymbolsSelect(x) =>
if let Some(Ok(x)) = x.sel(Some(freq))
&& let Err(e) = self.go(x.at, window.clone())
{
log::error!("alas! {e}")
},
- Some(Do::RenameSymbol(to)) => self.rename_symbol(to),
- Some(Do::CodeAction) => self.request_code_actions(),
- Some(Do::CASelectLeft) => {
+ Do::RenameSymbol(to) => self.rename_symbol(to),
+ Do::CodeAction => self.request_code_actions(),
+ Do::CASelectLeft => {
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
else {
@@ -239,7 +240,7 @@ impl Editor {
};
c.left();
}
- Some(Do::CASelectRight) => 'out: {
+ Do::CASelectRight => 'out: {
let Some(lsp) = lsp!(self) else { unreachable!() };
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
@@ -260,7 +261,7 @@ impl Editor {
log::error!("{e}");
}
}
- Some(Do::CASelectNext) => {
+ Do::CASelectNext => {
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
else {
@@ -268,7 +269,7 @@ impl Editor {
};
c.down();
}
- Some(Do::CASelectPrev) => {
+ Do::CASelectPrev => {
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
else {
@@ -276,7 +277,7 @@ impl Editor {
};
c.up();
}
- Some(Do::GoToMatch)
+ Do::GoToMatch
if let Some(x) =
&self.requests.document_highlights.result =>
'out: {
@@ -314,37 +315,36 @@ impl Editor {
}
}
}
- Some(Do::GoToMatch) =>
+ Do::GoToMatch =>
if self.requests.document_highlights.request.is_none() {
self.refresh_document_highlights();
},
- Some(Do::NavBack) => self.nav_back(),
- Some(Do::NavForward) => self.nav_forward(),
- Some(
- Do::Reinsert
- | Do::GoToDefinition(_)
- | Do::MoveCursor
- | Do::ExtendSelectionToMouse
- | Do::Hover
- | Do::InsertCursorAtMouse
- | Do::SetHovering
- | Do::ClickedHover,
- ) => panic!(),
- Some(Do::Save) => match &self.origin {
+ Do::NavBack => self.nav_back(),
+ Do::NavForward => self.nav_forward(),
+
+ Do::Reinsert
+ | Do::GoToDefinition(_)
+ | Do::MoveCursor
+ | Do::ExtendSelectionToMouse
+ | Do::Hover
+ | Do::InsertCursorAtMouse
+ | Do::SetHovering
+ | Do::ClickedHover => panic!(),
+ Do::Save => match &self.origin {
Some(_) => {
- self.state.consume(Action::Saved).unwrap();
+ self.transition(Action::Saved);
self.save();
}
None => {
- self.state.consume(Action::RequireFilename).unwrap();
+ self.transition(Action::RequireFilename);
}
},
- Some(Do::SaveTo(x)) => {
+ Do::SaveTo(x) => {
self.origin = Some(PathBuf::try_from(x).unwrap());
self.save();
}
- Some(Do::Edit) => self.handle_edit(event),
- Some(Do::Undo) => {
+ Do::Edit => self.handle_edit(event),
+ Do::Undo => {
self.hist.test_push(&mut self.text);
if let Err(e) = self.hist.undo(&mut self.text) {
eprintln!("undo failed: {e}");
@@ -353,14 +353,14 @@ impl Editor {
change!(self, window.clone());
}
- Some(Do::Redo) => {
+ Do::Redo => {
self.hist.test_push(&mut self.text);
self.hist.redo(&mut self.text).unwrap();
self.bar.last_action = "redid".to_string();
change!(self, window.clone());
}
- Some(Do::Quit) => return ControlFlow::Break(()),
- Some(Do::SetCursor(x)) => {
+ Do::Quit => return ControlFlow::Break(()),
+ Do::SetCursor(x) => {
self.text.cursor.each(|c| {
let Some(r) = c.sel else { return };
match x {
@@ -370,7 +370,7 @@ impl Editor {
});
self.text.cursor.clear_selections();
}
- Some(Do::StartSelection) => {
+ Do::StartSelection => {
let Key::Named(y) = event.logical_key else { panic!() };
// let mut z = vec![];
self.text.cursor.each(|x| {
@@ -385,7 +385,7 @@ impl Editor {
});
// *self.state.sel() = z;
}
- Some(Do::UpdateSelection) => {
+ Do::UpdateSelection => {
let Key::Named(y) = event.logical_key else { panic!() };
self.text.cursor.each(|x| {
x.extend_selection(
@@ -400,7 +400,7 @@ impl Editor {
self.text.scroll_to_cursor();
inlay!(self);
}
- Some(Do::Insert(c)) => {
+ Do::Insert(c) => {
// self.text.cursor.inner.clear();
self.hist.push_if_changed(&mut self.text);
ceach!(self.text.cursor, |cursor| {
@@ -413,7 +413,7 @@ impl Editor {
self.hist.push_if_changed(&mut self.text);
change!(self, window.clone());
}
- Some(Do::Delete) => {
+ Do::Delete => {
self.hist.push_if_changed(&mut self.text);
ceach!(self.text.cursor, |cursor| {
let Some(r) = cursor.sel else { return };
@@ -424,7 +424,7 @@ impl Editor {
change!(self, window.clone());
}
- Some(Do::Copy) => {
+ Do::Copy => {
self.hist.push_if_changed(&mut self.text);
unsafe { take(&mut META) };
let mut clip = String::new();
@@ -446,7 +446,7 @@ impl Editor {
self.hist.push_if_changed(&mut self.text);
change!(self, window.clone());
}
- Some(Do::Cut) => {
+ Do::Cut => {
self.hist.push_if_changed(&mut self.text);
unsafe { take(&mut META) };
let mut clip = String::new();
@@ -473,7 +473,7 @@ impl Editor {
self.hist.push_if_changed(&mut self.text);
change!(self, window.clone());
}
- Some(Do::PasteOver) => {
+ Do::PasteOver => {
self.hist.push_if_changed(&mut self.text);
ceach!(self.text.cursor, |cursor| {
let Some(r) = cursor.sel else { return };
@@ -483,11 +483,11 @@ impl Editor {
self.paste();
// self.hist.push_if_changed(&mut self.text);
}
- Some(Do::Paste) => self.paste(),
- Some(Do::OpenFile(x)) => {
+ Do::Paste => self.paste(),
+ Do::OpenFile(x) => {
_ = self.open(Path::new(&x), window.clone());
}
- Some(Do::StartSearch(x)) => {
+ Do::StartSearch(x) => {
let s = Regex::new(&x).unwrap();
let n = s
.find_iter(&self.text.rope.to_string())
@@ -510,7 +510,7 @@ impl Editor {
self.bar.last_action = "no matches".into()
});
}
- Some(Do::SearchChanged) => {
+ Do::SearchChanged => {
let (re, index, _) = self.state.search();
let s = self.text.rope.to_string();
let m = re.find_iter(&s).nth(*index).unwrap();
@@ -521,7 +521,7 @@ impl Editor {
self.text.scroll_to_cursor_centering();
inlay!(self);
}
- Some(Do::Boolean(BoolRequest::ReloadFile, true)) => {
+ Do::Boolean(BoolRequest::ReloadFile, true) => {
self.hist.push_if_changed(&mut self.text);
self.text.rope = Rope::from_str(
&std::fs::read_to_string(
@@ -540,8 +540,8 @@ impl Editor {
self.bar.last_action = "reloaded".into();
self.hist.push(&mut self.text)
}
- Some(Do::Boolean(BoolRequest::ReloadFile, false)) => {}
- Some(Do::InsertCursor(dir)) => {
+ Do::Boolean(BoolRequest::ReloadFile, false) => {}
+ Do::InsertCursor(dir) => {
let (x, y) = match dir {
Direction::Above => self.text.cursor.min(),
Direction::Below => self.text.cursor.max(),
@@ -554,7 +554,7 @@ impl Editor {
let position = self.text.line_to_char(y);
self.text.cursor.add(position + x, &self.text.rope);
}
- Some(Do::Run(x)) =>
+ Do::Run(x) =>
if let Some((l, ws)) =
lsp!(self).zip(self.workspace.as_deref())
{
@@ -562,7 +562,7 @@ impl Editor {
.block_on(crate::runnables::run(x, ws))
.unwrap();
},
- Some(Do::GoToImplementations) => {
+ Do::GoToImplementations => {
let State::GoToL(x) = &mut self.state else {
unreachable!()
};
@@ -574,13 +574,13 @@ impl Editor {
)));
}
}
- Some(Do::GTLSelect(x)) =>
+ Do::GTLSelect(x) =>
if let Some(Ok((g, _))) = x.sel(None)
&& let Err(e) = self.go(g, window.clone())
{
eprintln!("go-to-list select fail: {e}");
},
- Some(Do::GT) => {
+ Do::GT => {
let State::GoToL(x) = &mut self.state else {
unreachable!()
};
@@ -593,7 +593,6 @@ impl Editor {
// self.text.vo = self.text.char_to_line(x.start);
}
}
- None => {}
}
ControlFlow::Continue(())
}
@@ -699,7 +698,11 @@ impl Editor {
.requests
.complete
.consume(CompletionAction::K(event.logical_key.as_ref()))
- .unwrap()
+ .inspect_err(|e| {
+ log::error!("failure: {e}");
+ })
+ .ok()
+ .flatten()
{
Some(CDo::Request(ctx)) => {
if let Ok(fut) = lsp.request_complete(
diff --git a/src/edi/st.rs b/src/edi/st.rs
index 3fe6b31..c145f21 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -93,43 +93,7 @@ Hovering(x) => {
C(_) => _ [Hover],
MovedOut => Default,
Scrolled => Default,
- // reconsidering
- K(Key::Character("s") if ctrl()) => Save [Save],
- K(Key::Character("q") if ctrl()) => Dead [Quit],
- K(Key::Character("v") if ctrl()) => Default [Paste],
- K(Key::Character("z") if ctrl()) => Default [Undo],
- K(Key::Character("d") if ctrl()) => Default [GoToMatch],
- K(Key::Character("y") if ctrl()) => Default [Redo],
- K(Key::Character("f") if ctrl()) => Procure((default(), InputRequest::Search)),
- K(Key::Character("o") if ctrl()) => Procure((default(), InputRequest::OpenFile)),
- K(Key::Character("c") if ctrl()) => Default ,
- K(Key::Character("l") if ctrl()) => Default [Symbols],
- K(Key::Character(".") if ctrl()) => Default [CodeAction],
- K(Key::Character("0") if ctrl()) => Default [MatchingBrace],
- K(Key::Character("`") if ctrl()) => Default [SpawnTerminal],
- K(Key::Character("/") if ctrl()) => Default [Comment(State => State::Default)],
- K(Key::Character("p") if ctrl()) => Command(Commands => default()),
- K(Key::Named(Backspace) if alt()) => Default [DeleteBracketPair],
- K(Key::Named(F1)) => Procure((default(), InputRequest::RenameSymbol)),
- K(Key::Named(F10)) => GoToL(GoToList => default()) [GoToImplementations],
- K(Key::Named(k @ (ArrowUp | ArrowDown)) if alt()) => Default [InsertCursor(Direction => {
- if k == ArrowUp {Direction::Above} else { Direction::Below }
- })],
- K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End) if shift()) => Selection [StartSelection],
- M(MouseButton::Left if shift()) => Selection [StartSelection],
- M(MouseButton::Left if alt()) => Default [InsertCursorAtMouse],
- M(MouseButton::Left if ctrl()) => Default [GoToDefinition(Option<TextDocumentPositionParams> => None)],
- M(MouseButton::Left) => Default [MoveCursor],
- K(Key::Character("=") if ctrl()) => Default [NavForward],
- K(Key::Character("-") if ctrl()) => Default [NavBack],
- M(MouseButton::Back) => Default [NavBack],
- M(MouseButton::Forward) => _ [NavForward],
- C(((usize, usize)) => .. if unsafe { CLICKING }) => Selection [StartSelection],
- Changed => RequestBoolean(BoolRequest => BoolRequest::ReloadFile),
- K(Key::Named(Escape)) => Default [Escape],
- K(_) => Default [Edit],
- // duplicate zone
-
+ 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],
diff --git a/src/main.rs b/src/main.rs
index 95d2c5e..9f46bc6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -322,6 +322,14 @@ pub(crate) fn entry(event_loop: EventLoop) {
ed.scroll(rows);
window.request_redraw();
}
+ WindowEvent::MouseWheel {
+ device_id: _,
+ delta: MouseScrollDelta::PixelDelta(PhysicalPosition { x:_, y }),
+ phase: _,
+ } => {
+ ed.scroll(y as f32 *5.0);
+ window.request_redraw();
+ }
WindowEvent::ModifiersChanged(modifiers) => {
unsafe { MODIFIERS = modifiers.state() };
window.request_redraw();