A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 1573 |
1 files changed, 76 insertions, 1497 deletions
diff --git a/src/main.rs b/src/main.rs index 8acf0bd..699d6f4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -// this looks pretty good though #![feature(tuple_trait, unboxed_closures, fn_traits)] #![feature( anonymous_lifetime_in_impl_trait, @@ -33,55 +32,39 @@ try_blocks, portable_simd )] -#![allow(incomplete_features, redundant_semicolons)] -use std::borrow::Cow; -use std::iter::once; +#![allow(incomplete_features, irrefutable_let_patterns)] mod act; +mod edi; +mod rnd; mod sym; mod trm; -mod edi; + use std::num::NonZeroU32; -use std::os::fd::AsFd; -use std::path::{Path, PathBuf}; use std::sync::LazyLock; use std::time::Instant; -use crate::text::CoerceOption; + use Default::default; use NamedKey::*; -use atools::prelude::AASAdd; use diff_match_patch_rs::PatchInput; -use diff_match_patch_rs::traits::DType; use dsb::cell::Style; -use dsb::{Cell, F, Fonts}; -use fimg::pixels::Blend; -use fimg::{Image, OverlayAt}; +use dsb::{Cell, F}; +use fimg::Image; use lsp::{PathURI, Rq}; -use lsp_server::{Connection, Request as LRq}; -use lsp_types::request::{ - CodeActionResolveRequest, HoverRequest, SignatureHelpRequest, -}; use lsp_types::*; -use regex::Regex; -use ropey::Rope; use rust_fsm::StateMachine; use swash::{FontRef, Instance}; -use tokio::task::spawn_blocking; -use tokio_util::task::AbortOnDropHandle as DropH; -use url::Url; -use winit::dpi::{PhysicalPosition, PhysicalSize}; use winit::event::{ ElementState, Event, Ime, MouseButton, MouseScrollDelta, WindowEvent, }; use winit::event_loop::{ControlFlow, EventLoop}; -use winit::keyboard::{Key, ModifiersState, NamedKey, SmolStr}; +use winit::keyboard::{Key, ModifiersState, NamedKey}; use winit::platform::wayland::WindowAttributesExtWayland; use winit::window::Icon; -use crate::bar::Bar; -use crate::hov::Hovr; -use crate::lsp::{Client, RedrawAfter, RequestError, RqS}; -use crate::sym::Symbols; -use crate::text::{Diff, Mapping, TextArea, col, is_word}; +use crate::edi::Editor; +use crate::edi::st::*; +use crate::lsp::RqS; +use crate::text::{Diff, TextArea, col, is_word}; mod bar; pub mod com; pub mod hov; @@ -95,6 +78,7 @@ fn main() { // let x = HashMap::new(); unsafe { std::env::set_var("CARGO_UNSTABLE_RUSTC_UNICODE", "true") }; env_logger::init(); + // lsp::x(); entry(EventLoop::new().unwrap()) } @@ -106,15 +90,17 @@ struct Hist { pub last: TextArea, pub last_edit: std::time::Instant, pub changed: bool, -}impl Default for Hist{ +} +impl Default for Hist { fn default() -> Self { - Self{ - history: vec![], - redo_history: vec![], - last: TextArea::default(), - last_edit: Instant::now(), - changed: false, - } } + Self { + history: vec![], + redo_history: vec![], + last: TextArea::default(), + last_edit: Instant::now(), + changed: false, + } + } } #[derive(Debug, Default)] struct ClickHistory { @@ -216,11 +202,9 @@ const BORDER: [u8; 3] = col!("#ffffff"); pub(crate) fn entry(event_loop: EventLoop<()>) { let ppem = 20.0; let ls = 20.0; - let mut text = TextArea::default(); - let mut origin = std::env::args() - .nth(1) - .and_then(|x| PathBuf::try_from(x).ok()) - .and_then(|x| x.canonicalize().ok()); + let ed = Editor::new(); + let ed = Box::leak(Box::new(ed)); + let mut fonts = dsb::Fonts::new( F::FontRef(*FONT, &[(2003265652, 550.0)]), F::instance(*FONT, *BFONT), @@ -228,148 +212,12 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { 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); let mut cells = vec![]; - std::env::args().nth(1).map(|x| { - text.insert(&std::fs::read_to_string(x).unwrap()); - text.cursor = 0; - }); - fn rooter(x: &Path) -> Option<PathBuf> { - for f in std::fs::read_dir(&x).unwrap().filter_map(Result::ok) { - if f.file_name() == "Cargo.toml" { - return Some(f.path().with_file_name("").to_path_buf()); - } - } - x.parent().and_then(rooter) - } - - let workspace = origin - .as_ref() - .and_then(|x| rooter(&x.parent().unwrap())) - .and_then(|x| x.canonicalize().ok()); - let tree = workspace.as_ref().map(|x| { - walkdir::WalkDir::new(x).into_iter().flatten().filter(|x| x.path().extension().is_some_and(_ == "rs") ).map(|x| { - x.path().to_owned() - }).collect::<Vec<_>>() - }); - let c = workspace.as_ref().zip(origin.clone()).map( - |(workspace, origin)| { - let dh = std::panic::take_hook(); - let main = std::thread::current_id(); - // let mut c = Command::new("rust-analyzer") - // .stdin(Stdio::piped()) - // .stdout(Stdio::piped()) - // .stderr(Stdio::inherit()) - // .spawn() - // .unwrap(); - let (a, b) = Connection::memory(); - std::thread::Builder::new() - .name("Rust Analyzer".into()) - .stack_size(1024 * 1024 * 8) - .spawn(move || { - let ra = std::thread::current_id(); - std::panic::set_hook(Box::new(move |info| { - // iz - if std::thread::current_id() == main { - dh(info); - } else if std::thread::current_id() == ra - || std::thread::current() - .name() - .is_some_and(|x| x.starts_with("RA")) - { - println!( - "RA panic @ {}", - info.location().unwrap() - ); - } - })); - rust_analyzer::bin::run_server(b) - }) - .unwrap(); - let (c, t2, changed) = lsp::run( - (a.sender, a.receiver), - // 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(); - (&*Box::leak(Box::new(c)), (t2), changed) - }, - ); - let (lsp, _t, mut w) = match c { - Some((a, b, c)) => (Some(a), Some(b), Some(c)), - None => (None, None, None), - }; - macro_rules! lsp { - () => { - lsp.zip(origin.as_deref()) - }; - } - let mut hovering = - Rq::<Hovr, Option<Hovr>, (usize, usize), anyhow::Error>::default(); - let mut document_highlights: Rq<Vec<DocumentHighlight>, _, _, _> = Rq::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>, - (), - RequestError<lsp_request!("textDocument/inlayHint")>, - > = default(); - let mut def = Rq::< - LocationLink, - Option<GotoDefinitionResponse>, - (usize, usize), - RequestError<lsp_request!("textDocument/definition")>, - >::default(); - // 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 chist = ClickHistory::default(); - let mut hist = Hist { - history: vec![], - redo_history: vec![], - last: text.clone(), - last_edit: Instant::now(), - changed: false, + let mut w = match &mut ed.lsp { + Some((.., c)) => c.take(), + None => None, }; - macro_rules! modify { - () => { - origin - .as_ref() - .map(|x| x.metadata().unwrap().modified().unwrap()) - }; - } - - lsp!().map(|(x, origin)| { - x.rq_semantic_tokens(&mut semantic_tokens, origin, None).unwrap() - }); - let mut mtime: Option<std::time::SystemTime> = modify!(); let app = winit_app::WinitAppBuilder::with_init( move |elwt| { @@ -377,8 +225,14 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { x.with_title("gracilaria") .with_decorations(false) .with_name("com.bendn.gracilaria", "") - .with_window_icon(Some(Icon::from_rgba(include_bytes!("../dist/icon-32").to_vec(), 32, 32).unwrap())) - + .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(); @@ -397,43 +251,6 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { ) .with_event_handler( move |(window, _context), surface, event, elwt| { - macro_rules! inlay { - () => { - lsp!().map(|(lsp, path)| inlay.request(lsp.runtime.spawn(window.redraw_after(lsp.inlay(path, &text))))); - }; - } - macro_rules! change { - () => { - lsp!().map(|(x, origin)| { - x.edit(&origin, text.rope.to_string()).unwrap(); - x.rq_semantic_tokens(&mut semantic_tokens, origin, Some(window.clone())).unwrap(); - inlay!(); - }); - }; - } - macro_rules! save { - () => {{ - let t = text.rope.to_string(); - std::fs::write(origin.as_ref().unwrap(), &t).unwrap(); - bar.last_action = "saved".into(); - lsp!().map(|(l, o)| { - let v = l.runtime.block_on(l.format(o)).unwrap(); - for v in v.coerce() { - text.apply_adjusting(&v); - } - change!(); - hist.push(&text); - l.notify::<lsp_notification!("textDocument/didSave")>( - &DidSaveTextDocumentParams { - text_document: o.tid(), - text: Some(t), - }, - ) - .unwrap(); - }); - mtime = modify!(); - }}; - } elwt.set_control_flow(ControlFlow::Wait); let (fw, fh) = dsb::dims(&FONT, ppem); let (c, r) = dsb::fit( @@ -445,83 +262,16 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { window.inner_size().height as _, ), ); - if modify!() != mtime { - mtime = modify!(); - state.consume(Action::Changed).unwrap(); + if let t = Editor::modify(ed.origin.as_deref()) + && t != ed.mtime + { + ed.mtime = t; + ed.state.consume(Action::Changed).unwrap(); window.request_redraw(); } - if let Some((l, o)) = lsp!() { - for rq in l.req_rx.try_iter() { - match rq { - LRq { method: "workspace/diagnostic/refresh", .. } => { - // let x = l.pull_diag(o.into(), diag.result.clone()); - // diag.request(l.runtime.spawn(x)); - }, - rq => - log::debug!("discarding request {rq:?}"), - } - } - let r = &l.runtime; - inlay.poll(|x, p| x.ok().or(p.1).inspect(|x| { - text.set_inlay(x); - }), r); - document_highlights.poll(|x, _| { - x.ok() - }, r); - diag.poll(|x, _|x.ok().flatten(), r); - if let CompletionState::Complete(rq)= &mut complete { - rq.poll(|f, (c,_)| { - f.ok().flatten().map(|x| {Complete {r:x,start:c,selection:0,vo:0,}}) - }, r); - }; - - if let State::Symbols(x) = &mut state { - x.poll(|x, (_, p)| x.ok().map(|r| { - let tree = tree.as_deref().unwrap().iter().map(|x| { - SymbolInformation{ name: x.file_name().unwrap().to_str().unwrap().to_string() - ,kind: SymbolKind::FILE,location: Location { - range: lsp_types::Range{end:Position::default(), start:Position::default()}, - uri: Url::from_file_path(&x).unwrap(), - - }, container_name: None,deprecated: None, - tags: None, } - }); - sym::Symbols { - tedit: p.map(_.tedit).unwrap_or_default(), - r: tree.chain(r).collect(),..default() // dont care about previous selection - } - }), &l.runtime); - } - if let State::CodeAction(x) = &mut state { - x.poll(|x, _| { - let lems: Vec<CodeAction> = x.ok()??.into_iter().map(|x| match x { - CodeActionOrCommand::CodeAction(x) => x, - _ => panic!("alas we dont like these"), - }).collect(); - if lems.is_empty() { - bar.last_action = "no code actions available".into(); - None - } else { - Some(act::CodeActions::new(lems)) - } - },&l.runtime); - } - def.poll(|x, _| - x.ok().flatten().and_then(|x| match &x { - GotoDefinitionResponse::Link([x, ..]) => Some(x.clone()), - _ => None, - }) - , &l.runtime); - semantic_tokens.poll(|x, _| x.ok(), &l.runtime); - sig_help.poll(|x, ((), y)| x.ok().flatten().map(|x| { - if let Some((old_sig, vo, max)) = y && &sig::active(&old_sig) == &sig::active(&x){ - (x, vo, max) - } else { - (x, 0, None) - } - }), &l.runtime); - hovering.poll(|x, _| x.ok().flatten(), &l.runtime); - } match event { + ed.poll(); + + match event { Event::AboutToWait => {} Event::WindowEvent { window_id, @@ -555,462 +305,36 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { ] } } - Event::WindowEvent { event: WindowEvent::Ime(Ime::Preedit(x, y)), .. } => {} - Event::WindowEvent { event: WindowEvent::Ime(Ime::Commit(x)), .. } => { - text.insert(&x); + Event::WindowEvent { + event: WindowEvent::Ime(Ime::Preedit(..)), + .. + } => {} + Event::WindowEvent { + event: WindowEvent::Ime(Ime::Commit(x)), + .. + } => { + ed.text.insert(&x); window.request_redraw(); } Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested, } if window_id == window.id() => { - {let (cx, cy) = text.cursor_visual(); - let met = FONT.metrics(&[]); - let fac = ppem / met.units_per_em as f32; - window.set_ime_cursor_area( - PhysicalPosition::new( - ((cx + text.line_number_offset()) as f64 * (fw) as f64).round(), - ((cy.saturating_sub(text.vo)) as f64 * (fh + ls * fac) as f64).floor()) - , PhysicalSize::new(fw, fh) - )}; - let Some(surface) = surface else { - eprintln!( - "RedrawRequested fired before Resumed or \ - after Suspended" - ); - return; - }; - let size = window.inner_size(); - - if size.height != 0 && size.width != 0 { - let now = Instant::now(); - if c*r!=cells.len(){ - return; - } - cells.fill(Cell { - style: Style { fg: BG, secondary_color: BG, bg: BG, flags: 0 }, - letter: None, - }); - let x = match &state { - State::Selection(x) => Some(x.clone()), - _ => None, - }; - text.line_numbers( - (c, r - 1), - [67, 76, 87], - BG, - (&mut cells, (c, r)), - (1, 0), - ); - let t_ox = text.line_number_offset() + 1; - text.c = c - t_ox; - text.r = r - 1; - // let mut text = text.clone(); - // for (_, inlay) in inlay.result.as_ref().into_iter().flatten().chunk_by(|x| x.position.line).into_iter() { - // let mut off = 0; - // for inlay in inlay { - // let label = match &inlay.label { - // InlayHintLabel::String(x) => x.clone(), - // InlayHintLabel::LabelParts(v) => { - // v.iter().map(_.value.clone()).collect::<String>() - // }, - // }; - // text.rope.insert(text.l_position(inlay.position).unwrap() + off, &label); - // off += label.chars().count(); - // } - // } - - text.write_to( - (&mut cells, (c, r)), - (t_ox, 0), - x, - |(_c, _r), text, mut x| { - if let Some(hl) = &document_highlights.result { - for DocumentHighlight { range: r, .. } in hl { - // let s = match kind { - // Some(DocumentHighlightKind::READ) => Style::UNDERLINE, - // Some(DocumentHighlightKind::WRITE) => Style::UNDERLINE, - // _ => Style::UNDERCURL, - // }; - let (x1, y1) = text.map_to_visual((r.start.character as _, r.start.line as _)); - let (x2, y2) = text.map_to_visual((r.end.character as _, r.end.line as _)); - x.get_simple((x1, y1), (x2, y2)).coerce().for_each(|x| { - x.style.bg = col!("#3a4358"); - }); - } - } - if let Some(LocationLink { - origin_selection_range: Some(r), .. - }) = def.result { _ = try { - let (x1, y1) = text.map_to_visual((r.start.character as _, r.start.line as _)); - let (x2, y2) = text.map_to_visual((r.end.character as _, r.end.line as _)); - x.get_simple((x1, y1), (x2, y2))?.iter_mut().for_each(|x| { - x.style.flags |= Style::UNDERLINE; - x.style.fg = col!("#FFD173"); - }); - } } - if let Some((lsp, p)) = lsp!() && let uri = Url::from_file_path(p).unwrap() && let Some(diag) = lsp.diagnostics.get(&uri, &lsp.diagnostics.guard()) { - #[derive(Copy, Clone, Debug)] - enum EType { - Hint, Info, Error,Warning,Related(DiagnosticSeverity), - } - let mut occupied = vec![]; - diag.iter().flat_map(|diag| { - let sev = diag.severity.unwrap_or(DiagnosticSeverity::ERROR); - let sev_ = match sev { - - DiagnosticSeverity::ERROR => EType::Error, - DiagnosticSeverity::WARNING => EType::Warning, - DiagnosticSeverity::HINT => EType::Hint, - _ => EType::Info, - }; - once((diag.range, &*diag.message, sev_)).chain(diag.related_information.iter().flatten().filter(|sp| sp.location.uri == uri).map(move |x| { - (x.location.range, &*x.message, EType::Related(sev)) - })) - }).for_each(|(mut r, m, sev)| { - if let EType::Related(x) = sev && x != DiagnosticSeverity::ERROR { - return; - } - let p = r.start.line; - while occupied.contains(&r.start.line) { - r.start.line+=1; - }; - occupied.push(r.start.line); - let f = |cell:&mut Cell| { - cell.style.bg.blend(match sev { - EType::Error => col!("#ff66662c"), - EType::Warning | EType::Hint | EType::Info => col!("#9469242c"), - EType::Related(DiagnosticSeverity::ERROR) => col!("#dfbfff26"), - EType::Related(_) => col!("#ffad6625"), - }); - }; - if r.start == r.end { - x.get(text.map_to_visual((r.start.character as _, p as _))).map(f); - } else { - x.get_range(text.map_to_visual((r.start.character as _, p as _)), - text.map_to_visual((r.end.character as usize, r.end.line as _))) - .for_each(f) - } - let l = r.start.line as usize; - let Some(x_) = text.visual_eol(l).map(_+2) else { - return; - }; - let m = m.lines().next().unwrap_or(m); - x.get_range( - (x_, l), - (x_ + m.chars().count(), l), - ).zip(m.chars()).for_each(|(x, ch)| { - let (bg, fg) = match sev { - EType::Warning => { col!("#ff942f1b", "#fa973a") }, - EType::Error => { col!("#ff942f1b", "#f26462") }, - EType::Related(DiagnosticSeverity::WARNING) => { col!("#dfbfff26", "#DFBFFF") } - _ => return - }; - x.style.bg.blend(bg); - x.style.fg = fg; - x.letter = Some(ch); - }) - }); - } - if let State::Search(re, j, _) = &state { - re.find_iter(&text.rope.to_string()) - .enumerate() - .for_each(|(i, m)| { - for x in x.get_range( - text.map_to_visual(text.xy(text.rope.byte_to_char(m.start())).unwrap()),text.map_to_visual( text.xy(text - .rope - .byte_to_char( - m.end(), - )).unwrap())) - { - x.style.bg = if i == *j { - [105, 83, 128] - } else { - [65, 62, 83] - } - } - }); - } - }, - origin.as_deref(), - semantic_tokens.result.as_deref().zip( - match lsp { - Some(lsp::Client { initialized: Some(lsp_types::InitializeResult { - capabilities: ServerCapabilities { - semantic_tokens_provider: - Some(SemanticTokensServerCapabilities::SemanticTokensOptions(SemanticTokensOptions{ - legend,.. - })),.. - }, .. - }), .. - }) => Some(legend), - _ => None, - }), - ); - - bar.write_to( - BG, - FG, - (&mut cells, (c, r)), - r - 1, - origin - .as_ref() - .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 - ); - unsafe { - dsb::render( - &cells, - (c, r), - ppem, - &mut fonts, - ls, - true, - i.as_mut(),(0,0) - ) - }; - - let place_around = |(_x, _y): (usize, usize), fonts: &mut Fonts,mut i:Image<&mut [u8], 3> ,c: &[Cell],columns:usize, ppem_:f32,ls_:f32, ox:f32, oy: f32, toy: f32| { - let met = 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)); - // std::fs::write("cells", Cell::store(c)); - - if w >= size.width as usize - || (position.1 + h >= 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.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).saturating_sub( top)) )); /* suspicious saturation */ - 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, (columns, r)); - unsafe{ dsb::render( - &c, - (columns, 0), - ppem, - fonts, - ls, - true, - i.copy(), - (left as _, top as _) - )}; - Ok((is_above, left, top, w, h)) - }; - 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_some_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() => { - let mut t = pattypan::term::Terminal::new((95, (r.saturating_sub(5)) as _), false); - for b in x.replace('\n', "\r\n").replace("⸬", ":").replace("/home/os", "").bytes(){ t.rx(b,std::fs::File::open("/dev/null").unwrap().as_fd()); } - let y_lim = t.cells.rows().position(|x| x.iter().all(_.letter.is_none())).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 { continue }; - 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) }, - &mut fonts, - i.as_mut(), - &n, x_lim, - 17.0, 0., 0., 0., 0. - ) else { continue }; - pass=false; - 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(|[(_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; - }; - - // 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), - &mut fonts, - i.as_mut(), - c, x.item.c, - 18.0, 10.0, 0., 0., 0. - ) else { return }; - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); - })); - match &state { - State::CodeAction(Rq{ result :Some(x), ..}) => 'out: { - let m = x.maxc(); - let c = x.write(m); - let (_x, _y) = text.cursor_visual(); - let _x = _x + text.line_number_offset()+1; - let Some(_y) = _y.checked_sub(text.vo) else { - println!("rah"); - break 'out }; - let Ok((is_above,left, top, w, mut h)) = place_around((_x, _y), &mut fonts, i.as_mut(), &c, m, ppem, ls, 0., 0., 0.)else { println!("ra?"); break 'out}; - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); - }, - State::Symbols(Rq { result: Some(x),..}) => 'out: { - let ws = workspace.as_deref().unwrap(); - let c = x.cells(50,ws); - // let (_x, _y) = text.cursor_visual(); - let _x = 0; - let _y = r - 1; - let Ok((is_above,left, top, w, mut h)) = place_around((_x, _y), &mut fonts, i.as_mut(), &c, 50, ppem, ls, 0., 0., 0.)else { println!("ra?"); break 'out}; - 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,),..}) => { - let c = com::s(x, 40,&filter(&text)); - if c.len() == 0 { - complete.consume(CompletionAction::NoResult).unwrap(); None - } else { Some(c) }}, - _ => None, - }; - 'out: {if let Rq{result: Some((ref x, vo, ref mut max)), .. } = sig_help { - let (sig, p) = sig::active(x); - let c = sig::sig((sig, p), 40); - let (_x, _y) = text.cursor_visual(); - let _x = _x + text.line_number_offset()+1; - let Some(_y) = _y.checked_sub(text.vo) else { break 'out }; - let Ok((is_above,left, top, w, mut h)) = place_around((_x, _y), &mut fonts, i.as_mut(), &c, 40, ppem, ls, 0., 0., 0.) else { break 'out }; - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); - let com = com.and_then(|c| { - let Ok((is_above_,left, top, w_, h_)) = place_around( - (_x, _y), - &mut fonts, - i.as_mut(), - &c, 40, ppem, ls, 0., -(h as f32), if is_above { 0.0 } else { h as f32 } - ) else { return None}; - 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 { - h+=h_; - } - Some((is_above_, left, top, w_, h_)) - }); - { - let ppem = 15.0; - let ls = 10.0; - let (fw, _) = dsb::dims(&FONT, ppem); - let cols = (w as f32 / fw).floor() as usize; - sig::doc(sig, cols) .map(|mut cells| { - *max = Some(cells.l()); - cells.vo = vo; - let cells = cells.displayable(cells.l().min(15)); - let Ok((_,left_, top_, _w_, h_)) = place_around((_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 }) else { - return - }; - i.r#box((left_.saturating_sub(1) as _, top_.saturating_sub(1) as _), w as _,h_ as _, BORDER); - }); - } - } else if let Some(c) = com { - let ppem = 20.0; - let (_x, _y) = text.cursor_visual(); - let _x = _x + text.line_number_offset()+1; - let _y = _y.wrapping_sub(text.vo); - let Ok((_,left, top, w, h)) = place_around( - (_x, _y), - &mut fonts, - i.as_mut(), - &c, 40, ppem, ls, 0., 0., 0. - ) else { break 'out; }; - i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); - } - } - 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() { - let (fw, fh) = dsb::dims(&FONT, ppem); - let cursor = - Image::<_, 4>::build(3, (fh).ceil() as u32) - .fill([0xFF, 0xCC, 0x66, 255]); - let mut draw_at = |x: usize, y:usize, w| unsafe { - let x = (x + t_ox).saturating_sub(text.ho)%c; - - if (text.vo..text.vo + r).contains(&y) { - i.as_mut().overlay_at( - w, - (x as f32 * fw).floor() as u32, - ((y - text.vo) as f32 - * (fh + ls * fac)) - .floor() - as u32, - // 4 + ((x - 1) as f32 * sz) as u32, - // (x as f32 * (ppem * 1.25)) as u32 - 20, - ); - } - }; - 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 Some((x, y)) = text.xy(stop.clone().r().end) else { continue }; - draw_at(x, y, &image); - } - if matches!( - state, - State::Default | State::Selection(_) - ) - { - draw_at(x, y, &cursor); - } - window.pre_present_notify(); - let buffer = surface.buffer_mut().unwrap(); - let x = unsafe { - std::slice::from_raw_parts_mut( - buffer.as_ptr() as *mut u8, - buffer.len() * 4, - ) - .as_chunks_unchecked_mut::<4>() - }; - fimg::overlay::copy_rgb_bgr_(i.flatten(), x); - dbg!(now.elapsed()); - buffer.present().unwrap(); - } + rnd::render( + ed, + &mut cells, + ppem, + window, + fw, + fh, + ls, + c, + r, + surface, + cursor_position, + &mut fonts, + i.as_mut(), + ); } Event::WindowEvent { @@ -1030,130 +354,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { (position.y / (fh + ls * fac) as f64).floor() as usize, ); - match state - .consume(Action::C(cursor_position)) - .unwrap() - { - Some(Do::ExtendSelectionToMouse) => { - *state.sel() = text.extend_selection_to( - text.mapped_index_at(cursor_position), - state.sel().clone(), - ); - window.request_redraw(); - } - Some(Do::StartSelection) => { - 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.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(); - } - } - let text = text.clone(); - let mut rang = None; - let z = match hover { - Mapping::Char(_, _, i) => { - TextDocumentPositionParams { position: text.to_l_position(i).unwrap(), text_document: o.tid() } - }, - Mapping::Fake(mark, relpos, abspos, _) => { - let Some(ref loc) = mark.l[relpos].1 else { - break 'out; - }; - let (x, y) = text.xy(abspos).unwrap(); - let Some(mut begin) = text.reverse_source_map(y) else { break 'out }; - let start = begin.nth(x - 1).unwrap() + 1; - let left = mark.l[..relpos].iter().rev().take_while(_.1.as_ref() == Some(loc)).count(); - let start = start + relpos - left; - let length = mark.l[relpos..].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 ctrl() { - if def.request.as_ref().is_none_or(|&(_, x)| x != cursor_position) { - let handle = cl.runtime.spawn(window.redraw_after(cl.request::<lsp_request!("textDocument/definition")>(&GotoDefinitionParams { - text_document_position_params: z.clone(), - work_done_progress_params: default(), - partial_result_params: default(), - }).unwrap().0)); - def.request = Some((DropH::new(handle), cursor_position)); - } else if def.result.as_ref().is_some_and(|em| { - let z = em.origin_selection_range.unwrap(); - (z.start.character..z.end.character).contains(&((cursor_position.0 - text.line_number_offset()-1) as _)) - }) { - def.result = None; - } - } else { - def.result = None; - } -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 { - 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(); - let span = rang.or_else(|| x.range.and_then(|range| try { - 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 _)] - })); - anyhow::Ok(Some( hov::Hovr { span, item: text::CellBuffer { c: w, vo: 0, cells: cells.into() }}.into())) -})); -hovering.request = (DropH::new(handle), cursor_position).into(); -// hovering.result = None; -// lsp!().map(|(cl, o)| { -// let window = window.clone(); -// }); -// }); - } - Some(Do::Hover) => { - def.result = None; - hovering.result = None; - window.request_redraw(); - } - None => {} - x => unreachable!("{x:?}"), - } + ed.cursor_moved(cursor_position, window.clone(), c); } Event::WindowEvent { event: @@ -1163,57 +364,7 @@ hovering.request = (DropH::new(handle), cursor_position).into(); if button == MouseButton::Left { unsafe { CLICKING = true }; } - _ = complete.consume(CompletionAction::Click).unwrap(); - match state.consume(Action::M(button)).unwrap() { - Some(Do::MoveCursor) => { - text.cursor = text.mapped_index_at(cursor_position); - if let Some((lsp, path)) = lsp!() { - sig_help.request(lsp.runtime.spawn(window.redraw_after(lsp.request_sig_help(path, text.cursor())))); - document_highlights.request(lsp.runtime.spawn(window.redraw_after(lsp.document_highlights(path, text.to_l_position(text.cursor).unwrap())))); - } - hist.last.cursor = text.cursor; - chist.push(text.cursor()); - text.setc(); - } - Some(Do::NavForward) => { - chist.forth().map(|x| { - text.cursor = text.rope.line_to_char(x.1) + x.0; - text.scroll_to_cursor(); - }); - } - Some(Do::NavBack) => { - chist.back().map(|x| { - text.cursor = text.rope.line_to_char(x.1) + x.0; - text.scroll_to_cursor(); - }); - } - Some(Do::ExtendSelectionToMouse) => { - *state.sel() = text.extend_selection_to( - text.mapped_index_at(cursor_position), - state.sel().clone(), - ); - } - Some(Do::StartSelection) => { - let x = text.mapped_index_at(cursor_position); - hist.last.cursor = x; - *state.sel() = text.extend_selection_to( - x, - text.cursor..text.cursor, - ); - } - Some(Do::GoToDefinition) => { - if let Some(LocationLink { - ref target_uri, - target_range, .. }) = def.result && let Some((l, p)) = lsp!() { - if target_uri == &p.tid().uri { - text.cursor = text.l_position(target_range.start).unwrap(); - text.scroll_to_cursor(); - } - } - } - None => {} - _ => unreachable!(), - } + ed.click(button, cursor_position, window.clone()); window.request_redraw(); } Event::WindowEvent { @@ -1233,24 +384,8 @@ hovering.request = (DropH::new(handle), cursor_position).into(); phase: _, }, } => { - let rows = if alt() { rows * 8. } else { rows * 3. }; - let (vo, max) = lower::saturating::math! { if let Some(x)= &mut hovering.result && shift() { - let n = x.item.l(); - (&mut x.item.vo, n - 15) - } else if let Some((_, ref mut vo, Some(max))) = sig_help.result && shift(){ - (vo, max - 15) - } else { - let n = text.l() - 1; (&mut text.vo, n) - }}; - if rows < 0.0 { - let rows = rows.ceil().abs() as usize; - *vo = (*vo + rows).min(max); - } else { - let rows = rows.floor() as usize; - *vo = vo.saturating_sub(rows); - } + ed.scroll(rows); window.request_redraw(); - inlay!(); } Event::WindowEvent { event: WindowEvent::ModifiersChanged(modifiers), @@ -1279,400 +414,8 @@ hovering.request = (DropH::new(handle), cursor_position).into(); ) { return; } - let mut o: Option<Do> = state - .consume(Action::K(event.logical_key.clone())) - .unwrap(); - match o { - Some(Do::Reinsert) => - o = state - .consume(Action::K( - event.logical_key.clone(), - )) - .unwrap(), - _ => {} - } - match o { - Some(Do::SpawnTerminal) => { - trm::toggle(workspace.as_deref().unwrap_or(Path::new("/home/os/"))); - } - Some(Do::MatchingBrace) => { - if let Some((l, f)) = lsp!() { - l.matching_brace(f, &mut text); - } - } - Some(Do::Symbols) => { - if let Some(lsp) = lsp { - state = State::Symbols(Rq::new(lsp.runtime.spawn(window.redraw_after(lsp.symbols("".into()))))); - } - } - Some(Do::SymbolsHandleKey) => { - if let Some(lsp) = lsp { - let State::Symbols(Rq { result :Some(x), request}) = &mut state else {unreachable!()}; - let ptedit = x.tedit.rope.clone(); - if handle2(&event.logical_key, &mut x.tedit, lsp!()).is_some() || ptedit != x.tedit.rope { - *request = Some((DropH::new(lsp.runtime.spawn(window.redraw_after(lsp.symbols(x.tedit.rope.to_string())))), ())); - // state = State::Symbols(Rq::new(lsp.runtime.spawn(lsp.symbols("".into())))); - } - } - } - Some(Do::SymbolsSelectNext) => { - let State::Symbols(Rq { result :Some(x), ..}) = &mut state else {unreachable!()}; - x.next(); - }, - Some(Do::SymbolsSelectPrev) => { - let State::Symbols(Rq { result :Some(x), ..}) = &mut state else {unreachable!()}; - x.back(); - }, - Some(Do::SymbolsSelect) - => { let State::Symbols(Rq { result :Some(x), ..}) = &mut state else {unreachable!()}; - let x = x.sel(); // TODO dedup - let _: anyhow::Result<()> = try { - let f = x.location.uri.to_file_path().map_err(|()| anyhow::anyhow!("dammit"))?.canonicalize().map_err(anyhow::Error::from)?; - origin = Some(f.clone()); - let r = text.r; - text = default(); - text.r = r; - let new = std::fs::read_to_string(f).map_err(anyhow::Error::from)?; - text.insert(&new); - text.cursor = text.l_position(x.location.range.start).ok_or(anyhow::anyhow!("dangit"))?; - text.scroll_to_cursor_centering(); - hist = Hist { - history: vec![], - redo_history: vec![], - last: text.clone(), - last_edit: Instant::now(), - changed: false, - }; - complete = CompletionState::None; - mtime = modify!(); - - lsp!().map(|(x, origin)| { - (def, semantic_tokens, inlay, sig_help, complete, hovering) = (default(), default(), default(), default(), default(), default()); - x.open(&origin,new).unwrap(); - x.rq_semantic_tokens(&mut semantic_tokens, origin, Some(window.clone())).unwrap(); - }); - state = State::Default; - bar.last_action = "open".to_string(); - }; - - }, - Some(Do::CodeAction) => { - if let Some((lsp, f)) = lsp!() { - let r = lsp.request::<lsp_request!("textDocument/codeAction")>(&CodeActionParams { - text_document: f.tid(), range: text.to_l_range(text.cursor..text.cursor).unwrap(), context: CodeActionContext { - trigger_kind: Some(CodeActionTriggerKind::INVOKED), - // diagnostics: if let Some((lsp, p)) = lsp!() && let uri = Url::from_file_path(p).unwrap() && let Some(diag) = lsp.diagnostics.get(&uri, &lsp.diagnostics.guard()) { dbg!(diag.iter().filter(|x| { - - // text.l_range(x.range).unwrap().contains(&text.cursor) - // }).cloned().collect()) } else { vec![] }, - ..default() - }, work_done_progress_params: default(), partial_result_params: default() }).unwrap(); - let mut r2 = Rq::default(); - - r2.request(lsp.runtime.spawn( - async {r.0.await} - - )); - state = State::CodeAction( - r2 - ); - } - } - Some(Do::CASelectLeft) => { - let State::CodeAction(Rq{ result: Some(c), .. }) = &mut state else { panic!()}; - c.left(); - } - Some(Do::CASelectRight) =>'out: { - let Some((lsp,f)) = lsp!() else {unreachable!()}; - let State::CodeAction(Rq{ result: Some(c), .. }) = &mut state else { panic!()}; - let Some(act) = c.right() else { break 'out }; - let act = act.clone(); - state = State::Default; - hist.last.cursor = text.cursor; - hist.test_push(&text); - let act = lsp.runtime.block_on( - lsp.request::<CodeActionResolveRequest>(&act).unwrap().0 - ).unwrap(); - let mut f_ = |edits: &[SnippetTextEdit]|{ - // let mut first = false; - for edit in edits { - text.apply_snippet_tedit(edit).unwrap(); - } - }; - match act.edit { - Some(WorkspaceEdit { - document_changes:Some(DocumentChanges::Edits(x)), - .. - }) => { - for x in x { - if x.text_document.uri!= f.tid().uri { return } - f_(&x.edits); - } - - } - Some(WorkspaceEdit { - document_changes:Some(DocumentChanges::Operations(x)), - .. - }) => { - for op in x { - match op { - DocumentChangeOperation::Edit(TextDocumentEdit { - edits, text_document,.. - }) => { - if text_document.uri!= f.tid().uri { return } - f_(&edits); - } - x => log::error!("didnt apply {x:?}"), - }; - // if text_document.uri!= f.tid().uri { continue } - // for lsp_types::OneOf::Left(x)| lsp_types::OneOf::Right(AnnotatedTextEdit { text_edit: x, .. }) in edits { - // text.apply(&x).unwrap(); - // } - } - }, - _ =>{}, - } - change!(); - hist.record(&text); - } - Some(Do::CASelectNext) => { - let State::CodeAction(Rq{ result: Some(c), .. }) = &mut state else { panic!()}; - c.down(); - } - Some(Do::CASelectPrev) => { - let State::CodeAction(Rq{ result: Some(c), .. }) = &mut state else { panic!()}; - c.up(); - } - Some(Do::Reinsert | Do::GoToDefinition | Do::NavBack | Do::NavForward) => panic!(), - Some(Do::Save) => match &origin { - Some(x) => { - state.consume(Action::Saved).unwrap(); - save!(); - } - None => { - state - .consume(Action::RequireFilename) - .unwrap(); - } - }, - Some(Do::SaveTo(x)) => { - origin = Some(PathBuf::try_from(x).unwrap()); - save!(); - } - Some(Do::Edit) => { - hist.test_push(&text); - let cb4 = text.cursor; - if let Key::Named(Enter | ArrowUp | ArrowDown | Tab) = event.logical_key && let CompletionState::Complete(..) = complete{ - } else { - handle2(&event.logical_key, &mut text, lsp!()); - } - text.scroll_to_cursor(); - inlay!(); - if cb4 != text.cursor && let CompletionState::Complete(Rq{ result: Some(c),.. })= &mut complete - && ((text.cursor < c.start) || (!is_word(text.at_())&& (text.at_() != '.' || text.at_() != ':')) ) { - complete = CompletionState::None; - } - if sig_help.running() && cb4 != text.cursor && let Some((lsp, path)) = lsp!() { - sig_help.request(lsp.runtime.spawn(window.redraw_after(lsp.request_sig_help(path, text.cursor())))); - } - if hist.record(&text) && let Some((lsp, path)) = lsp!() { - change!(); - } - lsp!().map(|(lsp, o)|{ - let window = window.clone(); - match event.logical_key.as_ref() { - Key::Character(y) - if let Some(x) = &lsp.initialized - && let Some(x) = &x.capabilities.signature_help_provider - && let Some(x) = &x.trigger_characters && x.contains(&y.to_string()) => { - sig_help.request(lsp.runtime.spawn(window.redraw_after(lsp.request_sig_help(o, text.cursor())))); - }, - _ => {} - } - match complete.consume(CompletionAction::K(event.logical_key.as_ref())).unwrap(){ - Some(CDo::Request(ctx)) => { - let h = DropH::new(lsp.runtime.spawn( - window.redraw_after(lsp.request_complete(o, text.cursor(), ctx)) - )); - let CompletionState::Complete(Rq{ request : x, result: c, }) = &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))); - } - Some(CDo::SelectNext) => { - let CompletionState::Complete(Rq{ result: Some(c), .. }) = &mut complete else { panic!()}; - c.next(&filter(&text)); - } - Some(CDo::SelectPrevious) => { - let CompletionState::Complete(Rq{ result: Some(c), .. }) = &mut complete else { panic!()}; - c.back(&filter(&text)); - } - Some(CDo::Finish(x)) => { - let sel = x.sel(&filter(&text)); - let sel = lsp.runtime.block_on(lsp.resolve(sel.clone()).unwrap()).unwrap(); - let CompletionItem { text_edit: Some(CompletionTextEdit::Edit(ed)), additional_text_edits, insert_text_format, .. } = sel.clone() else { panic!() }; - match insert_text_format { - Some(InsertTextFormat::SNIPPET) =>{ - text.apply_snippet(&ed).unwrap(); - }, - _ => { - let (s, _) = text.apply(&ed).unwrap(); - text.cursor = s + ed.new_text.chars().count(); - } - } - for additional in additional_text_edits.into_iter().flatten() { - text.apply_adjusting(&additional).unwrap(); - } - if hist.record(&text) { change!();} - sig_help = Rq::new(lsp.runtime.spawn(window.redraw_after(lsp.request_sig_help(o, text.cursor())))); - } - None => {return}, - }; - }); - - } - Some(Do::Undo) => { - hist.test_push(&text); - hist.undo(&mut text); - bar.last_action = "undid".to_string(); - change!(); - } - Some(Do::Redo) => { - hist.test_push(&text); - hist.redo(&mut text); - bar.last_action = "redid".to_string(); - change!(); - } - Some(Do::Quit) => elwt.exit(), - Some(Do::StartSelection) => { - let Key::Named(y) = event.logical_key else { - panic!() - }; - *state.sel() = text.extend_selection( - y, - text.cursor..text.cursor, - ); - } - Some(Do::UpdateSelection) => { - let Key::Named(y) = event.logical_key else { - panic!() - }; - *state.sel() = text - .extend_selection(y, state.sel().clone()); - text.scroll_to_cursor(); - inlay!(); - } - Some(Do::Insert(x, c)) => { - hist.push_if_changed(&text); - _ = text.remove(x.clone()); - text.cursor = x.start; - text.setc(); - text.insert(&c); - hist.push_if_changed(&text); - change!(); - } - Some(Do::Delete(x)) => { - hist.push_if_changed(&text); - text.cursor = x.start; - _ = text.remove(x); - hist.push_if_changed(&text); - change!(); - } - Some(Do::Copy(x)) => { - clipp::copy(text.rope.slice(x).to_string()); - } - Some(Do::Cut(x)) => { - hist.push_if_changed(&text); - clipp::copy( - text.rope.slice(x.clone()).to_string(), - ); - text.rope.remove(x.clone()); - text.cursor = x.start; - hist.push_if_changed(&text); - change!(); - } - Some(Do::Paste) => { - hist.push_if_changed(&text); - text.insert(&clipp::paste()); - hist.push_if_changed(&text); - change!(); - } - Some(Do::OpenFile(x)) => { let _ = try { - origin = Some(PathBuf::from(&x).canonicalize()?); - text = TextArea::default(); - let new = std::fs::read_to_string(x)?; - text.insert(&new); - text.cursor = 0; - hist = Hist { - history: vec![], - redo_history: vec![], - last: text.clone(), - last_edit: Instant::now(), - changed: false, - }; - complete = CompletionState::None; - mtime = modify!(); - - lsp!().map(|(x, origin)| { - (def, semantic_tokens, inlay, sig_help, complete, hovering) = (default(), default(), default(), default(), default(), default()); - x.open(&origin,new).unwrap(); - x.rq_semantic_tokens(&mut semantic_tokens, origin, Some(window.clone())).unwrap(); - }); - bar.last_action = "open".to_string(); - }; - } - Some( - Do::MoveCursor | Do::ExtendSelectionToMouse | Do::Hover, - ) => { - unreachable!() - } - Some(Do::StartSearch(x)) => { - let s = Regex::new(&x).unwrap(); - let n = s - .find_iter(&text.rope.to_string()) - .enumerate() - .count(); - s.clone() - .find_iter(&text.rope.to_string()) - .enumerate() - .find(|(_, x)| x.start() > text.cursor) - .map(|(x, m)| { - state = State::Search(s, x, n); - text.cursor = - text.rope.byte_to_char(m.end()); - text.scroll_to_cursor_centering(); - inlay!(); - }) - .unwrap_or_else(|| { - bar.last_action = "no matches".into() - }); - } - Some(Do::SearchChanged) => { - let (re, index, _) = state.search(); - let s = text.rope.to_string(); - let m = re.find_iter(&s).nth(*index).unwrap(); - text.cursor = text.rope.byte_to_char(m.end()); - text.scroll_to_cursor_centering(); - inlay!(); - } - Some(Do::Boolean( - BoolRequest::ReloadFile, - true, - )) => { - text.rope = Rope::from_str( - &std::fs::read_to_string( - origin.as_ref().unwrap(), - ) - .unwrap(), - ); - text.cursor = - text.cursor.min(text.rope.len_chars()); - mtime = modify!(); - bar.last_action = "reloaded".into(); - } - Some(Do::Boolean( - BoolRequest::ReloadFile, - false, - )) => {} - None => {} + if ed.keyboard(event, window).is_break() { + elwt.exit(); } window.request_redraw(); } @@ -1683,48 +426,8 @@ hovering.request = (DropH::new(handle), cursor_position).into(); winit_app::run_app(event_loop, app); } -fn handle2<'a>(key: &'a Key, text: &mut TextArea, l: Option<(&Client, &Path)>) -> Option<&'a str> { - use Key::*; - - match key { - Named(Space) => text.insert(" ").unwrap(), - Named(Backspace) if ctrl() => text.backspace_word(), - Named(Backspace) => text.backspace(), - Named(Home) if ctrl() => { - text.cursor = 0; - text.vo = 0; - } - Named(End) if ctrl() => { - text.cursor = text.rope.len_chars(); - text.vo = text.l().saturating_sub(text.r); - } - Named(Home) => text.home(), - Named(End) => text.end(), - Named(Tab) => text.tab(), - Named(Delete) => { - text.right(); - text.backspace() - } - Named(ArrowLeft) if ctrl() => text.word_left(), - Named(ArrowRight) if ctrl() => text.word_right(), - Named(ArrowLeft) => text.left(), - Named(ArrowRight) => text.right(), - Named(ArrowUp) => text.up(), - Named(ArrowDown) => text.down(), - Named(PageDown) => text.page_down(), - Named(PageUp) => text.page_up(), - Named(Enter) if let Some((l, p)) = l => l.enter(p, text), - 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,None); +fn handle(key: Key, mut text: TextArea) -> TextArea { + edi::handle2(&key, &mut text, None); text } pub static FONT: LazyLock<FontRef<'static>> = LazyLock::new(|| { @@ -1754,121 +457,6 @@ fn alt() -> bool { fn ctrl() -> bool { unsafe { MODIFIERS }.control_key() } -impl State { - fn sel(&mut self) -> &mut Range<usize> { - let State::Selection(x) = self else { panic!() }; - x - } - fn search(&mut self) -> (&mut Regex, &mut usize, &mut usize) { - let State::Search(x, y, z) = self else { panic!() }; - (x, y, z) - } -} - -use std::ops::Range; -impl Default for State { - fn default() -> Self { - Self::Default - } -} -rust_fsm::state_machine! { -#[derive(Debug)] -pub(crate) State => Action => Do - -Dead => K(Key => _) => Dead, -Default => { - K(Key::Character(x) if x == "s" && ctrl()) => Save [Save], - K(Key::Character(x) if x == "q" && ctrl()) => Dead [Quit], - K(Key::Character(x) if x == "v" && ctrl()) => _ [Paste], - K(Key::Character(x) if x == "z" && ctrl()) => _ [Undo], - K(Key::Character(x) if x == "y" && ctrl()) => _ [Redo], - K(Key::Character(x) if x == "f" && ctrl()) => Procure((default(), InputRequest::Search)), - K(Key::Character(x) if x == "o" && ctrl()) => Procure((default(), InputRequest::OpenFile)), - K(Key::Character(x) if x == "c" && ctrl()) => _, - K(Key::Character(x) if x == "l" && ctrl()) => _ [Symbols], - K(Key::Character(x) if x == "." && ctrl()) => _ [CodeAction], - K(Key::Character(x) if x == "0" && ctrl()) => _ [MatchingBrace], - K(Key::Character(x) if x == "`" && ctrl()) => _ [SpawnTerminal], - K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End) if shift()) => Selection(Range<usize> => 0..0) [StartSelection], - M(MouseButton::Left if shift()) => Selection(Range<usize> => 0..0) [StartSelection], - M(MouseButton::Left if ctrl()) => _ [GoToDefinition], - M(MouseButton::Left) => _ [MoveCursor], - M(MouseButton::Back) => _ [NavBack], - M(MouseButton::Forward) => _ [NavForward], - C(((usize, usize)) => .. if unsafe { CLICKING }) => Selection(0..0) [StartSelection], - Changed => RequestBoolean(BoolRequest => BoolRequest::ReloadFile), - C(_) => _ [Hover], - K(_) => _ [Edit], - M(_) => _, -}, -Symbols(Rq { result: Some(_x), request: None }) => { - K(Key::Named(Tab) if shift()) => _ [SymbolsSelectNext], - K(Key::Named(ArrowDown)) => _ [SymbolsSelectNext], - K(Key::Named(ArrowUp | Tab)) => _ [SymbolsSelectPrev], - K(Key::Named(Enter)) => _ [SymbolsSelect], - K(Key::Named(Escape)) => Default, - K(_) => _ [SymbolsHandleKey], -}, -Symbols(Rq::<Symbols, Vec<SymbolInformation>, (), RequestError<lsp_request!("workspace/symbol")>> => _rq) => { - K(Key::Named(Escape)) => Default, - C(_) => _, - M(_) => _, - K(_) => _, -}, -CodeAction(Rq { result : Some(_x), request }) => { - K(Key::Named(Tab) if shift()) => _ [CASelectPrev], - K(Key::Named(ArrowDown | Tab)) => _ [CASelectNext], - K(Key::Named(ArrowUp)) => _ [CASelectPrev], - K(Key::Named(Enter | ArrowRight)) => _ [CASelectRight], - K(Key::Named(ArrowLeft)) => _ [CASelectLeft], -}, -CodeAction(RqS<act::CodeActions, lsp_request!("textDocument/codeAction")> => rq) => { - K(Key::Named(Escape)) => Default, - C(_) => _, - M(_) => _, - K(_) => _, -}, -Selection(x if shift()) => { - K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End)) => Selection(x) [UpdateSelection], - M(MouseButton => MouseButton::Left) => Selection(x) [ExtendSelectionToMouse], -}, // note: it does in fact fall through. this syntax is not an arm, merely shorthand. -Selection(x) => { - C(_ if unsafe { CLICKING }) => _ [ExtendSelectionToMouse], - C(_) => Selection(x), - M(MouseButton => MouseButton::Left) => Default [MoveCursor], - K(Key::Named(Backspace)) => Default [Delete(Range<usize> => x)], - K(Key::Character(y) if y == "x" && ctrl()) => Default [Cut(Range<usize> => x)], - K(Key::Character(y) if y == "c" && ctrl()) => Default [Copy(Range<usize> => x)], - K(Key::Character(y)) => Default [Insert((Range<usize>, SmolStr) => (x, y))], - K(_) => Default [Edit], -}, -Save => { - RequireFilename => Procure((TextArea, InputRequest) => (default(), InputRequest::SaveFile)), - Saved => Default, -}, -Procure((_, _)) => K(Key::Named(Escape)) => Default, -Procure((t, InputRequest::Search)) => K(Key::Named(Enter)) => Default [StartSearch(String => t.rope.to_string())], -Procure((t, InputRequest::SaveFile)) => K(Key::Named(Enter)) => Default [SaveTo(String => t.rope.to_string())], -Procure((t, InputRequest::OpenFile)) => K(Key::Named(Enter)) => Default [OpenFile(String => t.rope.to_string())], -Procure((t, a)) => K(k) => Procure((handle(k, t), a)), -RequestBoolean(t) => { - K(Key::Character(x) if x == "y") => Default [Boolean((BoolRequest, bool) => (t, true))], - K(Key::Character(x) if x == "n") => Default [Boolean((t, false))], - K(Key::Named(Escape)) => Default [Boolean((t, false))], - K(_) => RequestBoolean(t), - C(_) => _, - Changed => _, - M(_) => _, -}, -Search((x, y, m)) => { - M(MouseButton::Left) => Default [MoveCursor], - C(_) => Search((x, y, m)), - K(Key::Named(Enter) if shift()) => Search((x, y.checked_sub(1).unwrap_or(m-1), m)) [SearchChanged], - K(Key::Named(Enter)) => Search((Regex, usize, usize) => (x, (y+ 1) % m, m)) [SearchChanged], - K(_) => Default [Reinsert], -} -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum InputRequest { SaveFile, @@ -1977,12 +565,3 @@ fn filter(text: &TextArea) -> String { .collect::<String>() } } -fn frunctinator( - parameter1: usize, - _parameter2: u8, - _paramter4: u16, -) -> usize { - lower::saturating::math! { parameter1 }; - - 0 -} |