A simple CPU rendered GUI IDE experience.
-rw-r--r--src/edi/input_handlers/click.rs12
-rw-r--r--src/edi/input_handlers/keyboard.rs48
-rw-r--r--src/edi/st.rs1
-rw-r--r--src/rnd.rs208
-rw-r--r--src/text.rs8
5 files changed, 159 insertions, 118 deletions
diff --git a/src/edi/input_handlers/click.rs b/src/edi/input_handlers/click.rs
index 0998d46..692be1a 100644
--- a/src/edi/input_handlers/click.rs
+++ b/src/edi/input_handlers/click.rs
@@ -33,21 +33,11 @@ impl Editor {
),
));
}
- self.requests.document_highlights.request(
- lsp.runtime.spawn(
- lsp.document_highlights(
- path,
- text.to_l_position(
- text.cursor.first().position,
- )
- .unwrap(),
- ),
- ),
- );
}
self.hist.lc = text.cursor.clone();
self.chist.push(text.primary_cursor());
text.cursor.first().setc(&text.rope);
+ self.refresh_document_highlights();
}
Some(Do::NavForward) => self.nav_forward(),
Some(Do::NavBack) => self.nav_back(),
diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs
index f9c8ee6..a2c76f8 100644
--- a/src/edi/input_handlers/keyboard.rs
+++ b/src/edi/input_handlers/keyboard.rs
@@ -12,6 +12,7 @@ use ropey::Rope;
use rust_analyzer::lsp::ext::OnTypeFormatting;
use rust_fsm::StateMachine;
use tokio_util::task::AbortOnDropHandle as DropH;
+use ttools::{IteratorOfTuples, IteratorOfTuplesWithF, fns, hrf};
use winit::event::KeyEvent;
use winit::keyboard::Key;
use winit::window::Window;
@@ -274,6 +275,40 @@ impl Editor {
};
c.up();
}
+ Some(Do::GoToMatch)
+ if let Some(x) =
+ &self.requests.document_highlights.result =>
+ {
+ let lc = &self
+ .text
+ .cursor
+ .iter()
+ .max_by_key(|x| x.position)
+ .unwrap();
+ let n = x
+ .iter()
+ .zip(0..)
+ .filter_map_at::<0>(|x| self.text.l_range(x.range))
+ .filter_on::<0>(hrf(|x: &std::ops::Range<usize>| {
+ x.contains(lc)
+ }))
+ .max_by_key(|x| x.0.start)
+ .unwrap()
+ .1;
+
+ let p = self
+ .text
+ .l_position(x[(n + 1) % x.len()].range.start)
+ .unwrap();
+ self.text.scroll_to(p);
+ if !self.text.cursor.iter().any(|x| *x == p) {
+ self.text.cursor.add(p, &self.text.rope);
+ }
+ }
+ Some(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(
@@ -792,4 +827,17 @@ impl Editor {
self.state = State::CodeAction(Rq::new(lsp.runtime.spawn(r)));
}
+ pub fn refresh_document_highlights(&mut self) {
+ lsp!(let lsp, path = self);
+ self.requests.document_highlights.request(
+ lsp.runtime.spawn(
+ lsp.document_highlights(
+ path,
+ self.text
+ .to_l_position(self.text.cursor.first().position)
+ .unwrap(),
+ ),
+ ),
+ );
+ }
}
diff --git a/src/edi/st.rs b/src/edi/st.rs
index cf6c243..859ce4f 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -43,6 +43,7 @@ Default => {
K(Key::Character("q") if ctrl()) => Dead [Quit],
K(Key::Character("v") if ctrl()) => _ [Paste],
K(Key::Character("z") if ctrl()) => _ [Undo],
+ K(Key::Character("d") if ctrl()) => _ [GoToMatch],
K(Key::Character("y") if ctrl()) => _ [Redo],
K(Key::Character("f") if ctrl()) => Procure((default(), InputRequest::Search)),
K(Key::Character("o") if ctrl()) => Procure((default(), InputRequest::OpenFile)),
diff --git a/src/rnd.rs b/src/rnd.rs
index cf6b58b..6cf8f5d 100644
--- a/src/rnd.rs
+++ b/src/rnd.rs
@@ -4,6 +4,7 @@ use std::sync::{Arc, LazyLock};
use std::time::Instant;
use atools::prelude::*;
+pub use cell_buffer::CellBuffer;
use dsb::Cell;
use dsb::cell::Style;
use fimg::pixels::Blend;
@@ -20,16 +21,14 @@ use crate::edi::st::State;
use crate::edi::{Editor, lsp};
use crate::gotolist::{At, GoTo};
use crate::lsp::Rq;
-use crate::sym::{UsedSI};
+use crate::sym::UsedSI;
use crate::text::{CoerceOption, RopeExt, col, color_};
use crate::{
BG, BORDER, CompletionAction, CompletionState, FG, FONT, complete,
filter, lsp, sig,
};
-pub use cell_buffer::CellBuffer;
mod cell_buffer;
-
#[implicit_fn::implicit_fn]
pub fn render(
ed: &mut Editor,
@@ -84,10 +83,12 @@ pub fn render(
style: Style { fg: BG, secondary_color: BG, bg: BG, flags: 0 },
letter: None,
});
- let bmks = text.bookmarks .iter().filter_map(|x| {
- text.try_char_to_line(x.position).ok()
- }).collect::<Vec<_>>();
-
+ let bmks = text
+ .bookmarks
+ .iter()
+ .filter_map(|x| text.try_char_to_line(x.position).ok())
+ .collect::<Vec<_>>();
+
let z = match &ed.state {
State::Selection => Some(
text.cursor
@@ -98,7 +99,7 @@ pub fn render(
),
_ => None,
};
-
+
text.line_numbers(
(c, r - 1),
[67, 76, 87],
@@ -107,17 +108,20 @@ pub fn render(
(1, 0),
|_text, mut f, y| {
if let State::GoToL(menu) = &ed.state
- && let Some(Ok(( GoTo{ at: At::R(r),path}, _))) = menu.sel()
+ && let Some(Ok((GoTo { at: At::R(r), path }, _))) =
+ menu.sel()
&& Some(&*path) == ed.origin.as_deref()
- {
+ {
if (r.start.line..=r.end.line).contains(&(y as _)) {
f.style.fg = col!("#FFCC66");
}
}
if let State::Symbols(Rq { result: Some(menu), .. }) =
&ed.state
- && let Some(Ok(UsedSI { at: GoTo{ at: At::R(x),..}, .. })) =
- menu.sel()
+ && let Some(Ok(UsedSI {
+ at: GoTo { at: At::R(x), .. },
+ ..
+ })) = menu.sel()
{
if (x.start.line..=x.end.line).contains(&(y as _)) {
f.style.fg = col!("#FFCC66");
@@ -553,100 +557,96 @@ pub fn render(
&lsp.diagnostics.guard(),
)
{
- let dawg = diag.iter().filter(|diag| {
- text.l_range(diag.range).is_some_and(|x| {
- x.contains(&text.mapped_index_at(cursor_position))
- && (text.vo..text.vo + r)
- .contains(&(diag.range.start.line as _))
- })
- });
- for diag in dawg {
- match diag
- .data
- .as_ref()
- .unwrap_or_default()
- .get("rendered")
+ 'out: {
+ let dawgs = diag.iter().filter(|diag| {
+ text.l_range(diag.range).is_some_and(|x| {
+ x.contains(&text.mapped_index_at(cursor_position))
+ && (text.vo..text.vo + r)
+ .contains(&(diag.range.start.line as _))
+ })
+ });
+ let Some(diag) = dawgs.clone().next() else { break 'out };
+ let dawg = dawgs
+ .filter_map(|x| {
+ x.data
+ .as_ref()
+ .unwrap_or_default()
+ .get("rendered")
+ .and_then(serde_json::Value::as_str)
+ })
+ .collect::<String>();
+
+ let mut t = pattypan::term::Terminal::new(
+ (95, (r.saturating_sub(5)) as _),
+ false,
+ );
+ for b in simplify_path(
+ &dawg.replace('\n', "\r\n").replace("⸬", ":"),
+ )
+ .bytes()
{
- Some(x) if let Some(x) = x.as_str() => {
- let mut t = pattypan::term::Terminal::new(
- (95, (r.saturating_sub(5)) as _),
- false,
- );
- for b in simplify_path(
- &x.replace('\n', "\r\n").replace("⸬", ":"),
- )
- .bytes()
- {
- t.rx(
- b,
- std::fs::File::open("/dev/null")
- .unwrap()
- .as_fd(),
- );
- }
- let y_lim = t
- .cells
- .rows()
- .position(|x| x.iter().all(_.letter.is_none()))
- .unwrap_or(20);
- let c = t.cells.c() as usize;
- let Some(x_lim) = t
- .cells
- .rows()
- .map(
- _.iter()
- .rev()
- .take_while(_.letter.is_none())
- .count(),
- )
- .map(|x| c - x)
- .max()
- else {
- continue;
- };
- let n = t
- .cells
- .rows()
- .take(y_lim)
- .flat_map(|x| &x[..x_lim])
- .copied()
- .collect::<Vec<_>>();
- let Ok((_, left, top, w, h)) = place_around(
- {
- let (x, y) = text.map_to_visual((
- diag.range.start.character as _,
- diag.range.start.line as usize,
- ));
- (
- x + text.line_number_offset() + 1,
- y - text.vo,
- )
- },
- i.copy(),
- &*n,
- x_lim,
- 17.0,
- 0.,
- 0.,
- 0.,
- 0.,
- true,
- ) else {
- continue;
- };
- pass = false;
- i.r#box(
- (
- left.saturating_sub(1) as _,
- top.saturating_sub(1) as _,
- ),
- w as _,
- h as _,
- BORDER,
- );
- }
- _ => {}
+ t.rx(
+ b,
+ std::fs::File::open("/dev/null").unwrap().as_fd(),
+ );
}
+ let y_lim = t
+ .cells
+ .rows()
+ .position(|x| x.iter().all(_.letter.is_none()))
+ .unwrap_or(20);
+ let c = t.cells.c() as usize;
+ let Some(x_lim) = t
+ .cells
+ .rows()
+ .map(
+ _.iter()
+ .rev()
+ .take_while(_.letter.is_none())
+ .count(),
+ )
+ .map(|x| c - x)
+ .max()
+ else {
+ break 'out;
+ };
+ let n = t
+ .cells
+ .rows()
+ .take(y_lim)
+ .flat_map(|x| &x[..x_lim])
+ .copied()
+ .collect::<Vec<_>>();
+ let Ok((_, left, top, w, h)) = place_around(
+ {
+ let (x, y) = text.map_to_visual((
+ diag.range.start.character as _,
+ diag.range.start.line as usize,
+ ));
+ (x + text.line_number_offset() + 1, y - text.vo)
+ },
+ i.copy(),
+ &*n,
+ x_lim,
+ 17.0,
+ 0.,
+ 0.,
+ 0.,
+ 0.,
+ true,
+ ) else {
+ break 'out;
+ };
+ pass = false;
+ i.r#box(
+ (
+ left.saturating_sub(1) as _,
+ top.saturating_sub(1) as _,
+ ),
+ w as _,
+ h as _,
+ BORDER,
+ );
}
};
ed.requests.hovering.result.as_ref().filter(|_| pass).map(|x| {
diff --git a/src/text.rs b/src/text.rs
index 912feae..a38ddb2 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -727,10 +727,12 @@ impl TextArea {
self.set_ho();
}
}
-
- #[lower::apply(saturating)]
pub fn scroll_to_cursor(&mut self) {
- let (_, y) = self.primary_cursor();
+ self.scroll_to(*self.cursor.first());
+ }
+ #[lower::apply(saturating)]
+ pub fn scroll_to(&mut self, c: usize) {
+ let y = self.y(c).unwrap();
if !(self.vo..self.vo + self.r).contains(&y) {
if self.vo > y {