use std::{borrow::Cow, rc::Rc}; use crate::lineup::InterlinkSolver; pub struct Document<'raw> { pub(crate) nodes: Vec>, pub(crate) solver: Rc, } impl<'raw> Document<'raw> { pub fn set_interlink_solver(&mut self, solver: Rc) { self.solver = solver; } pub fn into_html(self) -> String { TreeNode::html_nodes(&self.nodes, Rc::clone(&self.solver)) } pub fn as_text(&self) -> String { TreeNode::text_nodes(&self.nodes, Rc::clone(&self.solver)) } } #[derive(Clone, Debug, PartialEq)] pub enum TreeNode<'raw> { Text(&'raw str), Interlink { children: Vec>, }, Link { kind: LinkKind, name: Option>>, children: Vec>, }, StyledText { style: NodeStyle, children: Vec>, }, ColoredText { color: &'raw str, children: Vec>, }, } #[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) -> Cow<'raw, str> { match self { TreeNode::Text(str) => Cow::Borrowed(str), 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!("{title}")) } 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!("{title}")) } TreeNode::StyledText { style, children } => { let (open, close) = match style { NodeStyle::Bold => ("", ""), NodeStyle::Code => ("", ""), NodeStyle::Italic => ("", ""), }; let inner = Self::html_nodes(children.as_slice(), solver); Cow::Owned(format!("{open}{inner}{close}")) } TreeNode::ColoredText { color, children } => { let inner = Self::html_nodes(children.as_slice(), solver); Cow::Owned(format!("{inner}")) } } } pub fn text(&self, solver: Rc) -> Cow<'raw, str> { match self { TreeNode::Text(str) => Cow::Borrowed(str), 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)) } TreeNode::ColoredText { color: _, children } => { Cow::Owned(Self::text_nodes(children, solver)) } } } fn text_nodes(nodes: &[TreeNode<'raw>], solver: Rc) -> 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) -> String { let mut ret = String::new(); for node in nodes { ret.push_str(&node.html(Rc::clone(&solver))); } ret } }