Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow inline summary cutoff #2581

Open
wants to merge 1 commit into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/content/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ markdown = { path = "../markdown" }
[dev-dependencies]
test-case = "3" # TODO: can we solve that usecase in src/page.rs in a simpler way? A custom macro_rules! maybe
tempfile = "3.3.0"
templates = { path = "../templates" }
14 changes: 7 additions & 7 deletions components/content/src/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ mod tests {
use std::path::{Path, PathBuf};

use libs::globset::{Glob, GlobSetBuilder};
use libs::tera::Tera;
use tempfile::tempdir;
use templates::ZOLA_TERA;

use crate::Page;
use config::{Config, LanguageOptions};
Expand All @@ -325,7 +325,7 @@ Hello world"#;
let mut page = res.unwrap();
page.render_markdown(
&HashMap::default(),
&Tera::default(),
&ZOLA_TERA,
&config,
InsertAnchor::None,
&HashMap::new(),
Expand Down Expand Up @@ -353,7 +353,7 @@ Hello world"#;
let mut page = res.unwrap();
page.render_markdown(
&HashMap::default(),
&Tera::default(),
&ZOLA_TERA,
&config,
InsertAnchor::None,
&HashMap::new(),
Expand Down Expand Up @@ -523,13 +523,13 @@ Hello world
let mut page = res.unwrap();
page.render_markdown(
&HashMap::default(),
&Tera::default(),
&ZOLA_TERA,
&config,
InsertAnchor::None,
&HashMap::new(),
)
.unwrap();
assert_eq!(page.summary, Some("<p>Hello world</p>\n".to_string()));
assert_eq!(page.summary, Some("<p>Hello world</p>".to_string()));
}

#[test]
Expand Down Expand Up @@ -557,15 +557,15 @@ And here's another. [^3]
let mut page = res.unwrap();
page.render_markdown(
&HashMap::default(),
&Tera::default(),
&ZOLA_TERA,
&config,
InsertAnchor::None,
&HashMap::new(),
)
.unwrap();
assert_eq!(
page.summary,
Some("<p>This page use <sup>1.5</sup> and has footnotes, here\'s one. </p>\n<p>Here's another. </p>\n".to_string())
Some("<p>This page use <sup>1.5</sup> and has footnotes, here\'s one. </p>\n<p>Here's another. </p>".to_string())
);
}

Expand Down
48 changes: 44 additions & 4 deletions components/markdown/src/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::codeblock::{CodeBlock, FenceSettings};
use crate::shortcode::{Shortcode, SHORTCODE_PLACEHOLDER};

const CONTINUE_READING: &str = "<span id=\"continue-reading\"></span>";
const SUMMARY_CUTOFF_TEMPLATE: &str = "summary-cutoff.html";
const ANCHOR_LINK_TEMPLATE: &str = "anchor-link.html";
static EMOJI_REPLACER: Lazy<EmojiReplacer> = Lazy::new(EmojiReplacer::new);

Expand Down Expand Up @@ -684,7 +685,9 @@ pub fn markdown_to_html(
event
});
}
Event::Html(text) if !has_summary && MORE_DIVIDER_RE.is_match(text.as_ref()) => {
Event::Html(text) | Event::InlineHtml(text)
if !has_summary && MORE_DIVIDER_RE.is_match(text.as_ref()) =>
{
has_summary = true;
events.push(Event::Html(CONTINUE_READING.into()));
}
Expand Down Expand Up @@ -787,15 +790,50 @@ pub fn markdown_to_html(
.position(|e| matches!(e, Event::Html(CowStr::Borrowed(CONTINUE_READING))))
.unwrap_or(events.len());

// determine closing tags missing from summary
let mut tags = Vec::new();
for event in &events[..continue_reading] {
match event {
Event::Start(Tag::HtmlBlock) | Event::End(TagEnd::HtmlBlock) => (),
Event::Start(tag) => tags.push(tag.to_end()),
Event::End(tag) => {
tags.truncate(tags.iter().rposition(|t| *t == *tag).unwrap_or(0));
}
_ => (),
}
}

let mut events = events.into_iter();

// emit everything up to summary
cmark::html::push_html(&mut html, events.by_ref().take(continue_reading));

if has_summary {
// remove footnotes
let summary_html = FOOTNOTES_RE.replace_all(&html, "").into_owned();
summary = Some(summary_html)
let mut summary_html = FOOTNOTES_RE.replace_all(&html, "").into_owned();

// truncate trailing whitespace
summary_html.truncate(summary_html.trim_end().len());

// add cutoff template
if !tags.is_empty() {
let mut c = tera::Context::new();
c.insert("summary", &summary_html);
c.insert("lang", &context.lang);
let summary_cutoff = utils::templates::render_template(
SUMMARY_CUTOFF_TEMPLATE,
&context.tera,
c,
&None,
)
.context("Failed to render summary cutoff template")?;
summary_html.push_str(&summary_cutoff);
}

// close remaining tags
cmark::html::push_html(&mut summary_html, tags.into_iter().rev().map(Event::End));

summary = Some(summary_html);
}

// emit everything after summary
Expand All @@ -820,6 +858,7 @@ mod tests {
use super::*;
use config::Config;
use insta::assert_snapshot;
use templates::ZOLA_TERA;

#[test]
fn insert_many_works() {
Expand Down Expand Up @@ -875,7 +914,8 @@ mod tests {
let mores =
["<!-- more -->", "<!--more-->", "<!-- MORE -->", "<!--MORE-->", "<!--\t MoRe \t-->"];
let config = Config::default();
let context = RenderContext::from_config(&config);
let mut context = RenderContext::from_config(&config);
context.tera.to_mut().extend(&ZOLA_TERA).unwrap();
for more in mores {
let content = format!("{top}\n\n{more}\n\n{bottom}");
let rendered = markdown_to_html(&content, &context, vec![]).unwrap();
Expand Down
19 changes: 19 additions & 0 deletions components/markdown/tests/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,25 @@ fn can_customise_anchor_template() {
insta::assert_snapshot!(body);
}

#[test]
fn can_customise_summary_template() {
let mut tera = Tera::default();
tera.extend(&ZOLA_TERA).unwrap();
tera.add_raw_template("summary-cutoff.html", " (in {{ lang }})").unwrap();
let permalinks_ctx = HashMap::new();
let config = Config::default_for_test();
let context = RenderContext::new(
&tera,
&config,
&config.default_language,
"",
&permalinks_ctx,
InsertAnchor::Right,
);
let summary = render_content("Hello <!-- more --> World!", &context).unwrap().summary.unwrap();
insta::assert_snapshot!(summary);
}

#[test]
fn can_use_smart_punctuation() {
let mut config = Config::default_for_test();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: components/markdown/tests/markdown.rs
expression: summary
---
<p>Hello (in en)</p>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: components/markdown/tests/summary.rs
expression: body
---
<p>Things to do:</p>
<ul>
<li>Program&hellip;
</li>
</ul>
7 changes: 3 additions & 4 deletions components/markdown/tests/summary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,16 @@ And some content after
}

#[test]
fn no_truncated_summary() {
let rendered = get_rendered(
fn truncated_summary() {
let body = get_summary(
r#"
Things to do:
* Program <!-- more --> something
* Eat
* Sleep
"#,
);
assert!(rendered.summary.is_none());
insta::assert_snapshot!(rendered.body);
insta::assert_snapshot!(body);
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions components/templates/src/builtins/summary-cutoff.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% if summary is matching("\PP$") %}&hellip;{% endif %}
1 change: 1 addition & 0 deletions components/templates/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub static ZOLA_TERA: Lazy<Tera> = Lazy::new(|| {
include_str!("builtins/split_sitemap_index.xml"),
),
("__zola_builtins/anchor-link.html", include_str!("builtins/anchor-link.html")),
("__zola_builtins/summary-cutoff.html", include_str!("builtins/summary-cutoff.html")),
("internal/alias.html", include_str!("builtins/internal/alias.html")),
])
.unwrap();
Expand Down
4 changes: 4 additions & 0 deletions docs/content/documentation/content/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,7 @@ available separately in the

A span element in this position with a `continue-reading` id is created, so you can link directly to it if needed. For example:
`<a href="{{ page.permalink }}#continue-reading">Continue Reading</a>`.

The `<!-- more -->` marker can also exist in the middle of a line, and it will ensure that this does not emit unclosed HTML tags.
You can use the `summary-cutoff.html` to show an ellipsis or other text after the summary (but before these closing tags) based
upon the summary before the cutoff. By default, it will show an ellipsis (…) if the summary does not end in any punctuation.