From 5d28a2e7078399c56e5f2fff2246839059d4b5ef Mon Sep 17 00:00:00 2001 From: jutty Date: Tue, 16 Dec 2025 19:01:20 -0300 Subject: [PATCH] Make default element generic --- src/handlers/graph.rs | 3 +- src/syntax/content.rs | 58 ++++++++++-------------- src/syntax/content/elements.rs | 5 +- src/syntax/content/elements/paragraph.rs | 2 +- src/syntax/content/parser.rs | 27 +++++------ src/syntax/content/units.rs | 54 ++++++++++++++++++++++ 6 files changed, 94 insertions(+), 55 deletions(-) create mode 100644 src/syntax/content/units.rs diff --git a/src/handlers/graph.rs b/src/handlers/graph.rs index 4c8e39f..e69adb3 100644 --- a/src/handlers/graph.rs +++ b/src/handlers/graph.rs @@ -16,8 +16,7 @@ pub async fn node(Path(id): Path) -> Response { context.insert("connections", &node.connections.clone()); context.insert("incoming", &graph.incoming.get(&id)); - let escaped_text = tera::escape_html(&node.text); - let out_text = parser::read(&escaped_text); + let out_text = parser::read::(&node.text); context.insert("text", &out_text); let not_found = node.clone() == empty_node; diff --git a/src/syntax/content.rs b/src/syntax/content.rs index 2ec8f9e..aab6405 100644 --- a/src/syntax/content.rs +++ b/src/syntax/content.rs @@ -1,43 +1,31 @@ -use elements::{paragraph::Paragraph, header::Header}; +use elements::{header::Header}; +use units::{Token, Lexeme}; -mod elements; +mod units; +pub mod elements; pub mod parser; -enum Token { - Paragraph(Paragraph), - Header(Header), -} - -struct Lexeme<'l> { - pub raw: &'l str, - pub first: &'l str, -} - -impl<'l> Lexeme<'l> { - pub fn new(text: &'l str) -> Lexeme<'l> { - let vec: Vec<&'l str> = text.split(" ").collect(); - - Self { - raw: text, - first: vec.first().unwrap_or_else(|| unreachable!()), - } - } -} - -trait Parseable { +pub trait Parseable: Into { fn probe(lexeme: &Lexeme) -> bool; - fn lex(lexeme: &Lexeme) -> Self - where - Self: Sized; + fn lex(lexeme: &Lexeme) -> Self; fn render(&self) -> String; } -type Matcher = fn(&Lexeme) -> bool; -type Constructor = fn(&Lexeme) -> Token; +type Probe = fn(&Lexeme) -> bool; +type Lexer = fn(&Lexeme) -> Token; +type LexEntry = (Probe, Lexer); +type LexMap<'lm> = &'lm [LexEntry]; -static LEXMAP: &[(Matcher, Constructor)] = &[ - (Header::probe, |lexeme| Token::Header(Header::lex(lexeme))), - (Paragraph::probe, |lexeme| { - Token::Paragraph(Paragraph::lex(lexeme)) - }), -]; +const LEXMAP: LexMap = + &[(Header::probe, |lexeme| Token::Header(Header::lex(lexeme)))]; + +fn make_lexmap() -> Vec { + let mut vector: Vec<(Probe, Lexer)> = LEXMAP.to_vec(); + + fn adapter(lex: &Lexeme) -> Token { + D::lex(lex).into() + } + + vector.push((DefaultToken::probe, adapter::)); + vector +} diff --git a/src/syntax/content/elements.rs b/src/syntax/content/elements.rs index c2c6381..b00cc5f 100644 --- a/src/syntax/content/elements.rs +++ b/src/syntax/content/elements.rs @@ -1,2 +1,3 @@ -pub(super) mod paragraph; -pub(super) mod header; +pub mod header; +pub mod paragraph; +pub mod span; diff --git a/src/syntax/content/elements/paragraph.rs b/src/syntax/content/elements/paragraph.rs index 7367ddc..5d802ce 100644 --- a/src/syntax/content/elements/paragraph.rs +++ b/src/syntax/content/elements/paragraph.rs @@ -1,7 +1,7 @@ use std::fmt::Display; use crate::syntax::content::{Parseable, Lexeme}; -pub(in crate::syntax::content) struct Paragraph { +pub struct Paragraph { text: String, } diff --git a/src/syntax/content/parser.rs b/src/syntax/content/parser.rs index d49e0e2..ebbb83d 100644 --- a/src/syntax/content/parser.rs +++ b/src/syntax/content/parser.rs @@ -1,16 +1,17 @@ -use super::{Parseable as _, Token, Lexeme, LEXMAP}; +use crate::syntax::content::{Parseable, Token, Lexeme, make_lexmap}; -pub fn read(text: &str) -> String { - parse(&lex(text)) +pub fn read(text: &str) -> String { + let escaped_text = tera::escape_html(text); + parse(&lex(&escaped_text, &make_lexmap::())) } -fn lex(text: &str) -> Vec { - let mut tokens = Vec::new(); +fn lex(text: &str, map: super::LexMap) -> Vec { + let mut tokens: Vec = Vec::new(); for line in text.lines().filter(|x| !x.trim().is_empty()) { let lexeme = Lexeme::new(line); - for &(ref matcher, lexer) in LEXMAP { + for &(ref matcher, lexer) in map { if matcher(&lexeme) { tokens.push(lexer(&lexeme)); break; @@ -22,13 +23,9 @@ fn lex(text: &str) -> Vec { } fn parse(tokens: &[Token]) -> String { - let mut out_text: Vec = Vec::new(); - for token in tokens { - out_text.push(match *token { - Token::Paragraph(ref d) => d.render(), - Token::Header(ref d) => d.render(), - }); - } - - out_text.join("\n") + tokens + .iter() + .map(Token::render) + .collect::>() + .join("\n") } diff --git a/src/syntax/content/units.rs b/src/syntax/content/units.rs new file mode 100644 index 0000000..1f38058 --- /dev/null +++ b/src/syntax/content/units.rs @@ -0,0 +1,54 @@ +use crate::syntax::content::Parseable as _; +use crate::syntax::content::elements::{ + paragraph::Paragraph, header::Header, span::Span, +}; + +pub enum Token { + Paragraph(Paragraph), + Header(Header), + Span(Span), +} + +impl Token { + pub fn render(&self) -> String { + match *self { + Token::Paragraph(ref d) => d.render(), + Token::Header(ref d) => d.render(), + Token::Span(ref d) => d.render(), + } + } +} + +impl From for Token { + fn from(d: Paragraph) -> Self { + Token::Paragraph(d) + } +} + +impl From
for Token { + fn from(d: Header) -> Self { + Token::Header(d) + } +} + +impl From for Token { + fn from(d: Span) -> Self { + Token::Span(d) + } +} + +pub struct Lexeme<'l> { + pub raw: &'l str, + pub first: &'l str, +} + +impl<'l> Lexeme<'l> { + pub fn new(text: &'l str) -> Lexeme<'l> { + let vec: Vec<&'l str> = text.split(" ").collect(); + + Self { + raw: text, + first: vec.first().unwrap_or_else(|| unreachable!()), + } + } +}