A simple CPU rendered GUI IDE experience.
-rw-r--r--src/edi.rs26
-rw-r--r--src/edi/input_handlers/cursor.rs122
-rw-r--r--src/edi/input_handlers/keyboard.rs12
-rw-r--r--src/edi/lsp_impl.rs19
-rw-r--r--src/edi/st.rs10
-rw-r--r--src/hov.rs161
-rw-r--r--src/lsp/client.rs8
-rw-r--r--src/main.rs6
-rw-r--r--src/rnd.rs483
-rw-r--r--src/rnd/cell_buffer.rs2
-rw-r--r--src/runnables.rs18
11 files changed, 573 insertions, 294 deletions
diff --git a/src/edi.rs b/src/edi.rs
index 54f6827..dedc780 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -7,6 +7,7 @@ use std::time::SystemTime;
use Default::default;
use ftools::Bind;
+use helix_core::snippets::RenderedSnippet;
use lsp_server::Connection;
use lsp_types::*;
use regex::Regex;
@@ -30,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};
+use crate::hov::{self, Hovr, Hovring, Rendered};
use crate::lsp::{
Anonymize, Client, Map_, PathURI, RequestError, Rq, tdpp, vsc_settings,
};
@@ -95,11 +96,11 @@ macro_rules! lsp {
($self:ident + p) => {
$crate::edi::lsp!($self).zip($self.origin.as_deref())
};
- (let $lsp:ident, $path:ident = $self:ident) => {
+ (let $lsp:ident, $path:ident = $self:ident $(else $else:expr)?) => {
let Some(($lsp, $path)) =
$crate::edi::lsp!($self).zip($self.origin.as_deref())
else {
- return;
+ return $($else)?;
};
};
}
@@ -389,14 +390,17 @@ 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(x), ..}) = &mut self.state && shift() {
- let n = x.item.l();
- (&mut x.item.vo, n - 15)
- } 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)
- }};
+ 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 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 e0fc1b5..05b6f95 100644
--- a/src/edi/input_handlers/cursor.rs
+++ b/src/edi/input_handlers/cursor.rs
@@ -1,5 +1,4 @@
use std::borrow::Cow;
-use std::ops::ControlFlow;
use std::sync::Arc;
use Default::default;
@@ -16,6 +15,7 @@ enum Set<T> {
Ignore,
}
use crate::edi::*;
+use crate::hov::{DiagnosticHovr, Hoverable, Hovring};
use crate::rnd::CellBuffer;
impl Editor {
#[implicit_fn]
@@ -62,28 +62,46 @@ impl Editor {
};
let l2 = &mut l.result;
- if let Some(Hovr {
- span: Some([(_x, _y), (_x2, _)]),
- ..
- }) = &*l2
- && let Some(_y) = _y.checked_sub(self.text.vo)
- && let Some(_x) = _x.checked_sub(self.text.ho)
- && let Some(_x2) =
- _x2.checked_sub(self.text.ho)
- && cursor_position.1 == _y
- && (_x..=_x2).contains(
- &&(cursor_position.0
- - self.text.line_number_offset()
- - 1),
- )
- {
- break 'out;
- } else {
- // println!("span no longer below cursor; cancel hover {_x}..{_x2} {}", cursor_position.0 - text.line_number_offset() - 1);
- *l2 = None;
- w.request_redraw();
+ match l2 {
+ Some(hovrables) => {
+ for hoverable in &hovrables.of {
+ if let Hoverable::Lsp(Hovr {
+ span,
+ ..
+ })
+ | Hoverable::Diagnostic(
+ DiagnosticHovr { span, .. },
+ ) = &*hoverable
+ && let Some([(_x, _y), (_x2, _)]) =
+ span
+ && let Some(_y) =
+ _y.checked_sub(self.text.vo)
+ && let Some(_x) =
+ _x.checked_sub(self.text.ho)
+ && let Some(_x2) =
+ _x2.checked_sub(self.text.ho)
+ && cursor_position.1 == _y
+ && (_x..=_x2).contains(
+ &&(cursor_position.0
+ - self
+ .text
+ .line_number_offset()
+ - 1),
+ )
+ {
+ break 'out;
+ } else {
+ // println!("span no longer below cursor; cancel hover {_x}..{_x2} {}", cursor_position.0 - text.line_number_offset() - 1);
+ *l2 = None;
+ w.request_redraw();
+ break;
+ }
+ }
+ }
+ None => {}
}
- self.rq_hover(hover, cursor_position, c);
+
+ self.rq_hover(hover, cursor_position, c, w);
}
_ => {}
}
@@ -97,12 +115,64 @@ impl Editor {
x => unreachable!("{x:?}"),
}
}
+ pub fn find_diags(
+ &mut self,
+ cursor_position: (usize, usize),
+ w: Arc<dyn Window>,
+ ) -> Option<Vec<Hoverable>> {
+ lsp!(let lsp, p = self else None);
+
+ lsp.diagnostics
+ .get(
+ &Url::from_file_path(p).unwrap(),
+ &lsp.diagnostics.guard(),
+ )
+ .map(|diag| {
+ let text = &mut self.text;
+ let r = text.r;
+
+ 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 _))
+ })
+ })
+ .cloned()
+ .map(|x| {
+ let span = try {
+ let range = x.range;
+ let (startx, starty) =
+ text.l_pos_to_char(range.start)?;
+ let (endx, endy) =
+ text.l_pos_to_char(range.end)?;
+ let x1 = text
+ .reverse_source_map(starty)?
+ .nth(startx)?;
+ let x2 = text
+ .reverse_source_map(endy)?
+ .nth(endx)?;
+ [
+ (x1, range.start.line as _),
+ (x2, range.start.line as _),
+ ]
+ };
+ // println!("{x:?}");
+ DiagnosticHovr::new(span, x, &w, r)
+ })
+ .map(Hoverable::Diagnostic)
+ .collect::<Vec<_>>()
+ })
+ }
#[implicit_fn]
pub fn rq_hover(
&mut self,
hover: Mapping<'_>,
cursor_position: (usize, usize),
c: usize,
+ w: Arc<dyn Window>,
) {
let (lsp, o) = lsp!(self + p).unwrap();
let text = self.text.clone();
@@ -272,9 +342,13 @@ impl Editor {
.into(),
))
});
-
+ let diags = self.find_diags(cursor_position, w);
self.state
- .consume(Action::SetHovering(handle, (cursor_position, tdpp)))
+ .consume(Action::SetHovering(
+ diags.map(|of| Hovring { of, ..default() }),
+ handle,
+ (cursor_position, tdpp),
+ ))
.unwrap();
// self.requests.hovering.request =
// (DropH::new(handle), cursor_position).into();
diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs
index 9a22457..c789851 100644
--- a/src/edi/input_handlers/keyboard.rs
+++ b/src/edi/input_handlers/keyboard.rs
@@ -345,8 +345,11 @@ impl Editor {
Some(Do::Edit) => self.handle_edit(event),
Some(Do::Undo) => {
self.hist.test_push(&mut self.text);
- self.hist.undo(&mut self.text).unwrap();
+ if let Err(e) = self.hist.undo(&mut self.text) {
+ eprintln!("undo failed: {e}");
+ }
self.bar.last_action = "undid".to_string();
+
change!(self, window.clone());
}
Some(Do::Redo) => {
@@ -758,9 +761,10 @@ impl Editor {
x
.iter()
.flatten()
- .flat_map(|(a, b)| {
- [a, b].map(|c| self.text.rope.l_position(*c).unwrap())
- })
+ .map(|c| self.text.rope.l_position(*c).unwrap())
+ // .flat_map(|(a, b)| {
+ // [a, b].map(|c| self.text.rope.l_position(*c).unwrap())
+ // })
.sorted()
.rev()
{
diff --git a/src/edi/lsp_impl.rs b/src/edi/lsp_impl.rs
index d8f2898..068667d 100644
--- a/src/edi/lsp_impl.rs
+++ b/src/edi/lsp_impl.rs
@@ -1,5 +1,6 @@
use std::iter::repeat;
+use Default::default;
use lsp_server::Request as LRq;
use lsp_types::request::*;
use lsp_types::*;
@@ -8,7 +9,7 @@ use ttools::{Tupl, With};
use crate::complete::Complete;
use crate::edi::st::*;
-use crate::hov::Hovr;
+use crate::hov::{Hoverable, Hovring};
use crate::lsp::{RequestError, Rq};
use crate::runnables::Runnables;
use crate::sym::GoTo;
@@ -150,7 +151,21 @@ impl crate::edi::Editor {
});
}
State::Hovering(x) => {
- if x.poll(|x, _| x.ok().flatten()) && x.result.is_none() {
+ if x.poll(|x, (_, p)| {
+ Some(match p {
+ Some(mut p) if !p.of.is_empty() => {
+ p.of.extend(
+ x.ok().flatten().map(Hoverable::Lsp),
+ );
+ p
+ }
+ _ => Hovring {
+ of: vec![Hoverable::Lsp(x.ok()??)],
+ ..default()
+ },
+ })
+ }) && x.result.is_none()
+ {
self.state = State::Default;
}
}
diff --git a/src/edi/st.rs b/src/edi/st.rs
index 7eea337..ad3eec4 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -11,7 +11,7 @@ use winit::keyboard::{Key, NamedKey, SmolStr};
use crate::commands::Commands;
use crate::edi::handle2;
use crate::gotolist::GoToList;
-use crate::hov::Hovr;
+use crate::hov::{Hoverable, Hovr, Hovring};
use crate::lsp::{AQErr, RequestError, Rq, RqS};
use crate::menu::generic::{GenericMenu, MenuData};
use crate::sym::{Symbols, SymbolsList};
@@ -79,7 +79,7 @@ Default => {
M(_) => _,
},
Hovered => {
- HOnSomething(((usize, usize)) => pos) => Hovering(Rq<Hovr, Option<Hovr>, ((usize, usize), TextDocumentPositionParams), RequestError<HoverRequest>> => default()) [SetHovering],
+ HOnSomething(((usize, usize)) => pos) => Hovering(Rq<Hovring, Option<Hovr>, ((usize, usize), TextDocumentPositionParams), RequestError<HoverRequest>> => default()) [SetHovering],
HOnNothing => Default,
},
Hovering(x) => {
@@ -87,9 +87,9 @@ Hovering(x) => {
HOnSomething(pos if let Some((_, (c, _))) = x.request && (c != pos)) => _ [SetHovering],
HOnSomething(_) => _ [SetHovering],
HOnNothing => Default,
- SetHovering((tokio::task::JoinHandle<
+ SetHovering((Option<Hovring>, tokio::task::JoinHandle<
Result<Option<Hovr>, RequestError<HoverRequest>>,
- >, ((usize, usize), TextDocumentPositionParams)) => (h, d)) => Hovering({ let mut x = x; x.request_d(h, d); x }),
+ >, ((usize, usize), TextDocumentPositionParams)) => (v, h, d)) => Hovering({ let mut x = x; x.result = v; x.request_d(h, d); x }),
C(_) => _ [Hover],
MovedOut => Default,
@@ -131,7 +131,7 @@ Hovering(x) => {
// duplicate zone
- M(MouseButton::Left if ctrl()) => Default [GoToDefinition(x.request.map(|x| x.1.1).or(x.result.map(|x| x.tdpp)))],
+ 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],
},
Command(_) => K(Key::Named(Escape)) => Default,
diff --git a/src/hov.rs b/src/hov.rs
index 5f27a52..f59da13 100644
--- a/src/hov.rs
+++ b/src/hov.rs
@@ -1,19 +1,26 @@
+use std::fmt::Debug;
use std::iter::{empty, once, repeat_n};
+use std::os::fd::AsFd;
use std::pin::pin;
use std::str::FromStr;
+use std::sync::Arc;
use std::vec::Vec;
use Default::default;
use dsb::Cell;
use dsb::cell::Style;
+use implicit_fn::implicit_fn;
use itertools::Itertools;
-use lsp_types::{TextDocumentIdentifier, TextDocumentPositionParams};
+use lsp_types::{
+ Diagnostic, TextDocumentIdentifier, TextDocumentPositionParams,
+};
use markdown::mdast::{self, Node};
use ropey::Rope;
use serde_derive::{Deserialize, Serialize};
use url::Url;
const D: Cell = Cell { letter: None, style: Style::new(FG, BG) };
-use crate::{FG, text};
+use crate::rnd::{CellBuffer, simplify_path};
+use crate::{FG, FONT, text};
struct Builder {
c: usize,
@@ -306,7 +313,7 @@ fn t() {
println!("{:?}", now.elapsed());
x.as_ref().save("x");
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Hash)]
pub struct Hovr {
pub(crate) span: Option<[(VisualX, usize); 2]>,
pub(crate) item: crate::rnd::CellBuffer,
@@ -323,4 +330,152 @@ fn tdp() -> TextDocumentPositionParams {
position: default(),
}
}
+
+#[derive(Serialize, Deserialize, Hash)]
+pub struct DiagnosticHovr {
+ pub(crate) span: Option<[(VisualX, usize); 2]>,
+ pub(crate) t: CellBuffer,
+ pub diag: Diagnostic,
+}
+impl DiagnosticHovr {
+ #[implicit_fn]
+ pub fn new(
+ span: Option<[(VisualX, usize); 2]>,
+ diag: Diagnostic,
+ window: &Arc<dyn winit::window::Window>,
+ r: usize,
+ ) -> Self {
+ let fw_15 = {
+ let ppem = 15.0;
+ let (fw, _) = dsb::dims(&FONT, ppem);
+ fw
+ };
+ let dawg = once(&diag)
+ .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(
+ (
+ ((window.surface_size().width as f32 / fw_15) as u16 - 5),
+ r as u16 - 5,
+ ),
+ false,
+ );
+ for b in
+ simplify_path(&dawg.replace('\n', "\r\n").replace("⸬", ":"))
+ .bytes()
+ {
+ t.rx(b, std::fs::File::open("/dev/null").unwrap().as_fd());
+ }
+ let y_lim = t
+ .cells
+ .rows()
+ .rev()
+ .position(|x| !x.iter().all(_.letter.is_none()))
+ .map(|x| t.cells.r() as usize - x)
+ .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 {
+ panic!()
+ };
+ let n = t
+ .cells
+ .rows()
+ .take(y_lim)
+ .flat_map(|x| &x[..x_lim])
+ .copied()
+ .collect();
+
+ Self { t: CellBuffer { c: x_lim, vo: 0, cells: n }, diag, span }
+
+ // 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,
+ // 15.0,
+ // -200.,
+ // 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,
+ // );
+ // }
+ // };
+ }
+}
+impl std::fmt::Debug for DiagnosticHovr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("DiagnosticHovr")
+ .field("span", &self.span)
+ .field("diag", &self.diag)
+ .finish()
+ }
+}
+
pub type VisualX = usize;
+#[derive(Debug, Serialize, Deserialize, Hash)]
+pub enum Hoverable {
+ Lsp(Hovr),
+ Diagnostic(DiagnosticHovr),
+}
+impl Hoverable {
+ pub fn tdpp(&self) -> Option<TextDocumentPositionParams> {
+ match self {
+ Hoverable::Lsp(hovr) => Some(hovr.tdpp.clone()),
+ Hoverable::Diagnostic(_) => None,
+ }
+ }
+}
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct Hovring {
+ pub of: Vec<Hoverable>,
+
+ #[serde(skip)]
+ pub rndr: Option<Rendered>,
+}
+impl Debug for Rendered {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Rendered")
+ .field("hash", &self.hash)
+ .field("scroll", &self.scroll)
+ .finish()
+ }
+}
+pub struct Rendered {
+ pub image: fimg::Image<Box<[u8]>, 3>,
+ pub hash: u64,
+ pub scroll: u32, // in pixels
+}
+impl Hovring {
+ pub fn rndr() {}
+}
diff --git a/src/lsp/client.rs b/src/lsp/client.rs
index 4b7b85f..86890ed 100644
--- a/src/lsp/client.rs
+++ b/src/lsp/client.rs
@@ -18,7 +18,6 @@ use rootcause::option_ext::OptionExt;
use rust_analyzer::lsp::ext::*;
use tokio::sync::oneshot;
use ttools::*;
-use winit::platform::x11::ffi::BadImplementation;
use crate::lsp::BehaviourAfter::{self, *};
use crate::lsp::init_opts::ra_config;
@@ -355,10 +354,7 @@ impl Client {
&self,
f: &Path,
x: Vec<Position>,
- ) -> Result<
- Vec<Option<(Position, Position)>>,
- RequestError<MatchingBrace>,
- > {
+ ) -> Result<Vec<Option<Position>>, RequestError<MatchingBrace>> {
self.request_immediate::<MatchingBrace>(&MatchingBraceParams {
text_document: f.tid(),
positions: x,
@@ -375,7 +371,7 @@ impl Client {
{
for (c, p) in t.cursor.inner.iter_mut().zip(x) {
if let Some(p) = p {
- c.position = t.rope.l_position(p.1).unwrap();
+ c.position = t.rope.l_position(p).unwrap();
}
}
}
diff --git a/src/main.rs b/src/main.rs
index c7fa248..b80cea4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -32,7 +32,7 @@
const_trait_impl,
try_blocks
)]
-#![allow(incomplete_features, irrefutable_let_patterns, static_mut_refs)]
+#![allow(incomplete_features, irrefutable_let_patterns, static_mut_refs, unexpected_cfgs)]
mod act;
mod edi;
mod error;
@@ -215,8 +215,8 @@ pub(crate) fn entry(event_loop: EventLoop) {
// let before = ed.state.name();
ed.poll();
// println!("{before} -> poll -> {}", ed.state.name());
- let before = ed.state.name();
- let ev = format!("{event:?}");
+ // let before = ed.state.name();
+ // let ev = format!("{event:?}");
// use WindowEvent as Event;
match event {
// Event::AboutToWait => {}
diff --git a/src/rnd.rs b/src/rnd.rs
index 0484de7..cbde329 100644
--- a/src/rnd.rs
+++ b/src/rnd.rs
@@ -1,12 +1,11 @@
use std::iter::{chain, once, repeat_n};
-use std::os::fd::AsFd;
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 dsb::{Cell, Fonts};
use fimg::pixels::Blend;
use fimg::{Image, OverlayAt};
use lsp_types::*;
@@ -20,13 +19,13 @@ use winit::window::{ImeRequestData, Window};
use crate::edi::st::State;
use crate::edi::{Editor, lsp};
use crate::gotolist::{At, GoTo};
-use crate::hov::Hovr;
+use crate::hov::{DiagnosticHovr, Hoverable, Hovr, Hovring, Rendered};
use crate::lsp::Rq;
use crate::sym::UsedSI;
use crate::text::{CoerceOption, RopeExt, col, color_};
use crate::{
BG, BORDER, CompletionAction, CompletionState, FG, FONT, complete,
- filter, lsp, sig,
+ filter, hash, lsp, sig,
};
mod cell_buffer;
@@ -182,13 +181,22 @@ pub fn render(
x.style.fg = col!("#FFD173");
});
} }
- if let State::Hovering(Rq{ result: Some(crate::hov::Hovr{ range:Some(r),..} ), ..}) = &ed.state {
- x.get_range(text.map_to_visual((r.start.character as _, r.start.line as _)),
+
+ if let State::Hovering(Rq{ result: Some(crate::hov::Hovring{ of, ..}),..}) = &ed.state {
+ for thing in of {
+ // if let Some(Hoverable::Diagnostic(DiagnosticHovr{ span, .. })) = thing {
+
+ // }
+ if let Hoverable::Lsp(Hovr { range:Some(r),.. })=thing {
+ x.get_range(text.map_to_visual((r.start.character as _, r.start.line as _)),
text.map_to_visual((r.end.character as usize, r.end.line as _)))
.for_each(|x| {
x.style.secondary_color = col!("#73d0ff");
x.style.flags |= Style::UNDERCURL;
});
+ }
+
+ }
// x.range;
}
if let Some((lsp, p)) = lsp!(ed + p) && let uri = Url::from_file_path(p).unwrap() && let Some(diag) = lsp.diagnostics.get(&uri, &lsp.diagnostics.guard()) {
@@ -361,12 +369,64 @@ pub fn render(
}
}
}
- let fw_15 = {
- let ppem = 15.0;
- let (fw, _) = dsb::dims(&fonts.regular, ppem);
- fw
+
+ let position = |(_x, _y): (usize, usize),
+ (w, h): (usize, usize),
+ // 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 = (
+ (((_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
+ {
+ return Err(());
+ }
+ 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(
+ ((((_y + add1_below as usize) as f32) * (fh + ls * fac))
+ .round()
+ + toy) as usize,
+ );
+
+ let left = if position.0 + w as usize
+ > window.surface_size().width as usize
+ {
+ window.surface_size().width as usize - w as usize
+ } else {
+ position.0
+ };
+
+ // let (w, h) =
+ // dsb::size(&fonts.regular, ppem, ls, (columns, r));
+ Ok((is_above, left, top))
};
- let mut place_around =
+ let place_around =
|(_x, _y): (usize, usize),
i: Image<&mut [u8], 3>,
c: &[Cell],
@@ -376,75 +436,85 @@ pub fn render(
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 = (
- (((_x) as f32 * fw).round() + ox) as usize,
- (((_y) as f32 * (fh + ls * fac)).round() + oy)
- as usize,
- );
+ add1_below: bool,
+ fonts: &mut Fonts<'_, '_, '_, '_>| {
+ // let met = super::FONT.metrics(&[]);
+ // let fac = ppem / met.units_per_em as f32;
+ // let position = (
+ // (((_x) as f32 * fw).round() + ox) as usize,
+ // (((_y) as f32 * (fh + ls * fac)).round() + oy)
+ // as usize,
+ // );
let ppem = ppem_;
let ls = ls_;
- let mut r = c.len() / columns;
assert_eq!(c.len() % columns, 0);
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,
+ )?;
// 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
- {
- unsafe {
- dsb::render_owned(
- c,
- (columns, c.len() / columns),
- ppem,
- fonts,
- ls,
- true,
- )
- .save("fail.png")
- };
- return Err(());
- }
+ // 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
+ // {
+ // unsafe {
+ // dsb::render_owned(
+ // c,
+ // (columns, c.len() / columns),
+ // ppem,
+ // fonts,
+ // ls,
+ // true,
+ // )
+ // .save("fail.png")
+ // };
+ // return Err(());
+ // }
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(
- ((((_y + add1_below as usize) as f32)
- * (fh + ls * fac))
- .round()
- + toy) as usize,
- );
- let (_, y) = dsb::fit(
- &fonts.regular,
- ppem,
- ls,
- (
- window.surface_size().width as _, /* - left */
- ((window.surface_size().height as usize)
- .saturating_sub(top)),
- ),
- ); /* suspicious saturation */
- r = r.min(y);
+ // let is_above = position.1.checked_sub(h).is_some();
+ // let top = position.1.checked_sub(h).unwrap_or(
+ // ((((_y + add1_below as usize) as f32)
+ // * (fh + ls * fac))
+ // .round()
+ // + toy) as usize,
+ // );
+ // let (_, y) = dsb::fit(
+ // &fonts.regular,
+ // ppem,
+ // ls,
+ // (
+ // window.surface_size().width as _, /* - left */
+ // ((window.surface_size().height as usize)
+ // .saturating_sub(top)),
+ // ),
+ // ); /* suspicious saturation */
+ // r = r.min(y);
- let left = if position.0 + w as usize
- > window.surface_size().width as usize
- {
- window.surface_size().width as usize - w as usize
- } else {
- position.0
- };
+ // let left = if position.0 + w as usize
+ // > window.surface_size().width as usize
+ // {
+ // window.surface_size().width as usize - w as usize
+ // } else {
+ // position.0
+ // };
let (w, h) =
dsb::size(&fonts.regular, ppem, ls, (columns, r));
@@ -460,7 +530,7 @@ pub fn render(
(left as _, top as _),
)
};
- Ok((is_above, left, top, w, h))
+ Ok::<_, ()>((is_above, left, top, w, h))
};
// dbg!(&ed.requests.document_symbols);
@@ -545,6 +615,7 @@ pub fn render(
0.,
0.,
false,
+ fonts,
) {
i.filled_box(
(w as u32, 0),
@@ -553,173 +624,129 @@ pub fn render(
color_("#191d27"),
);
}
- // dbg !(x);
}
- let mut pass = true;
- if let Some((lsp, p)) = lsp!(ed + p)
- && let Some(diag) = lsp.diagnostics.get(
- &Url::from_file_path(p).unwrap(),
- &lsp.diagnostics.guard(),
- )
+ if let State::Hovering(
+ Rq { result: Some(Hovring { of, rndr }), .. },
+ ..,
+ ) = &mut ed.state
+ && let sized = of.iter().map(|hovr| {
+ (
+ match hovr {
+ Hoverable::Lsp(x) => dsb::size(
+ &fonts.regular,
+ ppem,
+ ls,
+ (x.item.c, x.item.l()),
+ ),
+ Hoverable::Diagnostic(x) => dsb::size(
+ &fonts.regular,
+ 15.0,
+ -200.,
+ (x.t.c, x.t.l().into()),
+ ),
+ },
+ hovr,
+ )
+ })
+ && let (tw, th) = sized
+ .clone()
+ .fold((0, 0), |(w_, h_), ((w, h), _)| (w_.max(w), h_ + h))
+ && th != 0
+ // && pass
{
- '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 hof = hash(&of);
+ let buffer = match rndr {
+ Some(Rendered { hash, image, .. }) if *hash == hof =>
+ image,
+ _ => {
+ let mut buffer =
+ Image::<_, 3>::build(tw as _, th as _).alloc();
+ let mut oy = 0;
+ for ((_, h), item) in sized.collect::<Vec<_>>() {
+ // println!("{item:?}");
+ let c = match item {
+ Hoverable::Diagnostic(x) => &x.t,
+ Hoverable::Lsp(x) => &x.item,
+ };
+ // TODO: reflow lsp documentation to fit wide diagnostics?
+ unsafe {
+ dsb::render(
+ &c.cells,
+ (c.c, c.l()),
+ match item {
+ Hoverable::Diagnostic(_) => 15.0,
+ _ => ppem,
+ },
+ fonts,
+ match item {
+ Hoverable::Diagnostic(_) => -200.,
+ _ => ls,
+ },
+ true,
+ buffer.as_mut(),
+ (0, oy),
+ );
+ // dsb::render_owned(
+ // &c.cells,
+ // (c.c, c.l()),
+ // match item {
+ // Hoverable::Diagnostic(_) => 15.0,
+ // _ => ppem,
+ // },
+ // fonts,
+ // match item {
+ // Hoverable::Diagnostic(_) => -200.,
+ // _ => ls,
+ // },
+ // true,
+ // ).save(format!("{oy}.png"));
- let Some(diag) = dawgs.clone().next() else { break 'out };
- let dawg = dawgs
- .filter_map(|x| {
- dbg!(&x.related_information);
- 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(
- (
- ((window.surface_size().width as f32 / fw_15)
- as u16
- - 5),
- r as u16 - 5,
- ),
- false,
- );
- for b in simplify_path(
- &dawg.replace('\n', "\r\n").replace("⸬", ":"),
- )
- .bytes()
- {
- t.rx(
- b,
- std::fs::File::open("/dev/null").unwrap().as_fd(),
- );
+ oy += h as u32;
+ }
+ }
+ *rndr = Some(Rendered {
+ image: buffer.boxed(),
+ hash: hof,
+ scroll: 0,
+ });
+ &mut rndr.as_mut().unwrap().image
}
- let y_lim = t
- .cells
- .rows()
- .rev()
- .position(|x| !x.iter().all(_.letter.is_none()))
- .map(|x| t.cells.r() as usize - x)
- .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,
- 15.0,
- -200.,
- 0.,
- 0.,
- 0.,
+ if let Some(
+ Hoverable::Diagnostic(DiagnosticHovr { span, .. })
+ | Hoverable::Lsp(Hovr { span, .. }),
+ ) = of.iter().next()
+ && let Some([(_x, _y), (_x2, _)]) = *span
+ && (_x..=_x2).contains(
+ &(cursor_position
+ .0
+ .wrapping_sub(text.line_number_offset() + 1)),
+ )
+ && let [_x, _x2] =
+ [_x, _x2].add(text.line_number_offset() + 1)
+ && let Some(_y) = _y.checked_sub(text.vo)
+ && 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,
- ) else {
- break 'out;
- };
- pass = false;
+ )
+ {
+ unsafe { i.overlay_at(&buffer.as_ref(), x as _, y as _) };
i.r#box(
- (
- left.saturating_sub(1) as _,
- top.saturating_sub(1) as _,
- ),
- w as _,
- h as _,
+ (x.saturating_sub(1) as _, y.saturating_sub(1) as _),
+ tw as _,
+ th as _,
BORDER,
);
}
- };
- if let State::Hovering(
- Rq {
- result:
- Some(
- x @ Hovr {
- span: Some([(_x, _y), (_x2, _)]), ..
- },
- ),
- ..
- },
- ..,
- ) = &ed.state
- && pass
- {
- // }
- // ed.requests.hovering.result.as_ref().filter(|_| pass).map(|x| {
- // x.span.clone().map(|[(_x, _y), (_x2, _)]| {
- // let [(_x, _y), (_x2, _)] = text.position(sp);
- // dbg!(x..=x2, cursor_position.0)
- // if !(_x..=_x2).contains(&&(cursor_position.0 .wrapping_sub( text.line_number_offset()+1))) {
- // return
- // }
-
- let [_x, _x2] = [*_x, *_x2].add(text.line_number_offset() + 1);
- let Some(_y) = _y.checked_sub(text.vo) else {
- return;
- };
- let Some(_x) = _x.checked_sub(text.ho) else {
- return;
- };
-
- // if !(cursor_position.1 == _y && (_x..=_x2).contains(&cursor_position.0)) {
- // return;
- // }
-
- let r = x.item.l().min(15);
- let c = x.item.displayable(r);
- let Ok((_, left, top, w, h)) = place_around(
- (_x, _y),
- i.copy(),
- c,
- x.item.c,
- 17.0,
- 10.0,
- 0.,
- 0.,
- 0.,
- true,
- ) else {
- return;
- };
- i.r#box(
- (left.saturating_sub(1) as _, top.saturating_sub(1) as _),
- w as _,
- h as _,
- BORDER,
- );
}
let mut drawb = |cells, c| {
// let ws = ed.workspace.as_deref().unwrap();
@@ -737,6 +764,7 @@ pub fn render(
0.,
0.,
true,
+ fonts,
) else {
println!("ra?");
return;
@@ -769,6 +797,7 @@ pub fn render(
0.,
0.,
true,
+ fonts,
) else {
println!("ra?");
break 'out;
@@ -843,6 +872,7 @@ pub fn render(
0.,
0.,
true,
+ fonts,
) else {
break 'out;
};
@@ -867,6 +897,7 @@ pub fn render(
-(h as f32),
if is_above { 0.0 } else { h as f32 },
true,
+ fonts,
) else {
return None;
};
@@ -914,6 +945,7 @@ pub fn render(
h as f32
},
true,
+ fonts,
) else {
return;
};
@@ -944,6 +976,7 @@ pub fn render(
0.,
0.,
true,
+ fonts,
) else {
break 'out;
};
diff --git a/src/rnd/cell_buffer.rs b/src/rnd/cell_buffer.rs
index 2ac7e62..90dff55 100644
--- a/src/rnd/cell_buffer.rs
+++ b/src/rnd/cell_buffer.rs
@@ -2,7 +2,7 @@ use std::ops::Deref;
use dsb::Cell;
-#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(serde::Serialize, serde::Deserialize, Hash)]
pub struct CellBuffer {
pub c: usize,
pub vo: usize,
diff --git a/src/runnables.rs b/src/runnables.rs
index 62261f9..ee3970d 100644
--- a/src/runnables.rs
+++ b/src/runnables.rs
@@ -7,7 +7,7 @@ use dsb::cell::Style;
use itertools::Itertools;
use kitty_rc::LaunchCommand;
use lsp_types::LocationLink;
-use rust_analyzer::lsp::ext::{Runnable, RunnableArgs, RunnableKind};
+use rust_analyzer::lsp::ext::{Runnable, RunnableArgs};
use crate::menu::generic::{GenericMenu, MenuData};
use crate::menu::{Key, charc};
@@ -41,16 +41,14 @@ impl MenuData for Runb {
let d: Cell = Cell { letter: None, style: ds };
let mut b = vec![d; columns];
const MAP: [([u8; 3], [u8; 3], &str); 70] = {
- (
- amap::amap! {
- const { RunnableKind::Cargo as usize } => ("#9a9b9a", "󱣘 "),
- const { RunnableKind::Shell as usize } => ("#FFAD66", "$ "),
- _ => ("#9a9b9a", " "),
- }).map(const
- |(x, y)| (set_a(color_(x), 0.5), color_(x), y),
- )
+ (amap::amap! {
+ 0 => ("#9a9b9a", "󱣘 "),
+ 1 => ("#FFAD66", "$ "),
+ _ => ("#9a9b9a", " "),
+ })
+ .map(const |(x, y)| (set_a(color_(x), 0.5), color_(x), y))
};
- let (bgt, col, ty) = MAP[x.kind.clone() as usize];
+ let (bgt, col, ty) = MAP[0];
b.iter_mut().zip(ty.chars()).for_each(|(x, c)| {
*x = (Style::new(col, bgt) | Style::BOLD).basic(c)
});