A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 261 |
1 files changed, 177 insertions, 84 deletions
diff --git a/src/main.rs b/src/main.rs index e0f5289..4f04d36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,17 @@ // this looks pretty good though #![feature(tuple_trait, unboxed_closures, fn_traits)] #![feature( + iter_intersperse, stmt_expr_attributes, + new_range_api, + iter_collect_into, mpmc_channel, const_cmp, - // generator_trait, gen_blocks, const_default, - coroutines,iter_from_coroutine,coroutine_trait, + coroutines, + iter_from_coroutine, + coroutine_trait, cell_get_cloned, import_trait_associated_functions, if_let_guard, @@ -18,33 +22,34 @@ portable_simd )] #![allow(incomplete_features, redundant_semicolons)] -use std::convert::identity; +use std::borrow::Cow; use std::io::BufReader; -use std::mem::forget; use std::num::NonZeroU32; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use std::rc::Rc; use std::sync::{Arc, LazyLock, OnceLock}; use std::thread; use std::time::Instant; use Default::default; use NamedKey::*; +use atools::prelude::AASAdd; use diff_match_patch_rs::PatchInput; use dsb::cell::Style; use dsb::{Cell, F}; -use fimg::Image; +use fimg::{Image, OverlayAt}; use lsp_types::request::HoverRequest; use lsp_types::{ - Hover, HoverParams, Position, SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceFolder + Hover, HoverParams, MarkedString, Position, SemanticTokensOptions, + SemanticTokensServerCapabilities, ServerCapabilities, + TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceFolder, }; -use minimad::{Composite, CompositeStyle}; -use parking_lot::RwLock; +use parking_lot::Mutex; use regex::Regex; use ropey::Rope; use rust_fsm::StateMachineImpl; use swash::{FontRef, Instance}; +use tokio::task::spawn_blocking; use url::Url; use winit::event::{ ElementState, Event, MouseButton, MouseScrollDelta, WindowEvent, @@ -55,12 +60,13 @@ use winit::platform::wayland::WindowAttributesExtWayland; use winit::window::{Icon, Window}; use crate::bar::Bar; +use crate::hov::Hovr; use crate::text::{Diff, TextArea}; mod bar; +pub mod hov; mod lsp; mod text; mod winit_app; -mod hov; fn main() { env_logger::init(); // lsp::x(); @@ -185,38 +191,44 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { .as_ref() .and_then(|x| rooter(&x.parent().unwrap())) .and_then(|x| x.canonicalize().ok()); - let c = workspace.zip(origin.clone()).map(|(workspace, origin)| { - let mut c = Command::new("rust-analyzer") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .spawn() - .unwrap(); + let c = workspace.as_ref().zip(origin.clone()).map( + |(workspace, origin)| { + let mut c = Command::new("rust-analyzer") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .unwrap(); - let (c, t, t2, changed) = lsp::run( - lsp_server::stdio::stdio_transport( - BufReader::new(c.stdout.take().unwrap()), - c.stdin.take().unwrap(), - ), - WorkspaceFolder { - uri: Url::from_file_path(&workspace).unwrap(), - name: workspace - .file_name() - .unwrap() - .to_string_lossy() - .into_owned(), - }, - ); - c.open(&origin, std::fs::read_to_string(&origin).unwrap()) - .unwrap(); - ((c, origin), (t, t2), changed) - }); - let (lsp, t, ch) = match c { - Some((a,b,c)) => { - (Some(a), Some(b), Some(c)) + let (c, t, t2, changed) = lsp::run( + lsp_server::stdio::stdio_transport( + BufReader::new(c.stdout.take().unwrap()), + c.stdin.take().unwrap(), + ), + WorkspaceFolder { + uri: Url::from_file_path(&workspace).unwrap(), + name: workspace + .file_name() + .unwrap() + .to_string_lossy() + .into_owned(), + }, + ); + c.open(&origin, std::fs::read_to_string(&origin).unwrap()) + .unwrap(); + (c, (t, t2), changed) }, - None => { (None, None, None) } - }; + ); + let (lsp, t, ch) = match c { + Some((a, b, c)) => (Some(a), Some(b), Some(c)), + None => (None, None, None), + }; + macro_rules! lsp { + () => { + lsp.as_ref().zip(origin.as_deref()) + }; + } + let hovering = &*Box::leak(Box::new(Mutex::new(None::<hov::Hovr>))); // let mut hl_result = None; @@ -236,13 +248,13 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { } macro_rules! change { () => { - lsp.as_ref().map(|(x, origin)| { + lsp!().map(|(x, origin)| { x.edit(&origin, text.rope.to_string()).unwrap(); x.rq_semantic_tokens(origin).unwrap(); }); }; } - lsp.as_ref().map(|(x, origin)| x.rq_semantic_tokens(origin).unwrap()); + lsp!().map(|(x, origin)| x.rq_semantic_tokens(origin).unwrap()); let mut mtime = modify!(); macro_rules! save { () => {{ @@ -341,6 +353,9 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { if size.height != 0 && size.width != 0 { let now = Instant::now(); + if c*r!=cells.len(){ + return; + } cells.fill(Cell { style: Style { color: BG, bg: BG, flags: 0 }, letter: None, @@ -392,7 +407,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { } }, origin.as_deref(), - lsp.as_ref().and_then(|(x, _)| { match &x.initialized { + lsp!().and_then(|(x, _)| { match &x.initialized { Some(lsp_types::InitializeResult { capabilities: ServerCapabilities { semantic_tokens_provider: @@ -411,11 +426,11 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { r - 1, origin .as_ref() - .map(|x| x.to_str().unwrap()) + .map(|x| workspace.as_ref().and_then(|w| x.strip_prefix(w).ok()).unwrap_or(&x).to_str().unwrap()) .unwrap_or("new buffer"), &state, &text, - lsp.as_ref().map(|x| &x.0) + lsp.as_ref() ); unsafe { dsb::render( @@ -427,13 +442,52 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { ls, true, i.as_mut(), - ) + ) }; + hovering.lock().as_ref().map(|x| x.span.clone().map(|sp| { + let met = FONT.metrics(&[]); + let fac = ppem / met.units_per_em as f32; + let [(_x, _y), (_x2, _)] = text.position(sp); + let [_x, _x2] = [_x, _x2].add(text.line_number_offset()+1); + let _y = _y - text.vo; + if !(cursor_position.1 == _y && (_x..=_x2).contains(&cursor_position.0)) { + return; + } + let position = ( + ((_x) as f32 * fw).round() as usize, + ((_y as f32 as f32) * (fh + ls * fac)).round() as usize, + ); + + let ppem = 18.0; + let ls = 10.0; + let r = x.item.l().min(15); + let c = x.item.displayable(r); + let (w, h) = dsb::size(&fonts.regular, ppem, ls, (x.item.c, r)); + let top = position.1.checked_sub(h).unwrap_or((((_y + 1) as f32) * (fh + ls * fac)).round() as usize,); + let left = + if position.0 + w as usize > window.inner_size().width as usize { + window.inner_size().width as usize- w as usize + } else { position.0 }; + + let mut i2 = Image::build(w as _, h as _).fill(BG); + unsafe{ dsb::render( + &c, + (x.item.c, 0), + ppem, + hov::BG, + &mut fonts, + ls, + true, + i2.as_mut(), + )}; + // dbg!(w, h, i2.width(), i2.height(), window.inner_size(), i.width(),i.height()); + unsafe { i.overlay_at(&i2.as_ref(), left as u32, top as u32) }; + i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), i2.width(), i2.height(), [0;3]); + })); let met = FONT.metrics(&[]); let fac = ppem / met.units_per_em as f32; // if x.view_o == Some(x.cells.row) || x.view_o.is_none() { - use fimg::OverlayAt; let (fw, fh) = dsb::dims(&FONT, ppem); let cursor = Image::<_, 4>::build(3, (fh).ceil() as u32) @@ -509,41 +563,76 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { text.cursor = x; *state.sel() = x..x; } - Some(Do::Hover) => { - let hover = text.index_at(cursor_position); + 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 s = lsp.as_ref().map(|(c, o)| { - let (rx, id) = c.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(); - c.runtime.spawn(async { - let x = rx.await?.load::<Hover>()?; - // dbg!(&x); - match x.contents { - lsp_types::HoverContents::Scalar(marked_string) => { - println!("{marked_string:?}"); - }, - lsp_types::HoverContents::Array(marked_strings) => { - println!("{marked_strings:?}"); - - }, - lsp_types::HoverContents::Markup(markup_content) => { - println!("{}", markup_content.value); - // dbg!(minimad::Text::from(&*markup_content.value)); - }, - } - anyhow::Ok(()) - }) + let text = text.clone(); + { + let mut l = hovering.lock(); + 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 _y = _y - text.vo; + if cursor_position.1 == _y && (_x.._x2).contains(&cursor_position.0) { + return + } else { + *l = None; + window.request_redraw(); + } + } + } + let hovering = hovering; + lsp!().map(|(cl, o)| { +let window = window.clone(); +static RUNNING: LazyLock< papaya::HashSet<usize, >>= LazyLock::new(||papaya::HashSet::new()); +if !RUNNING.insert(hover, &RUNNING.guard()) {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(); +cl.runtime.spawn(async move { + let x = rx.await?.load::<Hover>()?; + let (w, cells) = spawn_blocking(move || { + let x = match &x.contents { + lsp_types::HoverContents::Scalar(marked_string) => { + match marked_string{ + MarkedString::LanguageString(x) =>Cow::Borrowed(&*x.value), + MarkedString::String(x) => Cow::Borrowed(&**x), + } + }, + lsp_types::HoverContents::Array(marked_strings) => { + Cow::Owned(marked_strings.iter().map(|x| match x{ + MarkedString::LanguageString(x) => &*x.value, + MarkedString::String(x) => &*x, + }).collect::<String>()) + }, + lsp_types::HoverContents::Markup(markup_content) => { + Cow::Borrowed(&*markup_content.value) + }, + }; + let x = hov::p(&x).unwrap(); + let m = hov::l(&x).into_iter().max().map(_+2).unwrap_or(usize::MAX).min(c-10); + (m, hov::markdown2(m, &x)) +}).await.unwrap(); +RUNNING.remove(&hover,&RUNNING.guard()); + let span = x.range.and_then(|x| { + Some(text.l_position(x.start).ok()?..text.l_position(x.end).ok()?) + }); + *hovering.lock()= Some( hov::Hovr { span, item: text::CellBuffer { c: w, vo: 0, cells: cells.into() }}.into()); + window.request_redraw(); + anyhow::Ok(()) +}); }); - + } + Some(Do::Hover) => { + *hovering.lock() = None; + window.request_redraw(); } None => {} x => unreachable!("{x:?}"), } } - Event::WindowEvent { event: WindowEvent::MouseInput { state: bt, button, .. }, @@ -796,12 +885,17 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { _ => {} }; }, - ); - ch.map(|ch| thread::Builder::new().name("redrawer".into()).spawn(move || { - for () in ch { - PUT.get().map(|x| x.request_redraw()); - } - })); + ); + ch.map(|ch| { + thread::Builder::new().name("redrawer".into()).spawn(move || { + for () in ch { + PUT.get().map(|x| { + x.request_redraw(); + println!("rq redraw"); + }); + } + }) + }); winit_app::run_app(event_loop, app); } @@ -886,7 +980,7 @@ impl State { } } -use std::ops::Range; +use std::ops::{Not, Range}; rust_fsm::state_machine! { #[derive(Clone, Debug)] @@ -907,8 +1001,7 @@ Default => { M(MouseButton => MouseButton::Left) => _ [MoveCursor], C(((usize, usize)) => .. if unsafe { CLICKING }) => Selection(0..0) [StartSelection], Changed => RequestBoolean(BoolRequest => BoolRequest::ReloadFile), - C(_ if false) => _ [Hover], - C(_) => _, + C(_) => _ [Hover], K(_) => _ [Edit], M(_) => _, }, |