commit b862381d54d9e9f7e7c211dbdbf768f3f48728ce
parent 07de6e47c5e479c5deadf225c4b8d62d0dc076ae
Author: Demonstrandum <moi@knutsen.co>
Date: Mon, 22 Jun 2020 05:55:25 +0100
Properly documentise HTML with missing tags.
Diffstat:
3 files changed, 85 insertions(+), 13 deletions(-)
diff --git a/src/assemble/html.rs b/src/assemble/html.rs
@@ -1,6 +1,6 @@
//! Assembles an expanded tree into valid HTML.
use super::Documentise;
-use crate::parse::parser::{ParseNode, ParseTree};
+use crate::parse::parser::{self, ParseNode, ParseTree};
use std::fmt::{self, Display};
@@ -24,16 +24,17 @@ pub const DEFAULT : &str =
impl Documentise for HTMLFormatter {
fn document(&self) -> String {
- // Check if <!DOCTYPE html> exists.
let mut doc = String::new();
if self.tree.is_empty() {
return String::from(DEFAULT);
}
- let mut current_node = &self.tree[0];
- let mut has_declaration = false;
+ let stripped = parser::strip(&self.tree);
+ let mut current_node = stripped.get(0);
- if let ParseNode::List(list) = ¤t_node {
- if let Some(ParseNode::Symbol(declaration)) = &list.get(0) {
+ // Check if <!DOCTYPE html> exists.
+ let mut has_declaration = false;
+ if let Some(ParseNode::List(list)) = current_node.as_ref() {
+ if let Some(ParseNode::Symbol(declaration)) = list.get(0) {
if declaration.value.to_lowercase() == "!doctype" {
has_declaration = true;
}
@@ -41,17 +42,70 @@ impl Documentise for HTMLFormatter {
}
if has_declaration {
- current_node = &self.tree[1];
+ current_node = stripped.get(1);
} else {
doc += "<!DOCTYPE html>\n"
}
+
// Check if <html></html> root object exists.
- // Check if head exits, if not, make an empty one.
- // Check if body exists, if not, make it, and put everything
- // in there.
+ let mut html_tag = false;
+ if let Some(ParseNode::List(list)) = current_node.as_ref() {
+ if let Some(ParseNode::Symbol(root_tag)) = &list.get(0) {
+ if root_tag.value.to_lowercase() == "html" {
+ html_tag = true;
+ }
+ }
+ }
+
+ if !html_tag {
+ doc += "<html>\n";
+ }
+ // Check if <head></head> exists.
+ let mut head_tag = false;
+ if let Some(ParseNode::List(list)) = current_node.as_ref() {
+ if let Some(ParseNode::List(head_list)) = &list.get(1) {
+ if let Some(ParseNode::Symbol(head)) = &head_list.get(0) {
+ if head.value.to_lowercase() == "head" {
+ head_tag = true;
+ }
+ }
+ }
+ }
+
+ if !head_tag {
+ doc += "<head></head>\n";
+ }
+
+ // Check if body exists, if not, make it, and populate it.
+ let mut body_tag = false;
+ if let Some(ParseNode::List(list)) = current_node.as_ref() {
+ if let Some(ParseNode::List(body_list)) = &list.get(2) {
+ if let Some(ParseNode::Symbol(body)) = &body_list.get(0) {
+ if body.value.to_lowercase() == "body" {
+ body_tag = true;
+ }
+ }
+ }
+ }
+
+ if !body_tag {
+ doc += "<body>\n";
+ }
+
+ // Populate.
+ doc += "<!-- Generated from symbolic-expressions \
+ into HTML. -->\n";
doc += &self.to_string();
+ // Cloes all new tags.
+ if !body_tag {
+ doc += "</body>\n";
+ }
+ if !html_tag {
+ doc += "</html>";
+ }
+
doc
}
}
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
@@ -157,6 +157,23 @@ pub fn parse_stream(tokens: tokens::TokenStream)
Ok(tree)
}
+/// Strip any pure whitespace nodes from the tree.
+pub fn strip(tree : &ParseTree) -> ParseTree {
+ let mut stripped = tree.to_owned();
+ stripped.retain(|branch| {
+ match branch {
+ ParseNode::String(node) => !node.value.trim().is_empty(),
+ _ => true
+ }
+ });
+ for branch in stripped.iter_mut() {
+ if let ParseNode::List(ref mut list) = branch {
+ *list = strip(list);
+ }
+ }
+ stripped
+}
+
/// Pretty printing for parse nodes.
#[cfg(feature="debug")]
impl fmt::Display for ParseNode {
diff --git a/test.html b/test.html
@@ -1,8 +1,9 @@
+<!-- Generated from symbolic-expressions into HTML. -->
<!DOCTYPE html>
-<html> <head> <title>Example HTML Document</title></head>
-<body> <p id="hello">Hello, World!</p>
+<html><head><title>Example HTML Document</title></head>
+<body><p id="hello">Hello, World!</p>
<p>something something text...</p>
-<h1> A (big) Header!</h1>
+<h1>A (big) Header!</h1>
<p>Yet some more <span style="color: red">text</span> <3</p>
<p>Hello<span style="color: green">World</span>!</p>
<img alt="Cat" src="https://static.insider.com/image/5d24d6b921a861093e71fef3.jpg" width="300"></img></body></html>