diff --git a/Cargo.lock b/Cargo.lock index 5bfc908..118ff7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,12 +281,23 @@ checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" dependencies = [ "log", "mac", - "markup5ever", + "markup5ever 0.11.0", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "html5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" +dependencies = [ + "log", + "markup5ever 0.35.0", + "match_token", +] + [[package]] name = "htmlua-apache-cgi" version = "0.1.0" @@ -300,7 +311,9 @@ name = "htmlua-parser" version = "0.1.0" dependencies = [ "anyhow", + "html5ever 0.35.0", "kuchikiki", + "markup5ever 0.11.0", "mlua", "pulldown-cmark", "syntect", @@ -429,6 +442,28 @@ dependencies = [ "tendril", ] +[[package]] +name = "markup5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "matches" version = "0.1.10" @@ -588,6 +623,15 @@ dependencies = [ "phf_shared 0.10.0", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", +] + [[package]] name = "phf_codegen" version = "0.8.0" @@ -608,6 +652,16 @@ dependencies = [ "phf_shared 0.10.0", ] +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + [[package]] name = "phf_generator" version = "0.8.0" @@ -1219,6 +1273,18 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "web_atoms" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" +dependencies = [ + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "which" version = "7.0.3" diff --git a/htmlua-parser/Cargo.toml b/htmlua-parser/Cargo.toml index 1e27f09..28416b7 100644 --- a/htmlua-parser/Cargo.toml +++ b/htmlua-parser/Cargo.toml @@ -5,7 +5,9 @@ edition = "2024" [dependencies] anyhow = "1.0.98" +html5ever = "0.35.0" kuchikiki = "0.8.2" +markup5ever = "0.11.0" mlua = { version = "0.10.5", features = ["lua54", "vendored", "serialize"] } pulldown-cmark = "0.13.0" syntect = "5.2.0" diff --git a/htmlua-parser/src/helpers.rs b/htmlua-parser/src/helpers.rs new file mode 100644 index 0000000..90439f7 --- /dev/null +++ b/htmlua-parser/src/helpers.rs @@ -0,0 +1,32 @@ +use std::{fs::File, io::{BufRead, BufReader, Read, Seek, SeekFrom}, path::PathBuf}; + +use anyhow::Result; +use kuchikiki::NodeRef; +use markup5ever::{LocalName, Namespace, QualName}; +use tendril::TendrilSink; + + + + +pub fn read_doc_from_file(path: PathBuf) -> Result { + + let mut file = File::open(path)?; + let mut reader = BufReader::new(&mut file); + + let mut first_line = String::new(); + reader.read_line(&mut first_line)?; + let first_line_trimmed = first_line.trim(); + + let is_whole_doc = first_line_trimmed.eq_ignore_ascii_case(""); + + file.seek(SeekFrom::Start(0))?; + let mut page_string = String::new(); + file.read_to_string(&mut page_string)?; + + if is_whole_doc { + Ok(kuchikiki::parse_html().one(page_string)) + } else { + let ctx_name = QualName::new(None, Namespace::from("http://www.w3.org/1999/xhtml"), LocalName::from("div")); + Ok(kuchikiki::parse_fragment(ctx_name, Vec::new()).one(page_string)) + } +} diff --git a/htmlua-parser/src/lib.rs b/htmlua-parser/src/lib.rs index 03e66bd..cd87be2 100644 --- a/htmlua-parser/src/lib.rs +++ b/htmlua-parser/src/lib.rs @@ -1,2 +1,3 @@ pub mod render; pub mod serve; +pub mod helpers; diff --git a/htmlua-parser/src/render.rs b/htmlua-parser/src/render.rs index 55047fc..35c37f4 100644 --- a/htmlua-parser/src/render.rs +++ b/htmlua-parser/src/render.rs @@ -12,6 +12,8 @@ use syntect::{ util::LinesWithEndings, }; +use crate::helpers::read_doc_from_file; + fn create_htmlua_stdlib(l: &Lua, stdout: &Rc>) -> mlua::Result { let t = l.create_table()?; @@ -106,13 +108,14 @@ pub fn expand_template(document: NodeRef, component_path: &PathBuf, include_from let exported = from_node .select_first(format!("exportelement.{name}").as_str()) .map_err(|()| anyhow!("Error finding exportelement"))?; - exported.as_node().children().for_each(|c| i.as_node().insert_after(c)); + exported.as_node().children().rev().for_each(|c| i.as_node().insert_after(c)); } } while let Ok(i) = document.select_first("includeelement") { i.as_node().detach(); } } + for i in document .select("include") .map_err(|()| anyhow!("Error finding include"))? @@ -124,12 +127,8 @@ pub fn expand_template(document: NodeRef, component_path: &PathBuf, include_from if let Some(include_path) = attrs.get("path") { let mut item_path = component_path.clone(); item_path.push(include_path); - let component_text = read_to_string(item_path)?; - let new_doc = kuchikiki::parse_html().one(component_text); - let new_node = new_doc - .select_first("body") - .map_err(|()| anyhow!("Failed to get body"))?; - let replaced_node = expand_template(new_node.as_node().clone(), component_path, Some(i.as_node()))?; + let new_node = read_doc_from_file(item_path)?; + let replaced_node = expand_template(new_node, component_path, Some(i.as_node()))?; i.as_node().insert_before(replaced_node); i.as_node().detach(); } diff --git a/htmlua-parser/src/serve.rs b/htmlua-parser/src/serve.rs index 5b63e3d..06de0ea 100644 --- a/htmlua-parser/src/serve.rs +++ b/htmlua-parser/src/serve.rs @@ -1,10 +1,9 @@ +use crate::helpers::read_doc_from_file; + use super::render::{execute_lua, expand_template, process_markdown, process_syntax_highlighting}; use anyhow::Result; -use kuchikiki::traits::TendrilSink; -use std::{ - fs::read_to_string, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf} +; pub fn serve_content(request_uri: &str) -> Result { // TODO: read from config @@ -12,8 +11,9 @@ pub fn serve_content(request_uri: &str) -> Result { let components = PathBuf::from("/var/www/htmlua/components"); let safe_path = Path::new(request_uri).strip_prefix("/")?; let page_path = pages.join(safe_path); - let page_string = read_to_string(&page_path)?; - let doc = kuchikiki::parse_html().one(page_string); + + let doc = read_doc_from_file(page_path)?; + let full_doc = expand_template(doc, &components, None)?; let markdown_doc = process_markdown(full_doc)?; let highlighted_doc = process_syntax_highlighting(markdown_doc)?;