A simple CPU rendered GUI IDE experience.
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/hov.rs | 403 | ||||
| -rw-r--r-- | src/lsp.rs | 12 | ||||
| -rw-r--r-- | src/main.rs | 59 | ||||
| -rw-r--r-- | src/text.rs | 356 | ||||
| -rw-r--r-- | src/winit_app.rs | 10 |
6 files changed, 685 insertions, 158 deletions
@@ -49,6 +49,9 @@ arc-swap = "1.7.1" tokio = { version = "1.47.1", features = ["rt-multi-thread"] } regex-cursor = "0.1.5" papaya = "0.2.3" +minimad = { git = "https://github.com/Canop/minimad", branch = "keep-code-fence", version = "0.13.1" } +markdown = "1.0.0" +itertools = "0.14.0" [build-dependencies] cc = "*" diff --git a/src/hov.rs b/src/hov.rs new file mode 100644 index 0000000..869ff75 --- /dev/null +++ b/src/hov.rs @@ -0,0 +1,403 @@ +use std::iter::{once, repeat}; +use std::pin::pin; +use std::time::Instant; +use std::vec::Vec; + +use dsb::cell::Style; +use dsb::{Cell, F}; +use fimg::Image; +use itertools::Itertools; +use minimad::*; +use ropey::Rope; + +use crate::{BG, FG, M, text}; +fn f(x: &Compound) -> u8 { + let mut s = 0; + if x.bold { + s |= Style::BOLD; + } + if x.italic { + s |= Style::ITALIC; + } + if x.strikeout { + s |= Style::STRIKETHROUGH + } + s +} +fn markdown(c: usize, x: &str) -> Vec<Cell> { + let mut cells = vec![]; + // println!( + // "{:#?}", + // markdown::to_mdast( + // include_str!("../vec.md"), + // &markdown::ParseOptions::default() + // ) + // .unwrap() + // ); + use Default::default; + // std::fs::write( + // "vec.ast", + // format!( + // "{:#?}", + // minimad::parse_text( + // include_str!("../vec.md"), + // Options { keep_code_fences: true, ..default() }, + // ) + // .lines + // ), + // ) + // .unwrap(); + const D: Cell = Cell { + letter: None, + style: Style { bg: BG, color: FG, flags: 0 }, + }; + let mut l = minimad::parse_text( + x, + Options { keep_code_fences: true, ..default() }, + ) + .lines + .into_iter() + .peekable(); + 'l: while let Some(line) = l.next() { + match line { + minimad::Line::Normal(Composite { style, compounds }) => { + let mut compounded = l + .by_ref() + .peeking_take_while(|x| matches!(x, Line::Normal(Composite{style, compounds}) if !matches!(style, CompositeStyle::Header(_)))) + .flat_map(|x| match x { + Line::Normal(Composite { style, compounds }) => + compounds.into_iter().flat_map(move |x| { + x.as_str().chars().zip(repeat(f(&x)).map( + move |flags| match style { + CompositeStyle::Paragraph => + Style { + color: FG, + bg: BG, + flags, + }, + CompositeStyle::Header(x) => + Style { + color: [255; 3], + bg: BG, + flags: flags | Style::BOLD, + }, + CompositeStyle::ListItem(x) => + Style { + color: FG, + bg: BG, + flags, + }, + CompositeStyle::Code => Style { + color: [244,244,244], + bg: [5,5,5], + flags, + }, + CompositeStyle::Quote => Style { + color: [128; 3], + bg: [0; 3], + flags, + }, + }, + )) + }).chain(once((' ', Style { color: FG, bg: BG, flags : 0 }))), + _ => panic!(), + }) + .chunk_by(|x| x.0.is_whitespace()); + let mut compounded = compounded.into_iter(); + let mut out = vec![]; + + // let mut compounds = compounds.iter(); + while let Some((x, word)) = compounded.next() { + if x { + continue; + } + if out.len() > c { + panic!() + } + let word = word.collect::<Vec<_>>(); + if word.len() > c { + let mut w = word.iter().map(|&(x, style)| Cell { + letter: Some(x), + style, + }); + out.extend(w); + cells.extend( + out.drain(..out.len() - out.len() % c), + ); + // 'out: loop { + // while out.len() != c { + // let Some(x) = w.next() else { + // break 'out; + // }; + // out.push(x); + // } + // cells.extend(&out); + // out.clear(); + // } + continue; + // cells.extend(&out); + // out.clear(); + // cells.extend( + // w.by_ref() + // .take(c.saturating_sub(out.len() + 1)), + // ); + // cells.push(Cell::basic('-')); + // cells.extend(w); + } + + if out.len() + word.len() > c { + assert_eq!(cells.len() % c, 0); + cells.extend(&out); + cells.extend(std::iter::repeat_n( + D, + c.saturating_sub(out.len()), + )); + dbg!(out.len(), c); + out.clear(); + assert_eq!(cells.len() % c, 0); + } + + out.extend(word.iter().map(|&(x, style)| Cell { + letter: Some(x), + style, + })); + if out.len() != c { + out.push(D); + } else { + cells.extend(&out); + out.clear(); + } + dbg!(out.len()); + + // } + } + // if out.len() > c { + // panic!(); + // } + // if out.len() + next.char_length() > c { + // cells.extend(&out); + // cells.extend(std::iter::repeat_n( + // Cell::default(), + // c.saturating_sub(out.len()), + // )); + // out.clear(); + // assert_eq!(cells.len() % c, 0); + // } + // out.extend( + // next.as_str() + // .chars() + // .map(|x| Cell { letter: Some(x), style }), + // ); + // } + if !out.is_empty() { + assert!(out.len() <= c, "{} < c", out.len()); + cells.extend(&out); + cells.extend(std::iter::repeat_n( + D, + c.saturating_sub(out.len()), + )); + assert_eq!(cells.len() % c, 0); + } + continue 'l; + } + minimad::Line::TableRow(table_row) => todo!(), + minimad::Line::TableRule(table_rule) => todo!(), + minimad::Line::HorizontalRule => vec![Cell::basic('-')], + minimad::Line::CodeFence(Composite { + compounds: [Compound { src: lang, .. }], + .. + }) => { + let mut r = Rope::new(); + while let Some(x) = l.next() { + match x { + Line::CodeFence(Composite { + compounds: [], + .. + }) => { + break; + } + Line::Normal(Composite { + compounds: [Compound { src, .. }], + .. + }) => { + r.insert(r.len_chars(), src); + r.insert_char(r.len_chars(), '\n'); + } + _ => {} + } + } + let mut cell = vec![D; c * r.len_lines()]; + + for (l, y) in r.lines().zip(0..) { + for (e, x) in l.chars().take(c).zip(0..) { + if e != '\n' { + cell[y * c + x].letter = Some(e); + } + } + } + for ((x1, y1), (x2, y2), s, txt) in + std::iter::from_coroutine(pin!(text::hl( + text::LOADER.language_for_name(lang).unwrap_or( + text::LOADER + .language_for_name("rust") + .unwrap() + ), + &r, + .., + c, + ))) + { + cell.get_mut(y1 * c + x1..y2 * c + x2).map(|x| { + x.iter_mut().zip(txt.chars()).for_each(|(x, c)| { + x.style |= s; + x.letter = Some(c); + }) + }); + } + cells.extend(cell); + assert_eq!(cells.len() % c, 0); + continue 'l; + } + _ => panic!(), + }; + // if out.len() > c { + // out.drain(c - 1..); + // out.push(Cell::basic('…')); + // } else { + // out.extend(std::iter::repeat_n( + // Cell::default(), + // c.saturating_sub(out.len()), + // )); + // } + // assert_eq!(out.len(), c); + // cells.extend(out); + } + assert_eq!(cells.len() % c, 0); + cells +} + +#[test] +fn t() { + let ppem = 18.0; + let lh = 10.0; + let (w, h) = (800, 8000); + let (c, r) = dsb::fit(&crate::FONT, ppem, lh, (w, h)); + std::fs::write( + "mdast2", + format!( + "{:#?}", + markdown::to_mdast( + include_str!("../vec.md"), + &markdown::ParseOptions::gfm() + ) + .unwrap() + ), + ); + let mut cells = markdown(c, include_str!("../vec.md")); + // use Default::default; + // for line in dbg!(minimad::parse_text( + // include_str!("../vec.md"), + // Options { keep_code_fences: true, ..default() }, + // )) + // .lines + // { + // fn f(x: &Compound) -> u8 { + // let mut s = 0; + // if x.bold { + // s |= Style::BOLD; + // } + // if x.italic { + // s |= Style::ITALIC; + // } + // if x.strikeout { + // s |= Style::STRIKETHROUGH + // } + // s + // } + // let mut out = match line { + // minimad::Line::Normal(Composite { style, compounds }) => + // compounds + // .iter() + // .flat_map(|c| { + // c.as_str().chars().map(move |x| { + // let flags = f(&c); + // let style = match style { + // CompositeStyle::Paragraph => Style { + // color: [128; 3], + // bg: [0; 3], + // flags, + // }, + // CompositeStyle::Header(x) => Style { + // color: [255; 3], + // bg: [0; 3], + // flags: flags | Style::BOLD, + // }, + // CompositeStyle::ListItem(x) => Style { + // color: [128; 3], + // bg: [0; 3], + // flags, + // }, + // CompositeStyle::Code => Style { + // color: [100; 3], + // bg: [0; 3], + // flags, + // }, + // CompositeStyle::Quote => Style { + // color: [128; 3], + // bg: [0; 3], + // flags, + // }, + // }; + // Cell { letter: Some(x), style } + // }) + // }) + // .collect::<Vec<_>>(), + // minimad::Line::TableRow(table_row) => todo!(), + // minimad::Line::TableRule(table_rule) => todo!(), + // minimad::Line::HorizontalRule => vec![Cell::basic('-')], + // minimad::Line::CodeFence(composite) => { + // vec![] + // } + // }; + // if out.len() > c { + // out.drain(c - 1..); + // out.push(Cell::basic('…')); + // } else { + // out.extend(std::iter::repeat_n( + // Cell::default(), + // c - out.len(), + // )); + // } + // assert_eq!(out.len(), c); + // cells.extend(out); + // } + dbg!(cells.len() / c); + // let (fw, fh) = dsb::dims(&FONT, ppem); + dbg!(w, h); + dbg!(c, r); + // panic!(); + + let mut fonts = dsb::Fonts::new( + F::FontRef(*crate::FONT, &[(2003265652, 550.0)]), + F::instance(*crate::FONT, *crate::BFONT), + F::FontRef(*crate::IFONT, &[(2003265652, 550.0)]), + F::instance(*crate::IFONT, *crate::BIFONT), + ); + + let now = Instant::now(); + let mut x = Image::build(w as _, h as _).fill(BG); + unsafe { + dsb::render( + &cells, + (c, r), + ppem, + BG, + &mut fonts, + lh, + true, + x.as_mut(), + ) + }; + println!("{:?}", now.elapsed()); + x.as_ref().save("x"); +} @@ -198,6 +198,13 @@ pub fn run( ..default() }), text_document: Some(TextDocumentClientCapabilities { + hover: Some(HoverClientCapabilities { + dynamic_registration: None, + content_format: Some(vec![ + MarkupKind::PlainText, + MarkupKind::Markdown, + ]), + }), semantic_tokens: Some(SemanticTokensClientCapabilities { dynamic_registration: Some(false), requests: SemanticTokensClientCapabilitiesRequests { @@ -303,7 +310,7 @@ pub fn run( recv(req_rx) -> x => match x { Ok((x, y)) => { debug!("received request {x}"); - assert!(map.insert(x, y).is_none()); + assert!(map.insert(x, (y, Instant::now())).is_none()); } Err(RecvError) => return, }, @@ -326,7 +333,8 @@ pub fn run( } } Ok(Message::Response(x)) => { - if let Some(s) = map.remove(&x.id.i32()) { + if let Some((s, took)) = map.remove(&x.id.i32()) { + debug!("request {} took {:?}", x.id, took.elapsed()); match s.send(x) { Ok(()) => {} Err(e) => { diff --git a/src/main.rs b/src/main.rs index 35e9109..e0f5289 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ // this looks pretty good though #![feature(tuple_trait, unboxed_closures, fn_traits)] #![feature( + stmt_expr_attributes, mpmc_channel, const_cmp, + // generator_trait, + gen_blocks, const_default, + coroutines,iter_from_coroutine,coroutine_trait, cell_get_cloned, import_trait_associated_functions, if_let_guard, @@ -16,6 +20,7 @@ #![allow(incomplete_features, redundant_semicolons)] use std::convert::identity; use std::io::BufReader; +use std::mem::forget; use std::num::NonZeroU32; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -30,11 +35,11 @@ use diff_match_patch_rs::PatchInput; use dsb::cell::Style; use dsb::{Cell, F}; use fimg::Image; +use lsp_types::request::HoverRequest; use lsp_types::{ - SemanticTokensOptions, SemanticTokensServerCapabilities, - ServerCapabilities, TextDocumentIdentifier, - TextDocumentPositionParams, WorkspaceFolder, + Hover, HoverParams, Position, SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceFolder }; +use minimad::{Composite, CompositeStyle}; use parking_lot::RwLock; use regex::Regex; use ropey::Rope; @@ -55,6 +60,7 @@ mod bar; mod lsp; mod text; mod winit_app; +mod hov; fn main() { env_logger::init(); // lsp::x(); @@ -503,6 +509,36 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { text.cursor = x; *state.sel() = x..x; } + Some(Do::Hover) => { + let 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(()) + }) + }); + + } None => {} x => unreachable!("{x:?}"), } @@ -516,7 +552,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { if button == MouseButton::Left { unsafe { CLICKING = true }; } - match dbg!(state.consume(Action::M(button)).unwrap() ){ + match state.consume(Action::M(button)).unwrap() { Some(Do::MoveCursor) => { text.cursor = text.index_at(cursor_position); text.setc(); @@ -703,7 +739,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { }; } Some( - Do::MoveCursor | Do::ExtendSelectionToMouse, + Do::MoveCursor | Do::ExtendSelectionToMouse | Do::Hover, ) => { unreachable!() } @@ -860,17 +896,18 @@ 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()) => Default [Paste], - K(Key::Character(x) if x == "z" && ctrl()) => Default [Undo], - K(Key::Character(x) if x == "y" && ctrl()) => Default [Redo], + 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()) => Default, + K(Key::Character(x) if x == "c" && ctrl()) => _, K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End) if shift()) => Selection(Range<usize> => 0..0) [StartSelection], M(MouseButton => MouseButton::Left if shift()) => Selection(Range<usize> => 0..0) [StartSelection], - M(MouseButton => MouseButton::Left) => Default [MoveCursor], + 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(_) => _, K(_) => _ [Edit], M(_) => _, @@ -880,7 +917,7 @@ Selection(x if shift()) => { 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 }) => Selection(x) [ExtendSelectionToMouse], + C(_ if unsafe { CLICKING }) => _ [ExtendSelectionToMouse], C(_) => Selection(x), M(MouseButton => MouseButton::Left) => Default [MoveCursor], K(Key::Named(Backspace)) => Default [Delete(Range<usize> => x)], diff --git a/src/text.rs b/src/text.rs index 7b18be5..f35539f 100644 --- a/src/text.rs +++ b/src/text.rs @@ -1,22 +1,24 @@ use std::cmp::min; use std::fmt::{Debug, Display}; -use std::ops::{Deref, Not as _, Range}; +use std::ops::{Deref, Not as _, Range, RangeBounds}; use std::path::Path; +use std::pin::{Pin, pin}; use std::sync::{Arc, LazyLock}; +use std::vec::Vec; use atools::prelude::*; use diff_match_patch_rs::{DiffMatchPatch, Patches}; use dsb::Cell; use dsb::cell::Style; use helix_core::Syntax; -use helix_core::syntax::{HighlightEvent, Loader}; +use helix_core::syntax::{HighlightEvent, Loader, reconfigure_highlights}; use implicit_fn::implicit_fn; use log::error; use lsp_types::{ SemanticToken, SemanticTokensLegend, SemanticTokensServerCapabilities, }; use ropey::{Rope, RopeSlice}; -use tree_house::fixtures; +use tree_house::{Language, fixtures}; use winit::keyboard::{NamedKey, SmolStr}; use crate::MODIFIERS; @@ -32,11 +34,12 @@ macro_rules! theme { ),+]; }; } -theme! { 15 +theme! { 16 "attribute" b"#ffd173", "comment" b"#5c6773" Style::ITALIC, "constant" b"#DFBFFF", "function" b"#FFD173" Style::ITALIC, + "function.macro" b"#fbc351", "variable.builtin" b"#FFAD66", "keyword" b"#FFAD66" Style::ITALIC | Style::BOLD, "number" b"#dfbfff", @@ -82,7 +85,7 @@ mod semantic { "enum" b"#73b9ff" Style::ITALIC | Style::BOLD, "builtinType" b"#73d0ff" Style::ITALIC, // "type" b"#73d0ff" Style::ITALIC | Style::BOLD, - "typeAlias" b"#5ce6d8" Style::ITALIC | Style::BOLD, + "typeAlias" b"#69caed" Style::ITALIC | Style::BOLD, "struct" b"#73d0ff" Style::ITALIC | Style::BOLD, // "variable" b"#cccac2", // "angle" b"#cccac2", @@ -201,7 +204,6 @@ pub struct TextArea { } impl Debug for TextArea { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - String::new(); f.debug_struct("TextArea") .field("rope", &self.rope) .field("cursor", &self.cursor) @@ -272,8 +274,12 @@ impl TextArea { } pub fn cursor(&self) -> (usize, usize) { - let y = self.rope.char_to_line(self.cursor); - let x = self.cursor - self.rope.line_to_char(y); + self.xy(self.cursor) + } + + pub fn xy(&self, c: usize) -> (usize, usize) { + let y = self.rope.char_to_line(c); + let x = c - self.rope.line_to_char(y); (x, y) } @@ -506,68 +512,56 @@ impl TextArea { let language = path .and_then(|x| LOADER.language_for_filename(x)) .unwrap_or_else(|| LOADER.language_for_name("rust").unwrap()); - let syntax = - Syntax::new(self.rope.slice(..), language, &LOADER).unwrap(); - - // println!( - // "{}", - // tree_house::fixtures::highlighter_fixture( - // "hmm", - // &*LOADER, - // |y| NAMES[y.idx()].to_string(), - // &syntax.inner, - // self.rope.slice(..), - // .., - // ) - // ); + let s = self.rope.line_to_char(self.vo); let e = self .rope - .try_line_to_char(self.vo + self.r + 20) + .try_line_to_char(self.vo + self.r * self.c) .unwrap_or(self.rope.len_chars()); - let mut h = syntax.highlighter( - self.rope.slice(..), - &LOADER, - s as u32..e as u32, - ); - let mut at = 0; - let (c, r) = (self.c, self.r); + for ((x1, y1), (x2, y2), s, _) in std::iter::from_coroutine(pin!( + hl(language, &self.rope, s as u32..e as u32, self.c) + )) { + cell.get_mut(y1 * self.c + x1..y2 * self.c + x2) + .map(|x| x.iter_mut().for_each(|x| x.style |= s)); + } - let mut highlight_stack = Vec::with_capacity(8); - loop { - let (e, new_highlights) = h.advance(); - if e == HighlightEvent::Refresh { - highlight_stack.clear(); - } - highlight_stack.extend(new_highlights); + // let mut highlight_stack = Vec::with_capacity(8); + // loop { + // let (e, new_highlights) = h.advance(); + // if e == HighlightEvent::Refresh { + // highlight_stack.clear(); + // } + // highlight_stack.extend(new_highlights); - let end = h.next_event_offset() as _; - if end == 4294967295 { - break; - } - for &h in &highlight_stack { - let y1 = self.rope.byte_to_line(at); - let y2 = self.rope.byte_to_line(end); - let x1 = min( - self.rope.byte_to_char(at) - - self.rope.line_to_char(y1), - c, - ); - let x2 = min( - self.rope.byte_to_char(end) - - self.rope.line_to_char(y2), - c, - ); - - cell.get_mut(y1 * c + x1..y2 * c + x2).map(|x| { - x.iter_mut().for_each(|x| { - x.style.flags |= STYLES[h.idx()]; - x.style.color = COLORS[h.idx()]; - }) - }); - } - at = end; - } + // let end = h.next_event_offset() as _; + // if end == 4294967295 { + // break; + // } + // for &h in &highlight_stack { + // let y1 = self.rope.byte_to_line(at); + // let y2 = self.rope.byte_to_line(end); + // let x1 = min( + // self.rope.byte_to_char(at) + // - self.rope.line_to_char(y1), + // self.c, + // ); + // let x2 = min( + // self.rope.byte_to_char(end) + // - self.rope.line_to_char(y2), + // self.c, + // ); + + // cell.get_mut(y1 * self.c + x1..y2 * self.c + x2).map( + // |x| { + // x.iter_mut().for_each(|x| { + // x.style.flags |= STYLES[h.idx()]; + // x.style.color = COLORS[h.idx()]; + // }) + // }, + // ); + // } + // at = end; + // } } pub fn slice<'c>( @@ -611,7 +605,10 @@ impl TextArea { } } } - + // let tokens = None::<( + // arc_swap::Guard<Arc<Box<[SemanticToken]>>>, + // &SemanticTokensLegend, + // )>; if let Some((t, leg)) = tokens && t.len() > 0 { @@ -862,75 +859,89 @@ impl TextArea { fn is_word(r: char) -> bool { matches!(r, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_') } -static LOADER: LazyLock<Loader> = LazyLock::new(|| { +pub static LOADER: LazyLock<Loader> = LazyLock::new(|| { let x = helix_core::config::default_lang_loader(); x.set_scopes(NAMES.map(|x| x.to_string()).to_vec()); + + // x.languages().for_each(|(_, x)| { + // x.syntax_config(&LOADER).map(|x| { + // x.configure(|x| { + // // let x = set.entry(x.to_string()).or_insert_with(|| { + // // n += 1; + // // n + // // }); + // // dbg!(x); + // NAMES + // .iter() + // .position(|&y| y == x) + // .map(|x| x as u32) + // .map(helix_core::syntax::Highlight::new) + // // Some(helix_core::syntax::Highlight::new(*x)) + // }) + // }); + // }); x }); -#[test] +// #[test] pub fn man() { let query_str = r#" (line_comment)+ @quantified_nodes ((line_comment)+) @quantified_nodes_grouped ((line_comment) (line_comment)) @multiple_nodes_grouped "#; - let source = Rope::from_str( - r#" - - pub fn extend_selection_to( - &mut self, - to: usize, - r: std::ops::Range<usize>, - ) -> std::ops::Range<usize> { - if [r.start, r.end].contains(&to) { - return r; - } - let r = if self.cursor == r.start { - if to < r.start { - to..r.end - } else if to > r.end { - r.end..to - } else { - to..r.end - } - } else if self.cursor == r.end { - if to > r.end { - r.start..to - } else if to < r.start { - to..r.start - } else { - r.start..to - } - } else { - panic!() - }; - assert!(r.start < r.end); - self.cursor = to; - self.setc(); - r - } -"#, - ); - let language = LOADER.language_for_name("rust").unwrap(); + let source = Rope::from_str(r#"assert_eq!(0, Some(0));"#); + // dbg!(source.slice(70..)); + // let mut set = std::collections::HashMap::new(); let mut n = 0; - let mut set = std::collections::HashMap::new(); - LOADER.languages().for_each(|(_, x)| { - x.syntax_config(&LOADER).map(|x| { - x.configure(|x| { - let x = set.entry(x.to_string()).or_insert_with(|| { - n += 1; - n - }); - // dbg!(x); - // NAMES - // .iter() - // .position(|&y| y == x) - // .map(|x| x as u32) - // .map(helix_core::syntax::Highlight::new) - Some(helix_core::syntax::Highlight::new(*x)) - }) - }); - }); + let loader = &*LOADER; + // loader.set_scopes(nam.map(|x| x.to_string()).to_vec()); + let language = loader.language_for_name("rust").unwrap(); + // for lang in [ + // "rust-format-args", + // "rust-format-args-macro", + // "rust", + // "markdown-rustdoc", + // "comment", + // "regex", + // ] { + // let c = LOADER + // .language(LOADER.language_for_name(lang).unwrap()) + // .syntax_config(&LOADER) + // .unwrap(); + // reconfigure_highlights(c, &NAMES.map(|x| x.to_string())); + // // c.configure(|x| { + // // // NAMES + // // // .iter() + // // // .position(|&y| y == x) + // // // .map(|x| x as u32) + // // // .map(helix_core::syntax::Highlight::new) + // // let x = set.entry(x.to_string()).or_insert_with(|| { + // // n += 1; + // // n + + // // }); + // // dbg!(*x); + // // Some(helix_core::syntax::Highlight::new(*x)) + // // }) + // } + // let mut set = std::collections::HashMap::new(); + // LOADER.languages().for_each(|(_, x)| { + // x.syntax_config(&LOADER).map(|x| { + // x.configure(|x| { + // // let x = set.entry(x.to_string()).or_insert_with(|| { + // // n += 1; + // // n + // // }); + // // dbg!(x); + // NAMES + // .iter() + // .position(|&y| y == x) + // .map(|x| x as u32) + // .map(helix_core::syntax::Highlight::new) + // // Some(helix_core::syntax::Highlight::new(*x)) + // }) + // }); + // }); // let c = LOADER.languages().next().unwrap().1; // let grammar = LOADER.get_config(language).unwrap().grammar; // let query = Query::new(grammar, query_str, |_, _| Ok(())).unwrap(); @@ -940,24 +951,24 @@ pub fn man() { // &NAMES.map(|x| x.to_string()), // ); - let syntax = Syntax::new(source.slice(..), language, &LOADER).unwrap(); + let syntax = Syntax::new(source.slice(..), language, &loader).unwrap(); let mut h = syntax.highlighter( source.slice(..), - &LOADER, + &loader, 0..source.len_chars() as u32, ); println!( "{}", tree_house::fixtures::highlighter_fixture( "hmm", - &*LOADER, - |y| set - .iter() - .find(|x| x.1 == &y.get()) - .unwrap() - .0 - .to_string(), - // |y| NAMES[y.idx()].to_string(), + &loader, + // |y| set + // .iter() + // .find(|x| x.1 == &y.get()) + // .unwrap() + // .0 + // .to_string(), + |y| NAMES[y.idx()].to_string(), &syntax.inner, source.slice(..), .., @@ -970,13 +981,13 @@ pub fn man() { // dbg!(hl.map(|x| NAMES[x.idx()]).collect::<Vec<_>>(), e); dbg!( h.active_highlights() - .map(|y| set - .iter() - .find(|x| x.1 == &y.get()) - .unwrap() - .0 - .to_string()) - // .map(|x| NAMES[x.idx()]) + // .map(|y| set + // .iter() + // .find(|x| x.1 == &y.get()) + // .unwrap() + // .0 + // .to_string()) + .map(|x| NAMES[x.idx()]) .collect::<Vec<_>>() ); // panic!() @@ -1002,3 +1013,68 @@ pub fn man() { // test("quantified_nodes", 1..37); panic!() } + +pub fn hl( + lang: Language, + text: &'_ Rope, + r: impl RangeBounds<u32>, + c: usize, +) -> impl std::ops::Coroutine< + Yield = ((usize, usize), (usize, usize), (u8, [u8; 3]), RopeSlice<'_>), + Return = (), +> { + // println!( + // "{}", + // tree_house::fixtures::highlighter_fixture( + // "hmm", + // &*LOADER, + // |y| NAMES[y.idx()].to_string(), + // &syntax.inner, + // self.rope.slice(..), + // .., + // ) + // ); + #[coroutine] + static move || { + println!("`\n{text}\n`"); + let syntax = Syntax::new(text.slice(..), lang, &LOADER).unwrap(); + let mut h = syntax.highlighter(text.slice(..), &LOADER, r); + let mut at = 0; + + let mut highlight_stack = Vec::with_capacity(8); + loop { + let (e, new_highlights) = h.advance(); + if e == HighlightEvent::Refresh { + highlight_stack.clear(); + } + highlight_stack.extend(new_highlights); + + let end = h.next_event_offset() as _; + if end == 4294967295 { + break; + } + for &h in &highlight_stack { + let y1 = text.byte_to_line(at); + let y2 = text.byte_to_line(end); + let x1 = + min(text.byte_to_char(at) - text.line_to_char(y1), c); + let x2 = + min(text.byte_to_char(end) - text.line_to_char(y2), c); + + yield ( + (x1, y1), + (x2, y2), + (STYLES[h.idx()], COLORS[h.idx()]), + (text.byte_slice(at..end)), + ) + } + at = end; + } + } + // }; + // std::iter::from_fn(move || { + // // + // use std::ops::Coroutine; + // Some(Pin::new(&mut x).resume(())) + // }) +} diff --git a/src/winit_app.rs b/src/winit_app.rs index 2d8c528..18f7258 100644 --- a/src/winit_app.rs +++ b/src/winit_app.rs @@ -39,19 +39,19 @@ pub(crate) fn make_window( /// Easily constructable winit application. pub(crate) struct WinitApp<T, S, Init, InitSurface, Handler> { /// Closure to initialize `state`. - init: Init, + pub init: Init, /// Closure to initialize `surface_state`. - init_surface: InitSurface, + pub init_surface: InitSurface, /// Closure to run on window events. - event: Handler, + pub event: Handler, /// Contained state. - state: Option<T>, + pub state: Option<T>, /// Contained surface state. - surface_state: Option<S>, + pub surface_state: Option<S>, } /// Builder that makes it so we don't have to name `T`. |