diff options
| author | gennyble <gen@nyble.dev> | 2026-09-21 14:23:07 -0500 |
|---|---|---|
| committer | gennyble <gen@nyble.dev> | 2026-09-21 14:23:07 -0500 |
| commit | be872aa0cd61ea16b95eddcd68c6a72f0fe3af96 (patch) | |
| tree | 8935da5f9639b939a0e5ecd2bba3072d71d602bc /markup/src/lineup/tree.rs | |
| parent | 178ca3c066a1ef920b112da741625099b6dc07da (diff) | |
massive reorg
Diffstat (limited to 'markup/src/lineup/tree.rs')
| -rw-r--r-- | markup/src/lineup/tree.rs | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/markup/src/lineup/tree.rs b/markup/src/lineup/tree.rs new file mode 100644 index 0000000..dcb1cb4 --- /dev/null +++ b/markup/src/lineup/tree.rs @@ -0,0 +1,147 @@ +use std::{borrow::Cow, rc::Rc}; + +use crate::InterlinkSolver; + +pub struct Document<'raw> { + pub(crate) nodes: Vec<TreeNode<'raw>>, + pub(crate) solver: Rc<dyn InterlinkSolver>, +} + +impl<'raw> Document<'raw> { + pub fn set_interlink_solver(&mut self, solver: Rc<dyn InterlinkSolver>) { + self.solver = solver; + } + + pub fn html(self) -> String { + TreeNode::html_nodes(&self.nodes, Rc::clone(&self.solver)) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum TreeNode<'raw> { + Text(&'raw str), + Paragraph { + children: Vec<TreeNode<'raw>>, + }, + Interlink { + children: Vec<TreeNode<'raw>>, + }, + Link { + kind: LinkKind, + name: Option<Vec<TreeNode<'raw>>>, + children: Vec<TreeNode<'raw>>, + }, + StyledText { + style: NodeStyle, + children: Vec<TreeNode<'raw>>, + }, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum LinkKind { + External, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum NodeStyle { + Bold, + Code, + Italic, +} + +impl<'raw> TreeNode<'raw> { + pub fn html(&self, solver: Rc<dyn InterlinkSolver>) -> Cow<'raw, str> { + match self { + TreeNode::Text(str) => Cow::Borrowed(str), + TreeNode::Paragraph { children } => { + let inner = Self::html_nodes(children.as_slice(), solver); + Cow::Owned(format!("<p>{inner}</p>")) + } + TreeNode::Interlink { children } => { + let txt = Self::text_nodes(&children, Rc::clone(&solver)); + + let title = solver.link_title(&txt); + let location = solver.link_location(&txt); + + Cow::Owned(format!("<a href=\"{location}\">{title}</a>")) + } + TreeNode::Link { + kind, + name, + children, + } => { + let txt = Self::text_nodes(&children, Rc::clone(&solver)); + + let title = match name.as_deref() { + None => Cow::Borrowed(txt.as_str()), + Some(name) => { + let txt = Self::text_nodes(name, Rc::clone(&solver)); + Cow::Owned(txt) + } + }; + let location = txt.as_str(); + + Cow::Owned(format!("<a href=\"{location}\">{title}</a>")) + } + TreeNode::StyledText { style, children } => { + let (open, close) = match style { + NodeStyle::Bold => ("<b>", "</b>"), + NodeStyle::Code => ("<code>", "</code>"), + NodeStyle::Italic => ("<i>", "</i>"), + }; + + let inner = Self::html_nodes(children.as_slice(), solver); + Cow::Owned(format!("{open}{inner}{close}")) + } + } + } + + pub fn text(&self, solver: Rc<dyn InterlinkSolver>) -> Cow<'raw, str> { + match self { + TreeNode::Text(str) => Cow::Borrowed(str), + TreeNode::Paragraph { children } => Cow::Owned(Self::text_nodes(children, solver)), + TreeNode::Interlink { children } => { + let text = Self::text_nodes(children, Rc::clone(&solver)); + Cow::Owned(solver.link_title(&text).into_owned()) + } + TreeNode::Link { + kind: _, + name, + children, + } => match name.as_deref() { + None => { + let text = Self::text_nodes(children, Rc::clone(&solver)); + Cow::Owned(solver.link_title(&text).into_owned()) + } + Some(name) => { + let text = Self::text_nodes(name, Rc::clone(&solver)); + Cow::Owned(solver.link_title(&text).into_owned()) + } + }, + TreeNode::StyledText { style: _, children } => { + Cow::Owned(Self::text_nodes(children, solver)) + } + } + } + + fn text_nodes(nodes: &[TreeNode<'raw>], solver: Rc<dyn InterlinkSolver>) -> String { + let mut ret = String::new(); + for node in nodes { + let node_txt = &node.text(Rc::clone(&solver)); + if !node_txt.is_empty() { + ret.push_str(node_txt); + } + } + + ret + } + + fn html_nodes(nodes: &[TreeNode<'raw>], solver: Rc<dyn InterlinkSolver>) -> String { + let mut ret = String::new(); + for node in nodes { + ret.push_str(&node.html(Rc::clone(&solver))); + } + + ret + } +} |
