A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 196 |
1 files changed, 186 insertions, 10 deletions
diff --git a/src/main.rs b/src/main.rs index 74b066e..89e1d90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ // this looks pretty good though #![feature(tuple_trait, unboxed_closures, fn_traits)] #![feature( + result_option_map_or_default, iter_intersperse, stmt_expr_attributes, new_range_api, @@ -26,6 +27,7 @@ use std::borrow::Cow; use std::io::BufReader; use std::num::NonZeroU32; use std::path::{Path, PathBuf}; +use std::pin::Pin; use std::process::{Command, Stdio}; use std::sync::{Arc, LazyLock, OnceLock}; use std::thread; @@ -34,22 +36,24 @@ use std::time::Instant; use Default::default; use NamedKey::*; use atools::prelude::AASAdd; +use crossbeam::channel::RecvError; use diff_match_patch_rs::PatchInput; use dsb::cell::Style; use dsb::{Cell, F}; use fimg::{Image, OverlayAt}; -use lsp_types::request::HoverRequest; +use lsp_types::request::{Completion, HoverRequest}; use lsp_types::{ - Hover, HoverParams, MarkedString, Position, SemanticTokensOptions, + CompletionContext, CompletionResponse, CompletionTriggerKind, Hover, + HoverParams, MarkedString, Position, SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceFolder, }; use parking_lot::Mutex; use regex::Regex; use ropey::Rope; -use rust_fsm::StateMachineImpl; +use rust_fsm::StateMachine; use swash::{FontRef, Instance}; -use tokio::task::spawn_blocking; +use tokio::task::{JoinHandle, spawn_blocking}; use url::Url; use winit::event::{ ElementState, Event, MouseButton, MouseScrollDelta, WindowEvent, @@ -61,8 +65,9 @@ use winit::window::{Icon, Window}; use crate::bar::Bar; use crate::hov::Hovr; -use crate::text::{ Diff, TextArea}; +use crate::text::{Diff, TextArea}; mod bar; +pub mod com; pub mod hov; mod lsp; mod text; @@ -229,7 +234,17 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { }; } let hovering = &*Box::leak(Box::new(Mutex::new(None::<hov::Hovr>))); - + let mut complete = CompletionState::None; + // let mut complete = None::<(CompletionResponse, (usize, usize))>; + // let mut complete_ = None::<( + // JoinHandle< + // Result< + // Option<CompletionResponse>, + // tokio::sync::oneshot::error::RecvError, + // >, + // >, + // (usize, usize), + // )>; // let mut hl_result = None; let mut hist = Hist { @@ -305,6 +320,24 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { state.consume(Action::Changed).unwrap(); window.request_redraw(); } + if let CompletionState::Complete(o, x)= &mut complete && + x.as_ref().is_some_and(|(x, _)|x.is_finished()) && let Some((task, c)) = x.take() && let Some(ref l) = lsp{ + // if text.cursor() ==* c_ { + println!("bl0ck on"); + + *o = l.runtime.block_on(task).ok().and_then(Result::ok).flatten().map(|x| Complete { +r:x,start:0,selection:0,scroll:0, + } ); + if let Some(x) = o { + std::fs::write("complete_", serde_json::to_string_pretty(&x.r).unwrap()).unwrap(); + println!("resolved") + } + // println!("{complete:#?}"); + // } else { + // println!("abort {c_:?}"); + // x.abort(); + // } + } match event { Event::AboutToWait => {} Event::WindowEvent { @@ -436,6 +469,60 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { i.as_mut(),(0,0) ) }; + if let CompletionState::Complete(Some(ref x,),_) = complete { + let c = com::s(x, 40,&if matches!(text.rope.get_char(text.cursor-1), Some('.' | ':')) { + "".to_string() + } else { + text.rope.slice(text.word_left_p()..text.cursor).chars().collect::<String>() + }); + let ppem = 20.0; + + let met = FONT.metrics(&[]); + let fac = ppem / met.units_per_em as f32; + let (_x, _y) = text.cursor(); + let _x = _x + text.line_number_offset()+1; + + // let [(_x, _y), (_x2, _)] = text.position(text.cursor); + // 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)) { + // return; + // } + let position = ( + ((_x) as f32 * fw).round() as usize, + ((_y as f32 as f32) * (fh + ls * fac)).round() as usize, + ); + + + + let ls = 10.0; + let mut r = c.len()/40; + let (w, h) = dsb::size(&fonts.regular, ppem, ls, (40, r)); + let top = position.1.checked_sub(h).unwrap_or((((_y + 1) as f32) * (fh + ls * fac)).round() as usize,); + let (_, y) = dsb::fit(&fonts.regular, ppem, ls, (window.inner_size().width as _ /* - left */,( window.inner_size().height as usize - top ) )); + r = r.min(y); + + 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 (w, h) = dsb::size(&fonts.regular, ppem, ls, (40, r)); + // let mut i2 = Image::build(w as _, h as _).fill(BG); + unsafe{ dsb::render( + &c, + (40, 0), + ppem, + &mut fonts, + ls, + true, + i.as_mut(), + (left as _, top as _) + )}; + // 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 _), w as _,h as _, [0;3]); + } hovering.lock().as_ref().map(|x| x.span.clone().map(|sp| { let met = FONT.metrics(&[]); let fac = ppem / met.units_per_em as f32; @@ -636,6 +723,10 @@ RUNNING.remove(&hover,&RUNNING.guard()); if button == MouseButton::Left { unsafe { CLICKING = true }; } + match complete.consume(CompletionAction::Click).unwrap() { + Some(CDo::Abort(x))=>{ x.abort() }, + _ => {}, + } match state.consume(Action::M(button)).unwrap() { Some(Do::MoveCursor) => { text.cursor = text.index_at(cursor_position); @@ -740,12 +831,57 @@ RUNNING.remove(&hover,&RUNNING.guard()); } Some(Do::Edit) => { hist.test_push(&text); - handle2(event.logical_key, &mut text); + let cb4 = text.cursor; + let r = handle2(&event.logical_key, &mut text); text.scroll_to_cursor(); + if hist.record(&text) { change!(); } -lsp!().map(|x|x.0.request_complete(x.1, text.cursor()));; +if let Some(r) = r { + lsp!().map(|(lsp, o)|{ + let window = window.clone(); + let ctx = match complete.consume(CompletionAction::TypeCharacter).unwrap() { + Some(CDo::Request) => { + CompletionContext { + trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, trigger_character:Some(r.to_string()) } + + // println!("make rq"); + // let x = lsp.request_complete(o, text.cursor(), ); + // let h = lsp.runtime.spawn(async move { + // let r = x.await; + // window.request_redraw(); + // r + // }); + // complete = CompletionState::Complete(None, Some((h,cb4))); + // dbg!(&complete); + } + Some(CDo::Update) => { + // CompletionContext { + // trigger_kind: CompletionTriggerKind + CompletionContext { + trigger_kind: CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS, trigger_character:None } + // complete = CompletionState::Complete(None, Some(lsp.runtime.spawn(async move { + // let r = x.await; + // window.request_redraw(); + // r + // }))); + } + None => {return}, + _ => panic!(), + }; + println!("make rq"); + let x = lsp.request_complete(o, text.cursor(), ctx); + let h = lsp.runtime.spawn(async move { + let r = x.await; + window.request_redraw(); + r + }); + complete = CompletionState::Complete(None, Some((h,text.cursor))); + dbg!(&complete); + + }); +} } Some(Do::Undo) => { hist.test_push(&text); @@ -895,11 +1031,12 @@ lsp!().map(|x|x.0.request_complete(x.1, text.cursor()));; winit_app::run_app(event_loop, app); } -fn handle2(key: Key, text: &mut TextArea) { +fn handle2<'a>(key: &'a Key, text: &mut TextArea) -> Option<&'a str> { use Key::*; match key { Named(Space) => text.insert(" "), + Named(Backspace) if ctrl() => text.backspace_word(), Named(Backspace) => text.backspace(), Named(Home) if ctrl() => { text.cursor = 0; @@ -927,12 +1064,14 @@ fn handle2(key: Key, text: &mut TextArea) { Named(Enter) => text.enter(), Character(x) => { text.insert(&x); + return Some(x); } _ => {} }; + None } fn handle(key: Key, mut text: TextArea) -> TextArea { - handle2(key, &mut text); + handle2(&key, &mut text); text } pub static FONT: LazyLock<FontRef<'static>> = LazyLock::new(|| { @@ -1040,6 +1179,7 @@ Search((x, y, m)) => { K(_) => Default [Reinsert], } } + #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum InputRequest { SaveFile, @@ -1098,3 +1238,39 @@ impl<T> M<T> for Option<T> { *self = self.take().map(f); } } + +rust_fsm::state_machine! { + #[derive(Debug)] + pub(crate) CompletionState => CompletionAction => CDo + None => Click => None, + None => TypeCharacter => Complete( + (Option<Complete>, Option<(JoinHandle< + Result< + Option<CompletionResponse>, + tokio::sync::oneshot::error::RecvError, + >, + >, usize)>) => (None,None) + ) [Request], + Complete((_x, None)) => Click => None, + Complete((_x, Some((y, _)))) => Click => None [Abort(JoinHandle< + Result< + Option<CompletionResponse>, + tokio::sync::oneshot::error::RecvError, + >, + > => y)], + Complete((_x, _y)) => TypeCharacter => _ [Update], + Complete((Some(x), task)) => Enter => None [Finish(Complete => { + if let Some((task, _)) = task { task.abort() }; x + })] +} +impl Default for CompletionState { + fn default() -> Self { + Self::None + } +} +#[derive(Debug)] struct Complete { + r: CompletionResponse, + start: usize, + selection: usize, + scroll: usize, +} |