A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 157 |
1 files changed, 70 insertions, 87 deletions
diff --git a/src/main.rs b/src/main.rs index 89e1d90..b84dda5 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( + thread_local, result_option_map_or_default, iter_intersperse, stmt_expr_attributes, @@ -35,6 +36,7 @@ use std::time::Instant; use Default::default; use NamedKey::*; +use array_chunks::ExtensionTrait; use atools::prelude::AASAdd; use crossbeam::channel::RecvError; use diff_match_patch_rs::PatchInput; @@ -65,7 +67,7 @@ use winit::window::{Icon, Window}; use crate::bar::Bar; use crate::hov::Hovr; -use crate::text::{Diff, TextArea}; +use crate::text::{Diff, TextArea, is_word}; mod bar; pub mod com; pub mod hov; @@ -221,10 +223,10 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { ); c.open(&origin, std::fs::read_to_string(&origin).unwrap()) .unwrap(); - (c, (t, t2), changed) + (&*Box::leak(Box::new(c)), (t, t2), changed) }, ); - let (lsp, t, ch) = match c { + let (lsp, t, mut w) = match c { Some((a, b, c)) => (Some(a), Some(b), Some(c)), None => (None, None, None), }; @@ -261,15 +263,8 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { .map(|x| x.metadata().unwrap().modified().unwrap()) }; } - macro_rules! change { - () => { - lsp!().map(|(x, origin)| { - x.edit(&origin, text.rope.to_string()).unwrap(); - x.rq_semantic_tokens(origin).unwrap(); - }); - }; - } - lsp!().map(|(x, origin)| x.rq_semantic_tokens(origin).unwrap()); + + lsp!().map(|(x, origin)| x.rq_semantic_tokens(origin, None).unwrap()); let mut mtime = modify!(); macro_rules! save { () => {{ @@ -282,7 +277,6 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { mtime = modify!(); }}; } - static PUT: OnceLock<Arc<Window>> = OnceLock::new(); let app = winit_app::WinitAppBuilder::with_init( move |elwt| { let window = winit_app::make_window(elwt, |x| { @@ -290,9 +284,12 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { .with_name("com.bendn.gracilaria", "") .with_window_icon(Some(Icon::from_rgba(include_bytes!("../dist/icon-32").to_vec(), 32, 32).unwrap())) }); + if let Some(x) = w.take() { + x.send(window.clone()).unwrap(); + } + window.set_ime_allowed(true); window.set_ime_purpose(winit::window::ImePurpose::Terminal); - PUT.set(window.clone()).unwrap(); let context = softbuffer::Context::new(window.clone()).unwrap(); @@ -304,6 +301,14 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { ) .with_event_handler( move |(window, _context), surface, event, elwt| { + macro_rules! change { + () => { + lsp!().map(|(x, origin)| { + x.edit(&origin, text.rope.to_string()).unwrap(); + x.rq_semantic_tokens(origin, Some(window.clone())).unwrap(); + }); + }; + } elwt.set_control_flow(ControlFlow::Wait); let (fw, fh) = dsb::dims(&FONT, ppem); let (c, r) = dsb::fit( @@ -321,16 +326,15 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { 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{ + 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, +r:x,start:c,selection:0,vo:0, } ); if let Some(x) = o { - std::fs::write("complete_", serde_json::to_string_pretty(&x.r).unwrap()).unwrap(); - println!("resolved") + // std::fs::write("complete_", serde_json::to_string_pretty(&x.r).unwrap()).unwrap(); + // println!("resolved") } // println!("{complete:#?}"); // } else { @@ -456,7 +460,7 @@ r:x,start:0,selection:0,scroll:0, .unwrap_or("new buffer"), &state, &text, - lsp.as_ref() + lsp ); unsafe { dsb::render( @@ -723,10 +727,7 @@ RUNNING.remove(&hover,&RUNNING.guard()); if button == MouseButton::Left { unsafe { CLICKING = true }; } - match complete.consume(CompletionAction::Click).unwrap() { - Some(CDo::Abort(x))=>{ x.abort() }, - _ => {}, - } + _ = complete.consume(CompletionAction::Click).unwrap(); match state.consume(Action::M(button)).unwrap() { Some(Do::MoveCursor) => { text.cursor = text.index_at(cursor_position); @@ -832,56 +833,40 @@ RUNNING.remove(&hover,&RUNNING.guard()); Some(Do::Edit) => { hist.test_push(&text); let cb4 = text.cursor; - let r = handle2(&event.logical_key, &mut text); + if let Key::Named(Enter | ArrowUp | ArrowDown | Tab) = event.logical_key && let CompletionState::Complete(..) = complete{ + } else { + handle2(&event.logical_key, &mut text); + } + text.scroll_to_cursor(); + if cb4 != text.cursor && let CompletionState::Complete(Some(c), t)= &mut complete + && ((text.cursor < c.start) || (!is_word(text.at_())&& (text.at_() != '.' || text.at_() != ':')) ) { + if let Some((x, _)) = t.take() { + x.abort(); + } + complete = CompletionState::None; + } if hist.record(&text) { change!(); } -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 - // }))); + match complete.consume(CompletionAction::K(event.logical_key.as_ref())).unwrap(){ + Some(CDo::Request(ctx)) => { + let x = lsp.request_complete(o, text.cursor(), ctx); + let h = lsp.runtime.spawn(async move { + x.await.inspect(|_| window.request_redraw()) + }); + let CompletionState::Complete(c, x) = &mut complete else { panic!()}; + *x = Some((h,c.as_ref().map(|x|x.start).or(x.as_ref().map(|x|x.1)).unwrap_or(text.cursor))); } 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); @@ -1018,16 +1003,6 @@ if let Some(r) = r { }; }, ); - 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); } @@ -1241,26 +1216,33 @@ impl<T> M<T> for Option<T> { rust_fsm::state_machine! { #[derive(Debug)] - pub(crate) CompletionState => CompletionAction => CDo + pub(crate) CompletionState => CompletionAction<'i> => CDo None => Click => None, - None => TypeCharacter => Complete( + None => K(Key<&'i str> => Key::Character(k @ ("." | ":"))) => Complete( (Option<Complete>, Option<(JoinHandle< Result< Option<CompletionResponse>, tokio::sync::oneshot::error::RecvError, >, >, usize)>) => (None,None) - ) [Request], + ) [Request(CompletionContext => CompletionContext {trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, trigger_character:Some(k.to_string()) })], + None => K(Key::Named(NamedKey::Space) if ctrl()) => Complete((None, None)) [Request(CompletionContext { trigger_kind: CompletionTriggerKind::INVOKED, trigger_character:None })], + None => K(Key::Character(x) if x.chars().next().is_some_and(is_word)) => Complete((None,None)) [Request(CompletionContext { trigger_kind: CompletionTriggerKind::INVOKED, trigger_character:None })], + None => K(_) => _, + + // when + Complete((_x,_y)) => K(Key::Named(NamedKey::Tab) if shift()) => _ [SelectPrevious], + Complete((_x,_y)) => K(Key::Named(NamedKey::Tab)) => _ [SelectNext], + + // exit cases 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 + Complete((_x, Some((y, _)))) => Click => None [Abort(((),) => y.abort())], + Complete((_x, Some((y, _)))) => K(Key::Character(x) if !x.chars().all(is_word)) => None [Abort(y.abort())], + Complete((_x, None)) => K(Key::Character(x) if !x.chars().all(is_word)) => None, + + Complete((_x, _y)) => K(_) => _ [Request(CompletionContext { trigger_kind: CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS, trigger_character:None })], + Complete((Some(x), task)) => K(Key::Named(NamedKey::Enter)) => None [Finish(Complete => { + task.map(|(task, _)| task.abort()); x })] } impl Default for CompletionState { @@ -1268,9 +1250,10 @@ impl Default for CompletionState { Self::None } } -#[derive(Debug)] struct Complete { +#[derive(Debug)] +struct Complete { r: CompletionResponse, start: usize, selection: usize, - scroll: usize, + vo: usize, } |