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
|
||||
/.vscode
|
||||
/*.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
|
||||
gdb
|
||||
stdenv
|
||||
|
||||
rustup
|
||||
rustc
|
||||
cargo
|
||||
];
|
||||
|
||||
# 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