A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 172 |
1 files changed, 100 insertions, 72 deletions
diff --git a/src/main.rs b/src/main.rs index 13f4249..084ec66 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ #![allow(incomplete_features, redundant_semicolons)] use std::borrow::Cow; use std::iter::{Take, once}; +use std::mem::transmute; use std::num::NonZeroU32; use std::os::fd::AsFd; use std::path::{Path, PathBuf}; @@ -49,7 +50,6 @@ use dsb::cell::Style; use dsb::{Cell, F, Fonts}; use fimg::pixels::Blend; use fimg::{Image, OverlayAt}; -use itertools::Itertools as _; use lsp::{PathURI, Rq}; use lsp_server::{Connection, Request as LRq}; use lsp_types::request::{HoverRequest, SignatureHelpRequest}; @@ -72,7 +72,7 @@ use winit::window::Icon; use crate::bar::Bar; use crate::hov::Hovr; use crate::lsp::{RedrawAfter, RqS}; -use crate::text::{Diff, TextArea, col, color, is_word, set_a}; +use crate::text::{Diff, Mapping, TextArea, col, is_word}; mod bar; pub mod com; pub mod hov; @@ -168,6 +168,7 @@ static mut CLICKING: bool = false; const BG: [u8; 3] = [31, 36, 48]; const FG: [u8; 3] = [204, 202, 194]; +const BORDER: [u8; 3] = col!("#ffffff"); #[implicit_fn::implicit_fn] pub(crate) fn entry(event_loop: EventLoop<()>) { let ppem = 20.0; @@ -183,11 +184,8 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { F::FontRef(*IFONT, &[(2003265652, 550.0)]), F::instance(*IFONT, *BIFONT), ); - let mut cursor_position = (0, 0); - - let mut state = State::Default; let mut bar = Bar { last_action: String::default() }; let mut i = Image::build(1, 1).fill(BG); @@ -204,7 +202,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { } x.parent().and_then(rooter) } - + let workspace = origin .as_ref() .and_then(|x| rooter(&x.parent().unwrap())) @@ -253,14 +251,14 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { }; } let mut hovering = - Rq::<Hovr, Option<Hovr>, usize, anyhow::Error>::default(); + Rq::<Hovr, Option<Hovr>, (usize, usize), anyhow::Error>::default(); let mut complete = CompletionState::None; let mut sig_help = // vo, lines RqS::<(SignatureHelp, usize, Option<usize>), SignatureHelpRequest, ()>::default(); let mut semantic_tokens = default(); let mut diag = Rq::<String, Option<String>, (), anyhow::Error>::default(); - let mut inlay: Rq::<Vec<InlayHint>, Vec<InlayHint>> = default(); + let mut inlay: Rq<Vec<InlayHint>, Vec<InlayHint>> = default(); // let mut complete = None::<(CompletionResponse, (usize, usize))>; // let mut complete_ = None::<( // JoinHandle< @@ -376,7 +374,9 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { log::debug!("discarding request {rq:?}"), } } - inlay.poll(|x, p| x.ok().or(p.1), &l.runtime); + inlay.poll(|x, p| x.ok().or(p.1).inspect(|x| { + text.set_inlay(x); + }), &l.runtime); diag.poll(|x, _|x.ok().flatten(), &l.runtime); if let CompletionState::Complete(rq)= &mut complete { rq.poll(|f, (c,_)| { @@ -391,7 +391,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { (x, 0, None) } }), &l.runtime); - hovering.poll(|x, (_, p)|x.ok().flatten().or(p), &l.runtime); + hovering.poll(|x, _| x.ok().flatten(), &l.runtime); } match event { Event::AboutToWait => {} Event::WindowEvent { @@ -512,13 +512,14 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { }); }; if r.start == r.end { - x.get((r.start.character as _, p as _)).map(f); + x.get(text.map_to_visual((r.start.character as _, p as _)).unwrap()).map(f); } else { - x.get_range((r.start.character as _, p as _), (r.end.character as usize, r.end.line as _)) + x.get_range(text.map_to_visual((r.start.character as _, p as _)).unwrap(), + text.map_to_visual((r.end.character as usize, r.end.line as _)).unwrap()) .for_each(f) } let l = r.start.line as usize; - let Some(x_) = text.rope.get_line(l).map(|x|x.len_chars() + 2) else { + let Some(x_) = text.visual_eol(l).map(_+2) else { return; }; let m = m.lines().next().unwrap_or(m); @@ -543,11 +544,11 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { .enumerate() .for_each(|(i, m)| { for x in x.get_range( - text.xy(text.rope.byte_to_char(m.start())), text.xy(text + text.map_to_visual(text.xy(text.rope.byte_to_char(m.start())).unwrap()).unwrap(),text.map_to_visual( text.xy(text .rope .byte_to_char( m.end(), - ))) + )).unwrap()).unwrap()) { x.style.bg = if i == *j { [105, 83, 128] @@ -572,7 +573,6 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { }) => Some(legend), _ => None, }), - inlay.result.as_deref() ); bar.write_to( @@ -616,7 +616,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { assert!(w < window.inner_size().width as _ &&h < window.inner_size().height as _); let is_above = position.1.checked_sub(h).is_some(); let top = position.1.checked_sub(h).unwrap_or(((((_y + 1) as f32) * (fh + ls * fac)).round() + toy) as usize); - let (_, y) = dsb::fit(&fonts.regular, ppem, ls, (window.inner_size().width as _ /* - left */,(window.inner_size().height as usize - top) )); + let (_, y) = dsb::fit(&fonts.regular, ppem, ls, (window.inner_size().width as _ /* - left */,((window.inner_size().height as usize).saturating_sub( top)) )); /* suspicious saturation */ r = r.min(y); let left = @@ -639,7 +639,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { }; let mut pass = true; if let Some((lsp, p)) = lsp!() && let Some(diag) = lsp.diagnostics.get(&Url::from_file_path(p).unwrap(), &lsp.diagnostics.guard()) { - let dawg = diag.iter().filter(|diag| text.l_range(diag.range).is_ok_and(|x| x.contains(&text.index_at(cursor_position)) && (text.vo..text.vo+r).contains(&(diag.range.start.line as _)))); + let dawg = diag.iter().filter(|diag| text.l_range(diag.range).is_ok_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") { Some(x) if let Some(x) = x.as_str() => { @@ -650,27 +650,37 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { 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 (_,left, top, w, h) = place_around_cursor( - (diag.range.start.character as usize+text.line_number_offset()+1, diag.range.start.line as usize - text.vo), + let (_,left, top, w, h) = place_around_cursor( + text.map_to_visual((diag.range.start.character as _, diag.range.start.line as usize)) + .map(|(x, y)| (x + text.line_number_offset() + 1, y - text.vo)) + .unwrap_or((diag.range.start.character as _, diag.range.start.line as usize - text.vo)), &mut fonts, i.as_mut(), &n, x_lim, 17.0, -400., 0., 0., 0. ); pass=false; - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, [0;3]); + i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); }, _ => {} } } }; - hovering.result.as_ref().filter(|_|pass).map(|x| x.span.clone().map(|sp| { - let [(_x, _y), (_x2, _)] = text.position(sp); + 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 _y = _y.wrapping_sub(text.vo); - if !(cursor_position.1 == _y && (_x..=_x2).contains(&cursor_position.0)) { + let Some(_y) = _y.checked_sub(text.vo) 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); @@ -681,7 +691,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { c, x.item.c, 18.0, 10.0, 0., 0., 0. ); - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, [0;3]); + i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); })); let com = match complete { CompletionState::Complete(Rq{ result: Some(ref x,),..}) => { @@ -698,7 +708,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let _x = _x + text.line_number_offset()+1; let Some(_y) = _y.checked_sub(text.vo) else { break 'out }; let (is_above,left, top, w, mut h) = place_around_cursor((_x, _y), &mut fonts, i.as_mut(), &c, 40, ppem, ls, 0., 0., 0.); - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, [0;3]); + i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); let com = com.map(|c| { let (is_above_,left, top, w_, h_) = place_around_cursor( @@ -707,7 +717,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { i.as_mut(), &c, 40, ppem, ls, 0., -(h as f32), if is_above { 0.0 } else { h as f32 } ); - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w_ as _,h_ as _, [0;3]); + i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w_ as _,h_ as _, BORDER); if is_above { // completion below, we need to push the docs, if any, below only below us, if the sig help is still above. h = h_; } else { @@ -727,7 +737,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let (_,left_, top_, _w_, h_) = place_around_cursor((_x, _y), &mut fonts, i.as_mut(), cells, cols, ppem, ls, 0., -(h as f32), if is_above { com.filter(|x| !x.0).map(|(_is, _l, _t, _w, h)| h).unwrap_or_default() as f32 } else { h as f32 }); - i.r#box((left_.saturating_sub(1) as _, top_.saturating_sub(1) as _), w as _,h_ as _, [0;3]); + i.r#box((left_.saturating_sub(1) as _, top_.saturating_sub(1) as _), w as _,h_ as _, BORDER); }); } } else if let Some(c) = com { @@ -741,7 +751,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { i.as_mut(), &c, 40, ppem, ls, 0., 0., 0. ); - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, [0;3]); + i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); } } let met = FONT.metrics(&[]); @@ -767,12 +777,12 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { ); } }; - let (x, y) = text.cursor(); + let (x, y) = text.cursor_visual(); let image = Image::<_, 4>::build(2, (fh).ceil() as u32) .fill([82,82,82, 255]); for stop in text.tabstops.as_ref().into_iter().flat_map(|x|x.list()) { - let (x, y) = text.xy(stop.clone().r().end); + let Some((x, y)) = text.xy(stop.clone().r().end) else { continue }; draw_at(x, y, &image); } if matches!( @@ -819,45 +829,60 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { { Some(Do::ExtendSelectionToMouse) => { *state.sel() = text.extend_selection_to( - text.index_at(cursor_position), + text.mapped_index_at(cursor_position), state.sel().clone(), ); window.request_redraw(); } Some(Do::StartSelection) => { - let x = text.index_at(cursor_position); + let x = text.mapped_index_at(cursor_position); hist.last.cursor = x; text.cursor = x; *state.sel() = x..x; } - Some(Do::Hover) if let Some(hover) = text.raw_index_at(cursor_position) => { - // assert_eq!(hover, text.index_at(cursor_position)); - let (x, y) =text.xy(hover); - let text = text.clone(); - 'out: { - let l = &mut hovering.result; - if let Some(Hovr{ span: Some(span),..}) = &*l { - let [(_x, _y), (_x2, _)] = text.position(span.clone()); - let [_x, _x2] = [_x, _x2].add(text.line_number_offset()+1); - let Some(_y) = _y.checked_sub(text.vo) else { break 'out }; - if cursor_position.1 == _y && (_x.._x2).contains(&cursor_position.0) { - break 'out; - } else { - *l = None; - window.request_redraw(); - } - if let Some((_, c)) = hovering.request && c == hover { - break 'out; - } + Some(Do::Hover) if let Some(hover) = text.visual_index_at(cursor_position) && + let Some((cl, o)) = lsp!() => 'out: { + let l = &mut hovering.result; + if let Some(Hovr{ span: Some([(_x, _y), (_x2, _)]),..}) = &*l { + let Some(_y) = _y.checked_sub(text.vo) else { break 'out }; + if cursor_position.1 == _y && (_x..=_x2).contains(&&(cursor_position.0 - 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); + *l = None; + window.request_redraw(); } - if let Some((cl, o)) = lsp!() { - // if !running.insert(hover) {return} - let (rx, _) = cl.request::<HoverRequest>(&HoverParams { -text_document_position_params: TextDocumentPositionParams { text_document: TextDocumentIdentifier::new(Url::from_file_path(o).unwrap()), position: Position { - line: y as _, character: x as _, -}}, -work_done_progress_params:default() }).unwrap(); -let handle = cl.runtime.spawn(window.redraw_after(async move { + } + let text = text.clone(); + let mut rang = None; + let z = match hover { + Mapping::Char(_, _, i) => { + TextDocumentPositionParams { position: text.to_l_position(i), text_document: o.tid() } + }, + Mapping::Fake(mark, index, _) => { + let Some(ref loc) = mark.l[index].1 else { + break 'out; + }; + let (x, y) = text.xy(mark.start).unwrap(); + let Some(begin) = text.reverse_source_map(y) else { break 'out }; + let start = begin[x - 1] + 1; + let left = mark.l[..index].iter().rev().take_while(_.1.as_ref() == Some(loc)).count(); + let start = start + index - left; + let length = mark.l[index..].iter().take_while(_.1.as_ref() == Some(loc)).count() + left; + rang = Some([(start, y), (start + length, y)]); + TextDocumentPositionParams { text_document: TextDocumentIdentifier { uri: loc.uri.clone() }, position: loc.range.start } + } + }; +if let Some((_, c)) = hovering.request && c == cursor_position { + break 'out; +} + // if !running.insert(hover) {return} +let (rx, _) = cl.request::<HoverRequest>(&HoverParams { + text_document_position_params: z, + work_done_progress_params:default() +}).unwrap(); +// println!("rq hov of {hover:?} (cur {})", hovering.request.is_some()); +let handle: tokio::task::JoinHandle<Result<Option<Hovr>, anyhow::Error>> = cl.runtime.spawn(window.redraw_after(async move { let Some(x) = rx.await? else {return Ok(None::<Hovr>)}; let (w, cells) = spawn_blocking(move || { let x = match &x.contents { @@ -881,13 +906,15 @@ let handle = cl.runtime.spawn(window.redraw_after(async move { let m = hov::l(&x).into_iter().max().map(_+2).unwrap_or(usize::MAX).min(c-10); (m, hov::markdown2(m, &x)) }).await.unwrap(); - let span = x.range.and_then(|x| text.l_range(x).ok()); + let span = rang.or_else(|| x.range.and_then(|range| try { + let x1 = text.reverse_source_map(range.start.line as _)?[range.start.character as usize]; + let x2 = text.reverse_source_map(range.end.line as _)?[range.end.character as usize]; + [(x1, range.start.line as _), (x2, range.start.line as _)] + })); anyhow::Ok(Some( hov::Hovr { span, item: text::CellBuffer { c: w, vo: 0, cells: cells.into() }}.into())) })); -hovering.request = (DropH::new(handle), hover).into(); -} - } - +hovering.request = (DropH::new(handle), cursor_position).into(); +// hovering.result = None; // lsp!().map(|(cl, o)| { // let window = window.clone(); // }); @@ -912,17 +939,18 @@ hovering.request = (DropH::new(handle), hover).into(); _ = complete.consume(CompletionAction::Click).unwrap(); match state.consume(Action::M(button)).unwrap() { Some(Do::MoveCursor) => { - text.cursor = text.index_at(cursor_position); + text.cursor = text.mapped_index_at(cursor_position); text.setc(); } Some(Do::ExtendSelectionToMouse) => { + println!("ext2"); *state.sel() = text.extend_selection_to( - text.index_at(cursor_position), + text.mapped_index_at(cursor_position), state.sel().clone(), ); } Some(Do::StartSelection) => { - let x = text.index_at(cursor_position); + let x = text.mapped_index_at(cursor_position); hist.last.cursor = x; *state.sel() = text.extend_selection_to( x, @@ -1511,6 +1539,6 @@ fn frunctinator( _paramter4: u16, ) -> usize { lower::saturating::math! { parameter1 }; - + 0 -}
\ No newline at end of file +} |