Skip to content

Commit

Permalink
Fix HTML shortcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
Keats committed Dec 9, 2021
1 parent 5b0e1ed commit 1e55db1
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 73 deletions.
125 changes: 52 additions & 73 deletions components/rendering/src/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,56 @@ pub fn markdown_to_html(

{
let mut events = Vec::new();
macro_rules! render_shortcodes {
($is_text:expr, $text:expr, $range:expr) => {
let orig_range_start = $range.start;
loop {
if let Some(ref shortcode) = next_shortcode {
if !$range.contains(&shortcode.span.start) {
break;
}
let sc_span = shortcode.span.clone();

// we have some text before the shortcode, push that first
if $range.start != sc_span.start {
let content = $text[($range.start - orig_range_start)
..(sc_span.start - orig_range_start)]
.to_string()
.into();
events.push(if $is_text {
Event::Text(content)
} else {
Event::Html(content)
});
$range.start = sc_span.start;
}

// Now we should be at the same idx as the shortcode
let shortcode = next_shortcode.take().unwrap();
match shortcode.render(&context.tera, &context.tera_context) {
Ok(s) => {
events.push(Event::Html(s.into()));
$range.start += SHORTCODE_PLACEHOLDER.len();
}
Err(e) => {
error = Some(e);
break;
}
}
next_shortcode = html_shortcodes.pop();
continue;
}

break;
}

if !$range.is_empty() {
// The $range value is for the whole document, not for this slice of text
let content = $text[($range.start - orig_range_start)..].to_string().into();
events.push(if $is_text { Event::Text(content) } else { Event::Html(content) });
}
};
}

for (event, mut range) in Parser::new_ext(content, opts).into_offset_iter() {
match event {
Expand All @@ -206,45 +256,7 @@ pub fn markdown_to_html(
continue;
}

// TODO: find a way to share that code with the HTML handler
let mut new_text = text.clone();
loop {
if let Some(ref shortcode) = next_shortcode {
let sc_span = shortcode.span.clone();
if range.contains(&sc_span.start) {
if range.start != sc_span.start {
events.push(Event::Text(
new_text[..(sc_span.start - range.start)]
.to_string()
.into(),
));
}

let shortcode = next_shortcode.take().unwrap();

match shortcode.render(&context.tera, &context.tera_context) {
Ok(s) => {
events.push(Event::Html(s.into()));
new_text = new_text[(sc_span.end - range.start)..]
.to_owned()
.into();
range.start = sc_span.end - range.start;
}
Err(e) => {
error = Some(e);
break;
}
}

next_shortcode = html_shortcodes.pop();
continue;
}
}

break;
}

events.push(Event::Text(new_text[..].to_string().into()));
render_shortcodes!(true, text, range);
}
}
Event::Start(Tag::CodeBlock(ref kind)) => {
Expand Down Expand Up @@ -338,40 +350,7 @@ pub fn markdown_to_html(
continue;
}

let mut new_text = text.clone();
loop {
if let Some(ref shortcode) = next_shortcode {
let sc_span = shortcode.span.clone();
if range.contains(&sc_span.start) {
if range.start != sc_span.start {
events.push(Event::Html(
new_text[..(sc_span.start - range.start)].to_owned().into(),
));
}

let shortcode = next_shortcode.take().unwrap();
match shortcode.render(&context.tera, &context.tera_context) {
Ok(s) => {
events.push(Event::Html(s.into()));
new_text = new_text[(sc_span.end - range.start)..]
.to_owned()
.into();
range.start = sc_span.end - range.start;
}
Err(e) => {
error = Some(e);
break;
}
}

next_shortcode = html_shortcodes.pop();
continue;
}
}

break;
}
events.push(Event::Html(new_text[..].to_string().into()));
render_shortcodes!(false, text, range);
}
_ => events.push(event),
}
Expand Down
46 changes: 46 additions & 0 deletions components/rendering/tests/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1656,3 +1656,49 @@ ttest2
let res = render_content(markdown_string, &context).unwrap();
assert_eq!(res.body, "<p>ttest1</p>\n<p>123</p>\n<p>ttest2</p>\n<p>123</p>\n");
}

// https://github.com/getzola/zola/issues/1689
#[test]
fn html_shortcode_regression() {
let permalinks_ctx = HashMap::new();
let mut tera = Tera::default();
tera.extend(&ZOLA_TERA).unwrap();
tera.add_raw_template("shortcodes/ex.html", "1").unwrap();
tera.add_raw_template("shortcodes/book.html", "2").unwrap();
tera.add_raw_template("shortcodes/std.html", "3").unwrap();
let config = Config::default_for_test();
let mut context = RenderContext::new(
&tera,
&config,
&config.default_language,
"",
&permalinks_ctx,
InsertAnchor::None,
);
let shortcode_def = utils::templates::get_shortcodes(&tera);
context.set_shortcode_definitions(&shortcode_def);

let markdown_string = r#"{{ book(page="") }} {{ ex(page="") }} {{ std(page="std") }}"#;
let res = render_content(markdown_string, &context).unwrap();
assert_eq!(res.body, "<p>2 1 3</p>\n");

// And in html
let markdown_string = r#"<p>{{ book(page="") }} {{ ex(page="") }} {{ std(page="std") }}</p>"#;
let res = render_content(markdown_string, &context).unwrap();
assert_eq!(res.body, "<p>2 1 3</p>");

// Another one with newlines
let markdown_string = "<p>\n{{ book(page='') }}\n</p>";
let res = render_content(markdown_string, &context).unwrap();
assert_eq!(res.body, "<p>\n2\n</p>");

// And another one
let markdown_string = "<span>{{ book(page='') }}</span>\n**The Book** {{ book(page='') }}";
let res = render_content(markdown_string, &context).unwrap();
assert_eq!(res.body, "<p><span>2</span>\n<strong>The Book</strong> 2</p>\n");

// with some text in between
let markdown_string = r#"a.{{ book(page="") }} b.{{ ex(page="") }} c.{{ std(page="std") }}"#;
let res = render_content(markdown_string, &context).unwrap();
assert_eq!(res.body, "<p>a.2 b.1 c.3</p>\n");
}

0 comments on commit 1e55db1

Please sign in to comment.