seam

Symbolic-Expressions As Markup.
git clone git://git.knutsen.co/seam
Log | Files | Refs | README | LICENSE

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:
Msrc/assemble/html.rs | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/parse/parser.rs | 17+++++++++++++++++
Mtest.html | 7++++---
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) = &current_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>