A simple CPU rendered GUI IDE experience.
-rw-r--r--src/edi.rs45
-rw-r--r--src/edi/input_handlers/cursor.rs36
-rw-r--r--src/edi/lsp_impl.rs4
-rw-r--r--src/hov.rs1
-rw-r--r--src/lsp.rs1
-rw-r--r--src/lsp/communication.rs11
-rw-r--r--src/lsp/rq.rs6
-rw-r--r--src/main.rs48
-rw-r--r--src/rnd.rs83
9 files changed, 134 insertions, 101 deletions
diff --git a/src/edi.rs b/src/edi.rs
index dedc780..c938f28 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -31,7 +31,7 @@ use crate::bar::Bar;
use crate::commands::Cmds;
use crate::error::WDebug;
use crate::gotolist::{At, GoTo};
-use crate::hov::{self, Hovr, Hovring, Rendered};
+use crate::hov::{self, HOV_HEIGHT, Hovr, Hovring, Rendered};
use crate::lsp::{
Anonymize, Client, Map_, PathURI, RequestError, Rq, tdpp, vsc_settings,
};
@@ -390,17 +390,38 @@ impl Editor {
}
pub fn scroll(&mut self, rows: f32) {
let rows = if alt() { rows * 8. } else { rows * 3. };
- let (vo, max) = lower::saturating::math! { if let State::Hovering(Rq {result: Some(Hovring {
- rndr: Some(Rendered {scroll, .. }),..
- }), ..}) = &mut self.state && shift() {
- // let n = x.item.l();
- // (&mut x.item.vo, n - 15)
- todo!()
- } else if let Some((_, ref mut vo, Some(max))) = self.requests.sig_help.result && shift(){
- (vo, max - 15)
- } else {
- let n =self. text.l() - 1; (&mut self.text.vo, n)
- }};
+ if let State::Hovering(Rq {
+ result:
+ Some(Hovring {
+ rndr: Some(Rendered { scroll: vo, image, .. }),
+ ..
+ }),
+ ..
+ }) = &mut self.state
+ && shift()
+ {
+ let max = image.height().saturating_sub(HOV_HEIGHT as _);
+ let rows = rows * 21.;
+ if rows < 0.0 {
+ let rows = rows.ceil().abs() as u32;
+ *vo = (*vo + rows).min(max);
+ } else {
+ let rows = rows.floor() as u32;
+ *vo = vo.saturating_sub(rows);
+ }
+ return;
+ };
+ let (vo, max) = lower::saturating::math! {
+ if let Some((_, ref mut vo, Some(max))) =
+ self.requests.sig_help.result
+ && shift()
+ {
+ (vo, max - 15)
+ } else {
+ let n = self.text.l() - 1;
+ (&mut self.text.vo, n)
+ }
+ };
if rows < 0.0 {
let rows = rows.ceil().abs() as usize;
*vo = (*vo + rows).min(max);
diff --git a/src/edi/input_handlers/cursor.rs b/src/edi/input_handlers/cursor.rs
index 05b6f95..f61fdfc 100644
--- a/src/edi/input_handlers/cursor.rs
+++ b/src/edi/input_handlers/cursor.rs
@@ -16,6 +16,7 @@ enum Set<T> {
}
use crate::edi::*;
use crate::hov::{DiagnosticHovr, Hoverable, Hovring};
+use crate::lsp::BehaviourAfter;
use crate::rnd::CellBuffer;
impl Editor {
#[implicit_fn]
@@ -118,7 +119,7 @@ impl Editor {
pub fn find_diags(
&mut self,
cursor_position: (usize, usize),
- w: Arc<dyn Window>,
+ w: &Arc<dyn Window>,
) -> Option<Vec<Hoverable>> {
lsp!(let lsp, p = self else None);
@@ -160,7 +161,7 @@ impl Editor {
]
};
// println!("{x:?}");
- DiagnosticHovr::new(span, x, &w, r)
+ DiagnosticHovr::new(span, x, w, r)
})
.map(Hoverable::Diagnostic)
.collect::<Vec<_>>()
@@ -261,20 +262,25 @@ impl Editor {
// return;
// }
// if !running.insert(hover) {return}
- let (rx, _) = lsp
- .request::<HoverRequest>(&HoverParams {
- text_document_position_params: tdpp.clone(),
- work_done_progress_params: default(),
- })
- .unwrap();
+ // let (rx, _) =;
// println!("rq hov of {hover:?} (cur {})", requests.hovering.request.is_some());
let tdp = tdpp.clone();
+ let window = w.clone();
let handle: tokio::task::JoinHandle<Result<Option<Hovr>, _>> =
lsp.runtime.spawn(async move {
- let Some(x) = rx.await? else {
+ let Some(x) = lsp
+ .request_::<HoverRequest, { BehaviourAfter::Nil }>(
+ &HoverParams {
+ text_document_position_params: tdp.clone(),
+ work_done_progress_params: default(),
+ },
+ )?
+ .0
+ .await?
+ else {
return Ok(None::<Hovr>);
};
- let (w, cells) = spawn_blocking(move || {
+ let (width, cells) = spawn_blocking(move || {
let x = match &x.contents {
lsp_types::HoverContents::Scalar(
marked_string,
@@ -327,22 +333,20 @@ impl Editor {
]
})
});
+ let cells = cells.into();
+ window.request_redraw();
Ok(Some(
hov::Hovr {
span,
tdpp: tdp,
- item: CellBuffer {
- c: w,
- vo: 0,
- cells: cells.into(),
- },
+ item: CellBuffer { c: width, vo: 0, cells: cells },
range: x.range,
// range: x.range.and_then(|x| text.l_range(x)),
}
.into(),
))
});
- let diags = self.find_diags(cursor_position, w);
+ let diags = self.find_diags(cursor_position, &w);
self.state
.consume(Action::SetHovering(
diags.map(|of| Hovring { of, ..default() }),
diff --git a/src/edi/lsp_impl.rs b/src/edi/lsp_impl.rs
index 068667d..d0e506e 100644
--- a/src/edi/lsp_impl.rs
+++ b/src/edi/lsp_impl.rs
@@ -164,7 +164,9 @@ impl crate::edi::Editor {
..default()
},
})
- }) && x.result.is_none()
+ }) && super::lsp!(self).unwrap().redraw_now().unwrap() // im not a fan of this, but its kinda. necessary. annoyingly.
+ == ()
+ && x.result.is_none()
{
self.state = State::Default;
}
diff --git a/src/hov.rs b/src/hov.rs
index f59da13..8b006c1 100644
--- a/src/hov.rs
+++ b/src/hov.rs
@@ -479,3 +479,4 @@ pub struct Rendered {
impl Hovring {
pub fn rndr() {}
}
+pub const HOV_HEIGHT: usize = 500;
diff --git a/src/lsp.rs b/src/lsp.rs
index 4bee141..d3cab0b 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -84,6 +84,7 @@ pub fn run(
}
#[derive(Copy, Clone, PartialEq, Eq, std::marker::ConstParamTy, Debug)]
pub enum BehaviourAfter {
+ RedrawNow,
Redraw,
// Poll, ? how impl.
Nil,
diff --git a/src/lsp/communication.rs b/src/lsp/communication.rs
index 8899f0f..0013ad1 100644
--- a/src/lsp/communication.rs
+++ b/src/lsp/communication.rs
@@ -35,6 +35,7 @@ pub fn handler(
loop {
crossbeam::select! {
recv(req_rx) -> x => match x {
+ Ok((.., BehaviourAfter::RedrawNow)) => w.request_redraw(),
Ok((x, y, and)) => {
debug!("received request {x}");
assert!(map.insert(x, (y, Instant::now(), and)).is_none());
@@ -162,7 +163,7 @@ impl super::Client {
self.request_::<X, { Redraw }>(y)
}
#[must_use]
- pub(super) fn request_<'me, X: Request, const THEN: BehaviourAfter>(
+ pub fn request_<'me, X: Request, const THEN: BehaviourAfter>(
&'me self,
y: &X::Params,
) -> Result<
@@ -224,4 +225,12 @@ impl super::Client {
id,
))
}
+
+ pub fn redraw_now<'me>(
+ &'me self,
+ ) -> Result<(), SendError<(i32, oneshot::Sender<Re>, BehaviourAfter)>>
+ {
+ let (tx, _) = oneshot::channel();
+ self.send_to.send((0, tx, BehaviourAfter::RedrawNow))
+ }
}
diff --git a/src/lsp/rq.rs b/src/lsp/rq.rs
index b9b2c7b..0a145d6 100644
--- a/src/lsp/rq.rs
+++ b/src/lsp/rq.rs
@@ -125,7 +125,7 @@ impl<T, R, D, E> Rq<T, R, D, E> {
self.request = Some((AbortOnDropHandle::new(f), d));
}
}
-impl<T, R, D, E> Rq<T, R, D, E> {
+impl<T, R, D, E: std::fmt::Debug> Rq<T, R, D, E> {
pub fn running(&self) -> bool {
matches!(
self,
@@ -143,7 +143,9 @@ impl<T, R, D, E> Rq<T, R, D, E> {
let (_, d) = self.request.take().unwrap();
self.result = f(
match x {
- Ok(x) => x,
+ Ok(x) => x.inspect_err(|x| {
+ dbg!(&x);
+ }),
Err(e) => {
log::error!(
"unexpected join error from request poll: {e}"
diff --git a/src/main.rs b/src/main.rs
index b80cea4..e199e2e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
#![feature(
+ exact_div,
yeet_expr,
const_array,
const_closures,
@@ -16,7 +17,7 @@
try_blocks_heterogeneous,
current_thread_id,
vec_try_remove,
- lazy_type_alias,
+ // lazy_type_alias,
thread_local,
iter_intersperse,
stmt_expr_attributes,
@@ -112,7 +113,6 @@ extern "C" fn sigint(_: i32) {
std::process::exit(12);
}
-#[implicit_fn::implicit_fn]
pub(crate) fn entry(event_loop: EventLoop) {
unsafe {
__ED.write(match Editor::new() {
@@ -139,7 +139,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
let mut cursor_position = (0, 0);
let mut i = Image::build(1, 1).fill(BG);
- let mut cells = vec![];
+ let mut cells = vec![];
let mut w = match &mut ed.lsp {
Some((.., c)) => c.take(),
None => None,
@@ -255,6 +255,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
window.request_redraw();
}
WindowEvent::RedrawRequested if window_id == window.id() => {
+ println!("running redraw");
rnd::render(
ed,
&mut cells,
@@ -285,13 +286,10 @@ pub(crate) fn entry(event_loop: EventLoop) {
);
ed.cursor_moved(cursor_position, window.clone(), c);
}
-
- WindowEvent::PointerButton {
- state: bt,
- button: ButtonSource::Mouse(button),
- ..
-
-
+ WindowEvent::PointerButton {
+ state: bt,
+ button: ButtonSource::Mouse(button),
+ ..
} if bt.is_pressed() => {
if button == MouseButton::Left {
unsafe { CLICKING = true };
@@ -299,19 +297,15 @@ pub(crate) fn entry(event_loop: EventLoop) {
ed.click(button, cursor_position, window.clone());
window.request_redraw();
}
-
- WindowEvent::PointerButton {
- button: ButtonSource::Mouse(MouseButton::Left),
- ..
- }
-
- => unsafe { CLICKING = false },
-
- WindowEvent::MouseWheel {
- device_id: _,
- delta: MouseScrollDelta::LineDelta(_, rows),
- phase: _,
- } => {
+ WindowEvent::PointerButton {
+ button: ButtonSource::Mouse(MouseButton::Left),
+ ..
+ } => unsafe { CLICKING = false },
+ WindowEvent::MouseWheel {
+ device_id: _,
+ delta: MouseScrollDelta::LineDelta(_, rows),
+ phase: _,
+ } => {
ed.scroll(rows);
window.request_redraw();
}
@@ -320,10 +314,10 @@ pub(crate) fn entry(event_loop: EventLoop) {
window.request_redraw();
}
WindowEvent::KeyboardInput {
- event,
- is_synthetic: false,
- ..
- } if event.state == ElementState::Pressed => {
+ event,
+ is_synthetic: false,
+ ..
+ } if event.state == ElementState::Pressed => {
// if event.logical_key == Key::Named(NamedKey::F12) {
// lsp.unwrap().runtime.spawn(async move {
// lsp.unwrap().symbols().await;
diff --git a/src/rnd.rs b/src/rnd.rs
index b966b5a..bf20af4 100644
--- a/src/rnd.rs
+++ b/src/rnd.rs
@@ -19,7 +19,9 @@ use winit::window::{ImeRequestData, Window};
use crate::edi::st::State;
use crate::edi::{Editor, lsp};
use crate::gotolist::{At, GoTo};
-use crate::hov::{DiagnosticHovr, Hoverable, Hovr, Hovring, Rendered};
+use crate::hov::{
+ DiagnosticHovr, HOV_HEIGHT, Hoverable, Hovr, Hovring, Rendered,
+};
use crate::lsp::Rq;
use crate::sym::UsedSI;
use crate::text::{CoerceOption, RopeExt, TextArea, col, color_};
@@ -452,51 +454,48 @@ pub fn render(
// i: Image<&mut [u8], 3>,
// c: &[Cell],
// columns: usize,
- ls_: f32,
ox: f32,
oy: f32,
toy: f32,
add1_below: bool| {
let met = super::FONT.metrics(&[]);
let fac = ppem / met.units_per_em as f32;
- let position = (
+ let (px, py) = (
(((_x) as f32 * fw).round() + ox) as usize,
(((_y) as f32 * (fh + ls * fac)).round() + oy) as usize,
);
- let ls = ls_;
// let mut r = c.len() / columns;
// assert_eq!(c.len() % columns, 0);
// std::fs::write("cells", Cell::store(c));
if w >= size.width as usize
- || (position
- .1
- .checked_add(h)
- .is_none_or(|x| x >= size.height as usize)
- && !position.1.checked_sub(h).is_some())
- || position.1 >= size.height as usize
- || position.0 >= size.width as usize
+ // if y + height > height, cant fit it anywhere
+ || ((py.checked_add(h)
+ .is_none_or(|x| x >= size.height as usize))
+ && !py.checked_sub(h).is_some())
+ || py >= size.height as usize
+ || px >= size.width as usize
{
- return Err(());
+ return Err(((px, py), size, (w, h)));
}
assert!(
w < window.surface_size().width as _
&& h < window.surface_size().height as _
);
- let is_above = position.1.checked_sub(h).is_some();
- let top = position.1.checked_sub(h).unwrap_or(
+ let is_above = py.checked_sub(h).is_some();
+ let top = py.checked_sub(h).unwrap_or(
((((_y + add1_below as usize) as f32) * (fh + ls * fac))
.round()
+ toy) as usize,
);
- let left = if position.0 + w as usize
+ let left = if px + w as usize
> window.surface_size().width as usize
{
window.surface_size().width as usize - w as usize
} else {
- position.0
+ px
};
// let (w, h) =
@@ -525,19 +524,12 @@ pub fn render(
let ppem = ppem_;
let ls = ls_;
- assert_eq!(c.len() % columns, 0);
+ let r = c.len().div_exact(columns).unwrap();
let (w, h) =
dsb::size(&fonts.regular, ppem, ls, (columns, r));
- let (is_above, left, top) = position(
- (_x, _y),
- (w, h),
- ls_,
- ox,
- oy,
- toy,
- add1_below,
- )?;
+ let (is_above, left, top) =
+ position((_x, _y), (w, h), ox, oy, toy, add1_below)?;
// std::fs::write("cells", Cell::store(c));
// if w >= size.width as usize
@@ -607,7 +599,9 @@ pub fn render(
(left as _, top as _),
)
};
- Ok::<_, ()>((is_above, left, top, w, h))
+ Ok::<_, ((usize, usize), PhysicalSize<u32>, (usize, usize))>(
+ (is_above, left, top, w, h),
+ )
};
// dbg!(&ed.requests.document_symbols);
@@ -732,9 +726,10 @@ pub fn render(
// && pass
{
let hof = hash(&of);
- let buffer = match rndr {
- Some(Rendered { hash, image, .. }) if *hash == hof =>
- image,
+ let rh = th.min(HOV_HEIGHT);
+ let (buffer, scr) = match rndr {
+ Some(Rendered { hash, image, scroll }) if *hash == hof =>
+ (image, *scroll),
_ => {
let mut buffer =
Image::<_, 3>::build(tw as _, th as _).alloc();
@@ -786,7 +781,8 @@ pub fn render(
hash: hof,
scroll: 0,
});
- &mut rndr.as_mut().unwrap().image
+ let r = rndr.as_mut().unwrap();
+ (&mut r.image, r.scroll)
}
};
@@ -806,21 +802,23 @@ pub fn render(
&& let Some(_x) = _x.checked_sub(text.ho)
&& (cursor_position.1 == _y
&& (_x..=_x2).contains(&cursor_position.0))
- && let Ok((_, x, y)) = position(
- (_x, _y),
- (tw, th),
- -200.0,
- 0.0,
- 0.0,
- 0.0,
- true,
- )
+ && let Ok((_, x, y)) =
+ position((_x, _y), (tw, rh), 0.0, 0.0, 0.0, true)
{
- unsafe { i.overlay_at(&buffer.as_ref(), x as _, y as _) };
+ let top = scr * tw as u32 * 3;
+ let o = &buffer.bytes()[top as usize
+ ..(top + (rh as u32 * tw as u32 * 3)) as usize];
+ unsafe {
+ i.overlay_at(
+ &Image::<_, 3>::build(tw as _, rh as _).buf(o),
+ x as _,
+ y as _,
+ )
+ };
i.r#box(
(x.saturating_sub(1) as _, y.saturating_sub(1) as _),
tw as _,
- th as _,
+ rh as _,
BORDER,
);
}
@@ -1055,6 +1053,7 @@ pub fn render(
true,
fonts,
) else {
+ println!("RAHHH");
break 'out;
};
i.r#box(