summaryrefslogtreecommitdiff
path: root/htmlua-parser
diff options
context:
space:
mode:
authorGrace Yoder <70408179+gyoder@users.noreply.github.com>2025-07-05 22:09:35 -0600
committerGitHub <noreply@github.com>2025-07-05 22:09:35 -0600
commit3897b8dd30d11cad8b35129797186c5879f9f711 (patch)
treee85b9c4192e4d338999c5c2065601c7c8e568f73 /htmlua-parser
parent9a0038dacde3bcf1a10de51278d72f0f322c3817 (diff)
parentc663ae27a8894afe8dc27586ecfc5f94b8731363 (diff)
Merge pull request #7 from trypsynth/markdown
Added support for <markdown>. Closes #4.
Diffstat (limited to 'htmlua-parser')
-rw-r--r--htmlua-parser/Cargo.toml1
-rw-r--r--htmlua-parser/src/render.rs63
-rw-r--r--htmlua-parser/src/serve.rs17
3 files changed, 64 insertions, 17 deletions
diff --git a/htmlua-parser/Cargo.toml b/htmlua-parser/Cargo.toml
index b611fde..c3cbe07 100644
--- a/htmlua-parser/Cargo.toml
+++ b/htmlua-parser/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2024"
anyhow = "1.0.98"
kuchikiki = "0.8.2"
mlua = { version = "0.10.5", features = ["lua54", "vendored", "serialize"] }
+pulldown-cmark = "0.13.0"
tendril = "0.4.3"
diff --git a/htmlua-parser/src/render.rs b/htmlua-parser/src/render.rs
index fe0b64f..eb50c2c 100644
--- a/htmlua-parser/src/render.rs
+++ b/htmlua-parser/src/render.rs
@@ -1,13 +1,9 @@
-use std::cell::RefCell;
-use std::fmt::Write;
-use std::fs::read_to_string;
-use std::path::PathBuf;
-use std::rc::Rc;
+use std::{cell::RefCell, fmt::Write, fs::read_to_string, path::PathBuf, rc::Rc};
-use anyhow::Result;
-use anyhow::anyhow;
+use anyhow::{Result, anyhow};
use kuchikiki::{NodeRef, traits::TendrilSink};
use mlua::{Lua, Table};
+use pulldown_cmark::{Options, Parser, html};
fn create_htmlua_stdlib(l: &Lua, stdout: &Rc<RefCell<String>>) -> mlua::Result<Table> {
let t = l.create_table()?;
@@ -69,6 +65,30 @@ pub fn execute_lua(document: NodeRef) -> Result<NodeRef> {
Ok(document)
}
+pub fn process_markdown(document: NodeRef) -> Result<NodeRef> {
+ let markdown_elements: Vec<_> = match document.select("markdown") {
+ Ok(e) => e.collect(),
+ Err(()) => return Err(anyhow!("Unable to find markdown elements")),
+ };
+ for node in markdown_elements {
+ if let Some(text_node) = node.as_node().first_child() {
+ if let Some(markdown_text) = text_node.as_text() {
+ let borrowed_text = markdown_text.borrow();
+ let parser = Parser::new_ext(&borrowed_text, Options::all());
+ let mut html_output = String::new();
+ html::push_html(&mut html_output, parser);
+ let html_fragment = kuchikiki::parse_html().one(html_output);
+ for child in html_fragment.children() {
+ node.as_node().insert_before(child);
+ }
+ // Remove the original markdown node.
+ node.as_node().detach();
+ }
+ }
+ }
+ Ok(document)
+}
+
pub fn expand_template(document: NodeRef, component_path: &PathBuf, include_from: Option<&NodeRef>) -> Result<NodeRef> {
if let Some(from_node) = include_from {
for i in document
@@ -269,4 +289,33 @@ mod tests {
assert!(d.select_first("exportelement").is_err());
assert!(d.select_first("includeelement").is_err());
}
+
+ #[test]
+ fn basic_markdown() {
+ let page = r#"
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Markdown Test</title>
+ </head>
+ <body>
+ <h1>Hello World</h1>
+ <div>
+ <markdown>
+# This is a heading
+This is a paragraph with **bold text** and *italic text*.
+
+- Item 1
+- Item 2
+- Item 3
+ </markdown>
+ </div>
+ </body>
+ </html>"#;
+ let document = kuchikiki::parse_html().one(page);
+ let d = process_markdown(document).unwrap();
+ assert!(d.select_first("markdown").is_err());
+ assert!(d.select_first("p").is_ok());
+ assert!(d.select_first("ul").is_ok());
+ }
}
diff --git a/htmlua-parser/src/serve.rs b/htmlua-parser/src/serve.rs
index 134cc13..eb9a043 100644
--- a/htmlua-parser/src/serve.rs
+++ b/htmlua-parser/src/serve.rs
@@ -1,24 +1,21 @@
-use super::render::execute_lua;
-use super::render::expand_template;
+use super::render::{execute_lua, expand_template, process_markdown};
use anyhow::Result;
use kuchikiki::traits::TendrilSink;
-use std::fs::read_to_string;
-use std::path::{Path, PathBuf};
+use std::{
+ fs::read_to_string,
+ path::{Path, PathBuf},
+};
pub fn serve_content(request_uri: &str) -> Result<String> {
// TODO: read from config
let pages = PathBuf::from("/var/www/htmlua/pages");
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 full_doc = expand_template(doc, &components, None)?;
- let executed_doc = execute_lua(full_doc)?;
-
+ let markdown_doc = process_markdown(full_doc)?;
+ let executed_doc = execute_lua(markdown_doc)?;
Ok(executed_doc.to_string())
}