Holy mother of femboys, I love rust.
This commit is contained in:
parent
436e08dbef
commit
ed6e217ae8
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@
|
|||||||
parser
|
parser
|
||||||
/.vscode
|
/.vscode
|
||||||
/*.html
|
/*.html
|
||||||
|
/target
|
||||||
|
/target/*
|
||||||
|
|||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "MarkdownToHtmlTranspiler"
|
||||||
|
version = "0.1.0"
|
||||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "MarkdownToHtmlTranspiler"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@ -20,6 +20,10 @@
|
|||||||
gcc
|
gcc
|
||||||
gdb
|
gdb
|
||||||
stdenv
|
stdenv
|
||||||
|
|
||||||
|
rustup
|
||||||
|
rustc
|
||||||
|
cargo
|
||||||
];
|
];
|
||||||
|
|
||||||
# Define the shell that will be executed.
|
# Define the shell that will be executed.
|
||||||
|
|||||||
99
src/boilerplate.rs
Normal file
99
src/boilerplate.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/// This is an old code example, moving to using enums now
|
||||||
|
|
||||||
|
pub trait Node {
|
||||||
|
fn to_html(&self) -> String;
|
||||||
|
fn is_empty(&self) -> bool;
|
||||||
|
|
||||||
|
fn add_child(&mut self, _: Box<dyn Node>) {
|
||||||
|
panic!("Cannot add children to this node.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> Option<&[Box<dyn Node>]> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DocumentNode {
|
||||||
|
pub children: Vec<Box<dyn Node>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HeadingNode {
|
||||||
|
pub size: u8,
|
||||||
|
pub children: Vec<Box<dyn Node>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParagraphNode {
|
||||||
|
pub children: Vec<Box<dyn Node>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for DocumentNode {
|
||||||
|
fn to_html(&self) -> String {
|
||||||
|
let inner_html = self
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.map(|child| child.to_html())
|
||||||
|
.collect::<String>();
|
||||||
|
format!(
|
||||||
|
"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Document</title>\n</head>\n<body>{}</body>\n</html>",
|
||||||
|
inner_html
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.children.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_child(&mut self, child: Box<dyn Node>) {
|
||||||
|
self.children.push(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> Option<&[Box<dyn Node>]> {
|
||||||
|
Some(&self.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for HeadingNode {
|
||||||
|
fn to_html(&self) -> String {
|
||||||
|
let inner_html = self
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.map(|child| child.to_html())
|
||||||
|
.collect::<String>();
|
||||||
|
format!("<h{}>{}</h{}>", self.size, inner_html, self.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.children.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_child(&mut self, child: Box<dyn Node>) {
|
||||||
|
self.children.push(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> Option<&[Box<dyn Node>]> {
|
||||||
|
Some(&self.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for ParagraphNode {
|
||||||
|
fn to_html(&self) -> String {
|
||||||
|
let inner_html = self
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.map(|child| child.to_html())
|
||||||
|
.collect::<String>();
|
||||||
|
format!("<p>{}</p>", inner_html)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.children.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_child(&mut self, child: Box<dyn Node>) {
|
||||||
|
self.children.push(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> Option<&[Box<dyn Node>]> {
|
||||||
|
Some(&self.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
154
src/main.rs
Normal file
154
src/main.rs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
pub enum Node {
|
||||||
|
// Structure Nodes
|
||||||
|
Document { children: Vec<Node> },
|
||||||
|
Heading { level: u8, children: Vec<Node> },
|
||||||
|
Paragraph { children: Vec<Node> },
|
||||||
|
List { ordered: bool, children: Vec<Node> },
|
||||||
|
ListItem { children: Vec<Node> },
|
||||||
|
CodeBlock { children: Vec<Node> },
|
||||||
|
BlockQuote { children: Vec<Node> },
|
||||||
|
|
||||||
|
// Inline Nodes
|
||||||
|
Text { content: String },
|
||||||
|
Bold { content: String },
|
||||||
|
Italic { content: String },
|
||||||
|
BoldItalic { content: String },
|
||||||
|
Code { content: String },
|
||||||
|
Link { href: String, content: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub fn to_html(&self) -> String {
|
||||||
|
match self {
|
||||||
|
// Structure nodes
|
||||||
|
Node::Document { children } => {
|
||||||
|
let inner = children.iter().map(|x| x.to_html()).collect::<String>();
|
||||||
|
format!(
|
||||||
|
"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Document</title>\n</head>\n<body>{}</body>\n</html>",
|
||||||
|
inner
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Node::Heading { level, children } => {
|
||||||
|
let inner = children.iter().map(|x| x.to_html()).collect::<String>();
|
||||||
|
format!("<h{level}>{}</h{level}>", inner, level = level)
|
||||||
|
}
|
||||||
|
Node::Paragraph { children } => {
|
||||||
|
let inner = children.iter().map(|x| x.to_html()).collect::<String>();
|
||||||
|
format!("<p>{}</p>", inner)
|
||||||
|
}
|
||||||
|
Node::List { ordered, children } => {
|
||||||
|
let inner = children.iter().map(|x| x.to_html()).collect::<String>();
|
||||||
|
let tag = if *ordered { "ol" } else { "ul" };
|
||||||
|
format!("<{tag}>{}</{tag}>", inner, tag = tag)
|
||||||
|
}
|
||||||
|
Node::ListItem { children } => {
|
||||||
|
let inner = children.iter().map(|x| x.to_html()).collect::<String>();
|
||||||
|
format!("<li>{}</li>", inner)
|
||||||
|
}
|
||||||
|
Node::CodeBlock { children } => {
|
||||||
|
let inner = children.iter().map(|x| x.to_html()).collect::<String>();
|
||||||
|
format!("<code>{}</code>", inner)
|
||||||
|
}
|
||||||
|
Node::BlockQuote { children } => {
|
||||||
|
let inner = children.iter().map(|x| x.to_html()).collect::<String>();
|
||||||
|
format!("<blockquote>{}</blockquote>", inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline nodes
|
||||||
|
Node::Text { content } => format!("{}", content),
|
||||||
|
Node::Bold { content } => format!("<strong>{}</strong>", content),
|
||||||
|
Node::Italic { content } => format!("<em>{}</em>", content),
|
||||||
|
Node::BoldItalic { content } => format!("<strong><em>{}</em></strong>", content),
|
||||||
|
Node::Code { content } => format!("<code>{}</code>", content),
|
||||||
|
Node::Link { href, content } => format!("<a href=\"{}\">{}</a>", href, content),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if a node is empty. For structure nodes (those with `children`) this will be
|
||||||
|
/// true when there are no elements in the list. For inline nodes (those without `children`)
|
||||||
|
/// this will be true when the string content of all fields are blank.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
// Structure nodes
|
||||||
|
Node::Document { children }
|
||||||
|
| Node::Heading { level: _, children }
|
||||||
|
| Node::Paragraph { children }
|
||||||
|
| Node::List {
|
||||||
|
ordered: _,
|
||||||
|
children,
|
||||||
|
}
|
||||||
|
| Node::ListItem { children }
|
||||||
|
| Node::CodeBlock { children }
|
||||||
|
| Node::BlockQuote { children } => children.is_empty(),
|
||||||
|
|
||||||
|
// Inline nodes
|
||||||
|
Node::Text { content }
|
||||||
|
| Node::Bold { content }
|
||||||
|
| Node::Italic { content }
|
||||||
|
| Node::BoldItalic { content }
|
||||||
|
| Node::Code { content } => content.is_empty(),
|
||||||
|
|
||||||
|
// Special rules
|
||||||
|
Node::Link { href, content } => content.is_empty() && href.is_empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns Some children if they exist, otherwise None will be returned. For nodes that do not
|
||||||
|
/// have children, None will be returned.
|
||||||
|
pub fn children(&self) -> Option<&[Node]> {
|
||||||
|
match self {
|
||||||
|
Node::Document { children }
|
||||||
|
| Node::Heading { level: _, children }
|
||||||
|
| Node::Paragraph { children }
|
||||||
|
| Node::List {
|
||||||
|
ordered: _,
|
||||||
|
children,
|
||||||
|
}
|
||||||
|
| Node::ListItem { children }
|
||||||
|
| Node::CodeBlock { children }
|
||||||
|
| Node::BlockQuote { children } => Some(&children),
|
||||||
|
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a child to the back of the list of children. If the node is a type which does not allow
|
||||||
|
/// children to be added, this function will panic.
|
||||||
|
pub fn add_child(&mut self, child: Node) {
|
||||||
|
match self {
|
||||||
|
Node::Document { children }
|
||||||
|
| Node::Heading { level: _, children }
|
||||||
|
| Node::Paragraph { children }
|
||||||
|
| Node::List {
|
||||||
|
ordered: _,
|
||||||
|
children,
|
||||||
|
}
|
||||||
|
| Node::ListItem { children }
|
||||||
|
| Node::CodeBlock { children }
|
||||||
|
| Node::BlockQuote { children } => children.push(child),
|
||||||
|
|
||||||
|
_ => panic!("Can't add child to this node type."),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let root = Node::Document {
|
||||||
|
children: vec![Node::Heading {
|
||||||
|
level: 1,
|
||||||
|
children: vec![
|
||||||
|
Node::Text {
|
||||||
|
content: String::from("Heading level 1"),
|
||||||
|
},
|
||||||
|
Node::Bold {
|
||||||
|
content: String::from(" this part is bold"),
|
||||||
|
},
|
||||||
|
Node::Italic {
|
||||||
|
content: String::from(" this part is italic"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{}", root.to_html())
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user