From c069bfdafadf38cb39fd3b5d81298460b8052d3a Mon Sep 17 00:00:00 2001
From: Thomas Hurst
Date: Wed, 22 Aug 2018 17:34:32 +0100
Subject: [PATCH 1/5] Rework summary handling.
Push summary handling into Markdown parsing, identifying the presence
of one by giving its length in the rendered markup.
Hopefully a better fix for #376.
---
components/content/src/page.rs | 19 +++++-----------
components/content/src/section.rs | 4 ++--
components/rendering/src/lib.rs | 2 +-
components/rendering/src/markdown.rs | 33 ++++++++++++++++++++--------
4 files changed, 33 insertions(+), 25 deletions(-)
diff --git a/components/content/src/page.rs b/components/content/src/page.rs
index 3a0bf066..4162d6d3 100644
--- a/components/content/src/page.rs
+++ b/components/content/src/page.rs
@@ -185,19 +185,12 @@ impl Page {
context.tera_context.add("page", self);
- let res = render_content(
- &self.raw_content.replacen("", "", 1),
- &context,
- ).chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?;
- self.content = res.0;
- self.toc = res.1;
- if self.raw_content.contains("") {
- self.summary = Some({
- let summary = self.raw_content.splitn(2, "").collect::>()[0];
- render_content(summary, &context)
- .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?.0
- })
- }
+ let res = render_content(&self.raw_content, &context)
+ .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?;
+
+ self.summary = res.summary_len.map(|l| res.body[0..l].to_owned());
+ self.content = res.body;
+ self.toc = res.toc;
Ok(())
}
diff --git a/components/content/src/section.rs b/components/content/src/section.rs
index dcff1f5c..07ddde2b 100644
--- a/components/content/src/section.rs
+++ b/components/content/src/section.rs
@@ -137,8 +137,8 @@ impl Section {
let res = render_content(&self.raw_content, &context)
.chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?;
- self.content = res.0;
- self.toc = res.1;
+ self.content = res.body;
+ self.toc = res.toc;
Ok(())
}
diff --git a/components/rendering/src/lib.rs b/components/rendering/src/lib.rs
index 9e6d7257..acc08953 100644
--- a/components/rendering/src/lib.rs
+++ b/components/rendering/src/lib.rs
@@ -32,7 +32,7 @@ pub use table_of_contents::Header;
pub use shortcode::render_shortcodes;
pub use context::RenderContext;
-pub fn render_content(content: &str, context: &RenderContext) -> Result<(String, Vec)> {
+pub fn render_content(content: &str, context: &RenderContext) -> Result {
// Don't do anything if there is nothing like a shortcode in the content
if content.contains("{{") || content.contains("{%") {
let rendered = render_shortcodes(content, context)?;
diff --git a/components/rendering/src/markdown.rs b/components/rendering/src/markdown.rs
index 56bea619..a9c3b3e6 100644
--- a/components/rendering/src/markdown.rs
+++ b/components/rendering/src/markdown.rs
@@ -1,4 +1,4 @@
-use std::borrow::Cow::Owned;
+use std::borrow::Cow::{Owned, Borrowed};
use pulldown_cmark as cmark;
use self::cmark::{Parser, Event, Tag, Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
@@ -14,6 +14,14 @@ use link_checker::check_url;
use table_of_contents::{TempHeader, Header, make_table_of_contents};
use context::RenderContext;
+const CONTINUE_READING: &str = "
\n";
+
+pub struct Rendered {
+ pub body: String,
+ pub summary_len: Option,
+ pub toc: Vec
+}
+
// We might have cases where the slug is already present in our list of anchor
// for example an article could have several titles named Example
// We add a counter after the slug if the slug is already present, which
@@ -36,8 +44,7 @@ fn is_colocated_asset_link(link: &str) -> bool {
&& !link.starts_with("mailto:")
}
-
-pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<(String, Vec)> {
+pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result {
// the rendered html
let mut html = String::with_capacity(content.len());
// Set while parsing
@@ -57,6 +64,7 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<(Strin
let mut temp_header = TempHeader::default();
let mut opts = Options::empty();
+ let mut has_summary = false;
opts.insert(OPTION_ENABLE_TABLES);
opts.insert(OPTION_ENABLE_FOOTNOTES);
@@ -208,6 +216,10 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<(Strin
temp_header = TempHeader::default();
Event::Html(Owned(val))
}
+ Event::Html(ref markup) if markup.contains("") => {
+ has_summary = true;
+ Event::Html(Borrowed(CONTINUE_READING))
+ }
_ => event,
}
});
@@ -215,11 +227,14 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<(Strin
cmark::html::push_html(&mut html, parser);
}
- match error {
- Some(e) => Err(e),
- None => Ok((
- html.replace("", "").replace("
", ""),
- make_table_of_contents(&headers)
- )),
+ if let Some(e) = error {
+ return Err(e)
+ } else {
+ html = html.replace("", "").replace("", "");
+ Ok(Rendered {
+ summary_len: if has_summary { html.find(CONTINUE_READING) } else { None },
+ body: html,
+ toc: make_table_of_contents(&headers)
+ })
}
}
From f2f3bed0804994fa90f9ad888ecd8ab753845b5b Mon Sep 17 00:00:00 2001
From: Thomas Hurst
Date: Fri, 24 Aug 2018 17:40:26 +0100
Subject: [PATCH 2/5] Markdown parsing: prefer Borrowed over Owned where
possible
As mentioned in #376
---
components/rendering/src/markdown.rs | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/components/rendering/src/markdown.rs b/components/rendering/src/markdown.rs
index a9c3b3e6..d7413b04 100644
--- a/components/rendering/src/markdown.rs
+++ b/components/rendering/src/markdown.rs
@@ -76,7 +76,7 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result Result or other things already there
temp_header.title += &text;
header_created = true;
- return Event::Html(Owned(String::new()));
+ return Event::Html(Borrowed(""));
}
// if we are in the middle of a code block
@@ -101,7 +101,7 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result {
if !context.config.highlight_code {
- return Event::Html(Owned("".to_string()));
+ return Event::Html(Borrowed(""));
}
let theme = &THEME_SET.themes[&context.config.highlight_theme];
@@ -109,7 +109,7 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result highlighter = Some(h),
Err(err) => {
error = Some(format!("Could not load syntax: {}", err).into());
- return Event::Html(Owned(String::new()));
+ return Event::Html(Borrowed(""));
}
}
let snippet = start_coloured_html_snippet(theme);
@@ -117,11 +117,11 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result {
if !context.config.highlight_code {
- return Event::Html(Owned("
\n".to_string()));
+ return Event::Html(Borrowed("
\n"));
}
// reset highlight and close the code block
highlighter = None;
- Event::Html(Owned("".to_string()))
+ Event::Html(Borrowed(""))
}
Event::Start(Tag::Image(src, title)) => {
if is_colocated_asset_link(&src) {
@@ -147,7 +147,7 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result url,
Err(_) => {
error = Some(format!("Relative link {} not found.", link).into());
- return Event::Html(Owned(String::new()));
+ return Event::Html(Borrowed(""));
}
}
} else if is_colocated_asset_link(&link) {
@@ -175,7 +175,7 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result", fixed_link, title)
};
temp_header.push(&html);
- return Event::Html(Owned(String::new()));
+ return Event::Html(Borrowed(""));
}
Event::Start(Tag::Link(Owned(fixed_link), title))
@@ -183,28 +183,28 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result {
if in_header {
temp_header.push("");
- return Event::Html(Owned(String::new()));
+ return Event::Html(Borrowed(""));
}
event
}
Event::Start(Tag::Code) => {
if in_header {
temp_header.push("");
- return Event::Html(Owned(String::new()));
+ return Event::Html(Borrowed(""));
}
event
}
Event::End(Tag::Code) => {
if in_header {
temp_header.push("
");
- return Event::Html(Owned(String::new()));
+ return Event::Html(Borrowed(""));
}
event
}
Event::Start(Tag::Header(num)) => {
in_header = true;
temp_header = TempHeader::new(num);
- Event::Html(Owned(String::new()))
+ Event::Html(Borrowed(""))
}
Event::End(Tag::Header(_)) => {
// End of a header, reset all the things and return the stringified
From 5f1f9efe7a0c0e49e6a47d64a2d8e2e900310364 Mon Sep 17 00:00:00 2001
From: Thomas Hurst
Date: Fri, 24 Aug 2018 22:37:39 +0100
Subject: [PATCH 3/5] Derive debug for markdown::Rendered
---
components/rendering/src/markdown.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/rendering/src/markdown.rs b/components/rendering/src/markdown.rs
index d7413b04..e7468db6 100644
--- a/components/rendering/src/markdown.rs
+++ b/components/rendering/src/markdown.rs
@@ -16,6 +16,7 @@ use context::RenderContext;
const CONTINUE_READING: &str = "
\n";
+#[derive(Debug)]
pub struct Rendered {
pub body: String,
pub summary_len: Option,
From c53c4037900ec484519ee8169477f3d3ac2bceb5 Mon Sep 17 00:00:00 2001
From: Thomas Hurst
Date: Fri, 24 Aug 2018 22:37:55 +0100
Subject: [PATCH 4/5] Update rendering tests
---
components/rendering/tests/markdown.rs | 76 +++++++++++++-------------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/components/rendering/tests/markdown.rs b/components/rendering/tests/markdown.rs
index 93e6f646..a3969513 100644
--- a/components/rendering/tests/markdown.rs
+++ b/components/rendering/tests/markdown.rs
@@ -22,7 +22,7 @@ fn can_do_render_content_simple() {
let config = Config::default();
let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, Path::new("something"), InsertAnchor::None);
let res = render_content("hello", &context).unwrap();
- assert_eq!(res.0, "hello
\n");
+ assert_eq!(res.body, "hello
\n");
}
#[test]
@@ -34,7 +34,7 @@ fn doesnt_highlight_code_block_with_highlighting_off() {
let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, Path::new("something"), InsertAnchor::None);
let res = render_content("```\n$ gutenberg server\n```", &context).unwrap();
assert_eq!(
- res.0,
+ res.body,
"$ gutenberg server\n
\n"
);
}
@@ -47,7 +47,7 @@ fn can_highlight_code_block_no_lang() {
let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, Path::new("something"), InsertAnchor::None);
let res = render_content("```\n$ gutenberg server\n$ ping\n```", &context).unwrap();
assert_eq!(
- res.0,
+ res.body,
"\n$ gutenberg server\n$ ping\n
"
);
}
@@ -60,7 +60,7 @@ fn can_highlight_code_block_with_lang() {
let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, Path::new("something"), InsertAnchor::None);
let res = render_content("```python\nlist.append(1)\n```", &context).unwrap();
assert_eq!(
- res.0,
+ res.body,
"\nlist.append(1)\n
"
);
}
@@ -74,7 +74,7 @@ fn can_higlight_code_block_with_unknown_lang() {
let res = render_content("```yolo\nlist.append(1)\n```", &context).unwrap();
// defaults to plain text
assert_eq!(
- res.0,
+ res.body,
"\nlist.append(1)\n
"
);
}
@@ -89,8 +89,8 @@ Hello
{{ youtube(id="ub36ffWAqgQ") }}
"#, &context).unwrap();
- assert!(res.0.contains("Hello
\n"));
- assert!(res.0.contains(r#"