diff --git a/src/main.rs b/src/main.rs index e5dd931..937854d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,18 @@ -use cosmic_text::{Attrs, Buffer, Color, FontSystem, Metrics, Shaping, SwashCache}; use std::{ - collections::HashMap, - fs::{self, File}, + fs::{self}, path::PathBuf, }; use clap::Parser; -use font_kit::loader::Loader; -use log::{debug, info}; -use logos::{Lexer, Logos}; -use raqote::{DrawOptions, DrawTarget, Point, SolidSource, Source}; +use log::info; +use raqote::DrawTarget; + +use parse::parse_the_shit_out_of_this_but_manually; + +use render::render_text; + +mod parse; +mod render; #[derive(Clone, Debug, Parser)] struct Args { @@ -41,171 +44,3 @@ fn main() { dt.write_png("out.png").unwrap(); } - -fn parse_the_shit_out_of_this_but_manually(text: &str) -> Vec { - let mut lex = Token::lexer(text); - let mut r = Vec::new(); - - loop { - match lex.next() { - Some(Ok(Token::Text(s))) => r.push(LanguageStructureThingy::Text(s)), - Some(Ok(Token::ParenOpen)) => hehe_sexpression_funy(&mut r, &mut lex), - Some(Ok(Token::ParenClose)) => todo!(), - Some(Ok(Token::String(_))) => todo!(), - Some(Ok(Token::Equals)) => todo!(), - Some(Ok(Token::Asterisk)) => todo!(), - Some(Ok(Token::Underscore)) => todo!(), - Some(Ok(Token::Backslash)) => todo!(), - Some(Ok(Token::WavyThing)) => todo!(), - Some(Ok(Token::Sparkles)) => todo!(), - Some(Ok(Token::HeadingLevelIndicator)) => todo!(), - Some(Err(_)) => panic!("mauuu~ :("), - None => break, - } - } - - r -} - -fn hehe_sexpression_funy(r: &mut Vec, lex: &mut Lexer<'_, Token>) { - if let Some(Ok(Token::Text(s))) = lex.next() { - let strs = s.trim_start().split_whitespace().collect::>(); - - let name = strs[0].to_owned(); - let mut attrs = HashMap::new(); - - if strs.len() == 1 { - } else if strs.len() == 2 && (lex.next() == Some(Ok(Token::Equals))) { - if let Some(Ok(Token::Text(next))) = lex.next() { - let _ = attrs.insert(strs[1].to_owned(), next.trim_end().to_owned()); - } - } else { - todo!() - } - - let content = if let Some(Ok(Token::String(s))) = lex.next() { - Box::new(LanguageStructureThingy::Text(s)) - } else { - todo!() - }; - - r.push(LanguageStructureThingy::Sexpression { - name, - attrs, - content, - }); - if let Some(Ok(Token::ParenClose)) = lex.next() { - return; - } - // handle other things too - todo!() - } -} - -struct HswtRenderer { - dt: DrawTarget, - font_system: FontSystem, - swash_cache: SwashCache, -} - -fn render_text(dt: &mut DrawTarget) { - // A FontSystem provides access to detected system fonts, create one per application - let mut font_system = FontSystem::new(); - - // A SwashCache stores rasterized glyphs, create one per application - let mut swash_cache = SwashCache::new(); - - // Text metrics indicate the font size and line height of a buffer - let metrics = Metrics::new(48.0, 60.0); - - // A Buffer provides shaping and layout for a UTF-8 string, create one per text widget - let mut buffer = Buffer::new(&mut font_system, metrics); - - // Borrow buffer together with the font system for more convenient method calls - let mut buffer = buffer.borrow_with(&mut font_system); - - // Set a size for the text buffer, in pixels - buffer.set_size(1920.0, 1080.0); - - // Attributes indicate what font to choose - let attrs = Attrs::new(); - - // Add some text! - buffer.set_text("Hello, Rust! 🦀\n", attrs, Shaping::Advanced); - - // Perform shaping as desired - buffer.shape_until_scroll(); - - // Inspect the output runs - for run in buffer.layout_runs() { - for glyph in run.glyphs.iter() { - println!("{:#?}", glyph); - } - } - - // Create a default text color - let text_color = Color::rgb(0xFF, 0xFF, 0xFF); - - // Draw the buffer (for performance, instead use SwashCache directly) - buffer.draw(&mut swash_cache, text_color, |x, y, w, h, color| { - let (r, g, b, a) = color.as_rgba_tuple(); - dt.fill_rect( - x as f32, - y as f32, - w as f32, - h as f32, - &Source::Solid(SolidSource::from_unpremultiplied_argb(a, r, g, b)), - &DrawOptions { - ..Default::default() - }, - ) - }); -} - -#[derive(Debug)] -enum LanguageStructureThingy { - Text(String), - Newline, - Sexpression { - name: String, - attrs: HashMap, - content: Box, - }, -} - -struct ObjectStyles { - height: Option, - width: Option, -} - -enum Size { - Absolute(u16), - Relative(f32), - Auto, -} - -#[derive(Logos, Debug, PartialEq)] -enum Token { - #[regex("[a-zA-Z\\d\\w]+", |lex| lex.slice().to_owned())] - Text(String), - #[token("(")] - ParenOpen, - #[token(")")] - ParenClose, - #[regex(r#""([^"\\]|\\["\\bnfrt]|u[a-fA-F0-9]{4})*""#, |lex| lex.slice().to_owned())] - String(String), - #[token("=")] - Equals, - #[token("*")] - Asterisk, - #[token("_")] - Underscore, - #[token("\\")] - Backslash, - #[token("~")] - WavyThing, - #[token("✨")] - Sparkles, - #[token("|| ")] - HeadingLevelIndicator, -} diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..7b3182d --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,102 @@ +use std::collections::HashMap; + +use logos::{Lexer, Logos}; + +#[derive(Logos, Debug, PartialEq)] +pub enum Token { + #[regex("[a-zA-Z\\d\\w]+", |lex| lex.slice().to_owned())] + Text(String), + #[token("(")] + ParenOpen, + #[token(")")] + ParenClose, + #[regex(r#""([^"\\]|\\["\\bnfrt]|u[a-fA-F0-9]{4})*""#, |lex| lex.slice().to_owned())] + String(String), + #[token("=")] + Equals, + #[token("*")] + Asterisk, + #[token("_")] + Underscore, + #[token("\\")] + Backslash, + #[token("~")] + WavyThing, + #[token("✨")] + Sparkles, + #[token("|| ")] + HeadingLevelIndicator, + #[token("\n")] + Newline, +} + +#[derive(Debug)] +pub enum LanguageStructureThingy { + Text(String), + Sexpression { + name: String, + attrs: HashMap, + content: Box, + }, +} + +pub fn parse_the_shit_out_of_this_but_manually(text: &str) -> Vec { + let mut lex = Token::lexer(text); + let mut r = Vec::new(); + + loop { + match lex.next() { + Some(Ok(Token::Text(s))) => r.push(LanguageStructureThingy::Text(s)), + Some(Ok(Token::Newline)) => r.push(LanguageStructureThingy::Text("\n".to_owned())), + Some(Ok(Token::ParenOpen)) => hehe_sexpression_funy(&mut r, &mut lex), + Some(Ok(Token::ParenClose)) => todo!(), + Some(Ok(Token::String(_))) => todo!(), + Some(Ok(Token::Equals)) => todo!(), + Some(Ok(Token::Asterisk)) => todo!(), + Some(Ok(Token::Underscore)) => todo!(), + Some(Ok(Token::Backslash)) => todo!(), + Some(Ok(Token::WavyThing)) => todo!(), + Some(Ok(Token::Sparkles)) => todo!(), + Some(Ok(Token::HeadingLevelIndicator)) => todo!(), + Some(Err(e)) => panic!("mauuu~ :(, e: {e:?}"), + None => break, + } + } + + r +} + +fn hehe_sexpression_funy(r: &mut Vec, lex: &mut Lexer<'_, Token>) { + if let Some(Ok(Token::Text(s))) = lex.next() { + let strs = s.trim_start().split_whitespace().collect::>(); + + let name = strs[0].to_owned(); + let mut attrs = HashMap::new(); + + if strs.len() == 1 { + } else if strs.len() == 2 && (lex.next() == Some(Ok(Token::Equals))) { + if let Some(Ok(Token::Text(next))) = lex.next() { + let _ = attrs.insert(strs[1].to_owned(), next.trim_end().to_owned()); + } + } else { + todo!() + } + + let content = if let Some(Ok(Token::String(s))) = lex.next() { + Box::new(LanguageStructureThingy::Text(s)) + } else { + todo!() + }; + + r.push(LanguageStructureThingy::Sexpression { + name, + attrs, + content, + }); + if let Some(Ok(Token::ParenClose)) = lex.next() { + return; + } + // handle other things too + todo!() + } +} diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 0000000..3689a6a --- /dev/null +++ b/src/render.rs @@ -0,0 +1,62 @@ +use cosmic_text::{Attrs, Buffer, Color, FontSystem, Metrics, Shaping, SwashCache}; +use raqote::{DrawOptions, DrawTarget, SolidSource, Source}; + +struct HswtRenderer { + dt: DrawTarget, + font_system: FontSystem, + swash_cache: SwashCache, +} + +pub fn render_text(dt: &mut DrawTarget) { + // A FontSystem provides access to detected system fonts, create one per application + let mut font_system = FontSystem::new(); + + // A SwashCache stores rasterized glyphs, create one per application + let mut swash_cache = SwashCache::new(); + + // Text metrics indicate the font size and line height of a buffer + let metrics = Metrics::new(48.0, 60.0); + + // A Buffer provides shaping and layout for a UTF-8 string, create one per text widget + let mut buffer = Buffer::new(&mut font_system, metrics); + + // Borrow buffer together with the font system for more convenient method calls + let mut buffer = buffer.borrow_with(&mut font_system); + + // Set a size for the text buffer, in pixels + buffer.set_size(1920.0, 1080.0); + + // Attributes indicate what font to choose + let attrs = Attrs::new(); + + // Add some text! + buffer.set_text("Hello, Rust! 🦀\n", attrs, Shaping::Advanced); + + // Perform shaping as desired + buffer.shape_until_scroll(); + + // Inspect the output runs + for run in buffer.layout_runs() { + for glyph in run.glyphs.iter() { + println!("{:#?}", glyph); + } + } + + // Create a default text color + let text_color = Color::rgb(0xFF, 0xFF, 0xFF); + + // Draw the buffer (for performance, instead use SwashCache directly) + buffer.draw(&mut swash_cache, text_color, |x, y, w, h, color| { + let (r, g, b, a) = color.as_rgba_tuple(); + dt.fill_rect( + x as f32, + y as f32, + w as f32, + h as f32, + &Source::Solid(SolidSource::from_unpremultiplied_argb(a, r, g, b)), + &DrawOptions { + ..Default::default() + }, + ) + }); +}