A simple CPU rendered GUI IDE experience.
| -rw-r--r-- | src/edi.rs | 26 | ||||
| -rw-r--r-- | src/edi/input_handlers/cursor.rs | 122 | ||||
| -rw-r--r-- | src/edi/input_handlers/keyboard.rs | 12 | ||||
| -rw-r--r-- | src/edi/lsp_impl.rs | 19 | ||||
| -rw-r--r-- | src/edi/st.rs | 10 | ||||
| -rw-r--r-- | src/hov.rs | 161 | ||||
| -rw-r--r-- | src/lsp/client.rs | 8 | ||||
| -rw-r--r-- | src/main.rs | 6 | ||||
| -rw-r--r-- | src/rnd.rs | 483 | ||||
| -rw-r--r-- | src/rnd/cell_buffer.rs | 2 | ||||
| -rw-r--r-- | src/runnables.rs | 18 |
11 files changed, 573 insertions, 294 deletions
@@ -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, @@ -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 => {} @@ -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) }); |