Skip to content

Commit 188fa13

Browse files
authored
Fix shortcode/continue-reading parsing with inline HTML (smaller version) (#2606)
* Fix shortcode/continue-reading parsing with inline HTML (smaller version) * Remove inline <!-- more -->
1 parent 0ce8936 commit 188fa13

File tree

8 files changed

+105
-31
lines changed

8 files changed

+105
-31
lines changed

components/content/src/page.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ static RFC3339_DATE: Lazy<Regex> = Lazy::new(|| {
3131
).unwrap()
3232
});
3333

34-
static FOOTNOTES_RE: Lazy<Regex> = Lazy::new(|| {
35-
Regex::new(r#"<sup class="footnote-reference"><a href=\s*.*?>\s*.*?</a></sup>"#).unwrap()
36-
});
37-
3834
#[derive(Clone, Debug, Default, PartialEq, Eq)]
3935
pub struct Page {
4036
/// All info about the actual file
@@ -232,10 +228,7 @@ impl Page {
232228
let res = render_content(&self.raw_content, &context)
233229
.with_context(|| format!("Failed to render content of {}", self.file.path.display()))?;
234230

235-
self.summary = res
236-
.summary_len
237-
.map(|l| &res.body[0..l])
238-
.map(|s| FOOTNOTES_RE.replace_all(s, "").into_owned());
231+
self.summary = res.summary;
239232
self.content = res.body;
240233
self.toc = res.toc;
241234
self.external_links = res.external_links;

components/markdown/src/markdown.rs

+36-18
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ static MORE_DIVIDER_RE: Lazy<Regex> = Lazy::new(|| {
3636
.unwrap()
3737
});
3838

39+
static FOOTNOTES_RE: Lazy<Regex> = Lazy::new(|| {
40+
Regex::new(r#"<sup class="footnote-reference"><a href=\s*.*?>\s*.*?</a></sup>"#).unwrap()
41+
});
42+
3943
/// Although there exists [a list of registered URI schemes][uri-schemes], a link may use arbitrary,
4044
/// private schemes. This regex checks if the given string starts with something that just looks
4145
/// like a scheme, i.e., a case-insensitive identifier followed by a colon.
@@ -78,7 +82,7 @@ fn is_colocated_asset_link(link: &str) -> bool {
7882
#[derive(Debug)]
7983
pub struct Rendered {
8084
pub body: String,
81-
pub summary_len: Option<usize>,
85+
pub summary: Option<String>,
8286
pub toc: Vec<Heading>,
8387
/// Links to site-local pages: relative path plus optional anchor target.
8488
pub internal_links: Vec<(String, Option<String>)>,
@@ -405,6 +409,7 @@ pub fn markdown_to_html(
405409
.map(|x| x.as_object().unwrap().get("relative_path").unwrap().as_str().unwrap());
406410
// the rendered html
407411
let mut html = String::with_capacity(content.len());
412+
let mut summary = None;
408413
// Set while parsing
409414
let mut error = None;
410415

@@ -679,17 +684,13 @@ pub fn markdown_to_html(
679684
event
680685
});
681686
}
682-
Event::Html(text) => {
683-
if !has_summary && MORE_DIVIDER_RE.is_match(&text) {
684-
has_summary = true;
685-
events.push(Event::Html(CONTINUE_READING.into()));
686-
continue;
687-
}
688-
if !contains_shortcode(text.as_ref()) {
689-
events.push(Event::Html(text));
690-
continue;
691-
}
692-
687+
Event::Html(text) if !has_summary && MORE_DIVIDER_RE.is_match(text.as_ref()) => {
688+
has_summary = true;
689+
events.push(Event::Html(CONTINUE_READING.into()));
690+
}
691+
Event::Html(text) | Event::InlineHtml(text)
692+
if contains_shortcode(text.as_ref()) =>
693+
{
693694
render_shortcodes!(false, text, range);
694695
}
695696
_ => events.push(event),
@@ -781,14 +782,31 @@ pub fn markdown_to_html(
781782
convert_footnotes_to_github_style(&mut events);
782783
}
783784

784-
cmark::html::push_html(&mut html, events.into_iter());
785+
let continue_reading = events
786+
.iter()
787+
.position(|e| matches!(e, Event::Html(CowStr::Borrowed(CONTINUE_READING))))
788+
.unwrap_or(events.len());
789+
790+
let mut events = events.into_iter();
791+
792+
// emit everything up to summary
793+
cmark::html::push_html(&mut html, events.by_ref().take(continue_reading));
794+
795+
if has_summary {
796+
// remove footnotes
797+
let summary_html = FOOTNOTES_RE.replace_all(&html, "").into_owned();
798+
summary = Some(summary_html)
799+
}
800+
801+
// emit everything after summary
802+
cmark::html::push_html(&mut html, events);
785803
}
786804

787805
if let Some(e) = error {
788806
Err(e)
789807
} else {
790808
Ok(Rendered {
791-
summary_len: if has_summary { html.find(CONTINUE_READING) } else { None },
809+
summary,
792810
body: html,
793811
toc: make_table_of_contents(headings),
794812
internal_links,
@@ -861,10 +879,10 @@ mod tests {
861879
for more in mores {
862880
let content = format!("{top}\n\n{more}\n\n{bottom}");
863881
let rendered = markdown_to_html(&content, &context, vec![]).unwrap();
864-
assert!(rendered.summary_len.is_some(), "no summary when splitting on {more}");
865-
let summary_len = rendered.summary_len.unwrap();
866-
let summary = &rendered.body[..summary_len].trim();
867-
let body = &rendered.body[summary_len..].trim();
882+
assert!(rendered.summary.is_some(), "no summary when splitting on {more}");
883+
let summary = rendered.summary.unwrap();
884+
let summary = summary.trim();
885+
let body = rendered.body[summary.len()..].trim();
868886
let continue_reading = &body[..CONTINUE_READING.len()];
869887
let body = &body[CONTINUE_READING.len()..].trim();
870888
assert_eq!(summary, &top_rendered);

components/markdown/tests/shortcodes.rs

+12
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,15 @@ fn can_use_shortcodes_in_quotes() {
311311
.body;
312312
insta::assert_snapshot!(body);
313313
}
314+
315+
#[test]
316+
fn can_render_with_inline_html() {
317+
let body = common::render(
318+
r#"
319+
Here is <span>{{ ex1(page="") }}</span> example.
320+
"#,
321+
)
322+
.unwrap()
323+
.body;
324+
insta::assert_snapshot!(body);
325+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
source: components/markdown/tests/shortcodes.rs
3+
expression: body
4+
---
5+
<p>Here is <span>1</span> example.</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
source: components/markdown/tests/summary.rs
3+
expression: body
4+
---
5+
<p>Hello world.</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
source: components/markdown/tests/summary.rs
3+
expression: rendered.body
4+
---
5+
<p>Things to do:</p>
6+
<ul>
7+
<li>Program <!-- more --> something</li>
8+
<li>Eat</li>
9+
<li>Sleep</li>
10+
</ul>

components/markdown/tests/summary.rs

+35-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
mod common;
22

33
fn get_summary(content: &str) -> String {
4-
let rendered = common::render(content).unwrap();
5-
assert!(rendered.summary_len.is_some());
6-
let summary_len = rendered.summary_len.unwrap();
7-
rendered.body[..summary_len].to_owned()
4+
get_rendered(content).summary.expect("had no summary")
5+
}
6+
7+
fn get_rendered(content: &str) -> markdown::Rendered {
8+
common::render(content).expect("couldn't render")
89
}
910

1011
#[test]
@@ -45,3 +46,33 @@ And some content after
4546
);
4647
insta::assert_snapshot!(body);
4748
}
49+
50+
#[test]
51+
fn no_truncated_summary() {
52+
let rendered = get_rendered(
53+
r#"
54+
Things to do:
55+
* Program <!-- more --> something
56+
* Eat
57+
* Sleep
58+
"#,
59+
);
60+
assert!(rendered.summary.is_none());
61+
insta::assert_snapshot!(rendered.body);
62+
}
63+
64+
#[test]
65+
fn footnotes_summary() {
66+
let body = get_summary(
67+
r#"
68+
Hello world[^1].
69+
70+
<!-- more -->
71+
72+
Good bye.
73+
74+
[^1]: "World" is a placeholder.
75+
"#,
76+
);
77+
insta::assert_snapshot!(body);
78+
}

docs/content/documentation/content/page.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ template = "page.html"
155155
You can ask Zola to create a summary if, for example, you only want to show the first
156156
paragraph of the page content in a list.
157157

158-
To do so, add <code>&lt;!-- more --&gt;</code> in your content at the point
158+
To do so, add `<!-- more -->` in your content at the point
159159
where you want the summary to end. The content up to that point will be
160160
available separately in the
161161
[template](@/documentation/templates/pages-sections.md#page-variables) via `page.summary`.

0 commit comments

Comments
 (0)