parent
769264e3e5
commit
51784aa60f
@ -10,6 +10,7 @@
|
||||
- Shorcodes and `anchor-link.html` can now access the `lang` context
|
||||
- Add prompt before replacing the output directory with `zola build` if the `output-dir` flag is given
|
||||
- Shortcode handling has been completely rewritten, solving many issues
|
||||
- Also add internal links starting with `#` without any internal Zola link
|
||||
|
||||
## 0.14.1 (2021-08-24)
|
||||
|
||||
|
@ -236,7 +236,7 @@ impl Page {
|
||||
anchor_insert,
|
||||
);
|
||||
context.set_shortcode_definitions(shortcode_definitions);
|
||||
|
||||
context.set_current_page_path(&self.file.relative);
|
||||
context.tera_context.insert("page", &SerializingPage::from_page_basic(self, None));
|
||||
|
||||
let res = render_content(&self.raw_content, &context).map_err(|e| {
|
||||
|
@ -10,7 +10,7 @@ use front_matter::{split_section_content, SectionFrontMatter};
|
||||
use rendering::{render_content, Heading, RenderContext};
|
||||
use utils::fs::read_file;
|
||||
use utils::site::get_reading_analytics;
|
||||
use utils::templates::render_template;
|
||||
use utils::templates::{render_template, ShortcodeDefinition};
|
||||
|
||||
use crate::content::file_info::FileInfo;
|
||||
use crate::content::ser::SerializingSection;
|
||||
@ -147,6 +147,7 @@ impl Section {
|
||||
permalinks: &HashMap<String, String>,
|
||||
tera: &Tera,
|
||||
config: &Config,
|
||||
shortcode_definitions: &HashMap<String, ShortcodeDefinition>,
|
||||
) -> Result<()> {
|
||||
let mut context = RenderContext::new(
|
||||
tera,
|
||||
@ -156,7 +157,8 @@ impl Section {
|
||||
permalinks,
|
||||
self.meta.insert_anchor_links,
|
||||
);
|
||||
|
||||
context.set_shortcode_definitions(shortcode_definitions);
|
||||
context.set_current_page_path(&self.file.relative);
|
||||
context.tera_context.insert("section", &SerializingSection::from_section_basic(self, None));
|
||||
|
||||
let res = render_content(&self.raw_content, &context).map_err(|e| {
|
||||
|
@ -12,6 +12,7 @@ pub struct RenderContext<'a> {
|
||||
pub tera: Cow<'a, Tera>,
|
||||
pub config: &'a Config,
|
||||
pub tera_context: Context,
|
||||
pub current_page_path: Option<&'a str>,
|
||||
pub current_page_permalink: &'a str,
|
||||
pub permalinks: Cow<'a, HashMap<String, String>>,
|
||||
pub insert_anchor: InsertAnchor,
|
||||
@ -35,6 +36,7 @@ impl<'a> RenderContext<'a> {
|
||||
Self {
|
||||
tera: Cow::Borrowed(tera),
|
||||
tera_context,
|
||||
current_page_path: None,
|
||||
current_page_permalink,
|
||||
permalinks: Cow::Borrowed(permalinks),
|
||||
insert_anchor,
|
||||
@ -50,6 +52,11 @@ impl<'a> RenderContext<'a> {
|
||||
self.shortcode_definitions = Cow::Borrowed(def);
|
||||
}
|
||||
|
||||
/// Same as above
|
||||
pub fn set_current_page_path(&mut self, path: &'a str) {
|
||||
self.current_page_path = Some(path);
|
||||
}
|
||||
|
||||
// In use in the markdown filter
|
||||
// NOTE: This RenderContext is not i18n-aware, see MarkdownFilter::filter for details
|
||||
// If this function is ever used outside of MarkdownFilter, take this into consideration
|
||||
@ -57,6 +64,7 @@ impl<'a> RenderContext<'a> {
|
||||
Self {
|
||||
tera: Cow::Owned(Tera::default()),
|
||||
tera_context: Context::new(),
|
||||
current_page_path: None,
|
||||
current_page_permalink: "",
|
||||
permalinks: Cow::Owned(HashMap::new()),
|
||||
insert_anchor: InsertAnchor::None,
|
||||
|
@ -10,6 +10,7 @@ use errors::Result;
|
||||
|
||||
pub use context::RenderContext;
|
||||
use markdown::markdown_to_html;
|
||||
pub use markdown::Rendered;
|
||||
pub use table_of_contents::Heading;
|
||||
|
||||
pub fn render_content(content: &str, context: &RenderContext) -> Result<markdown::Rendered> {
|
||||
|
@ -92,9 +92,20 @@ fn fix_link(
|
||||
} else {
|
||||
if is_external_link(link) {
|
||||
external_links.push(link.to_owned());
|
||||
link.to_owned()
|
||||
} else if link.starts_with("#") {
|
||||
// local anchor without the internal zola path
|
||||
if let Some(current_path) = context.current_page_path {
|
||||
internal_links.push((current_path.to_owned(), Some(link[1..].to_owned())));
|
||||
format!("{}{}", context.current_page_permalink, &link)
|
||||
} else {
|
||||
link.to_string()
|
||||
}
|
||||
} else {
|
||||
link.to_string()
|
||||
}
|
||||
link.to_string()
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@ -121,8 +132,7 @@ fn get_heading_refs(events: &[Event]) -> Vec<HeadingRef> {
|
||||
heading_refs.push(HeadingRef::new(i, *level));
|
||||
}
|
||||
Event::End(Tag::Heading(_)) => {
|
||||
let msg = "Heading end before start?";
|
||||
heading_refs.last_mut().expect(msg).end_idx = i;
|
||||
heading_refs.last_mut().expect("Heading end before start?").end_idx = i;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -1,82 +1,62 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use errors::Result;
|
||||
use rendering::Rendered;
|
||||
|
||||
mod common;
|
||||
|
||||
macro_rules! test_links {
|
||||
(
|
||||
$in_str:literal,
|
||||
[$($id:literal => $perma_link:literal),*],
|
||||
[$($abs_path:literal),*],
|
||||
[$($rel_path:literal:$opt_anchor:expr),*],
|
||||
[$($shortcodes:ident),*]
|
||||
) => {
|
||||
let config = config::Config::default_for_test();
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut tera = tera::Tera::default();
|
||||
|
||||
// Add all shortcodes
|
||||
$(
|
||||
tera.add_raw_template(
|
||||
&format!("shortcodes/{}", $shortcodes.filename()),
|
||||
$shortcodes.output
|
||||
).expect("Failed to add raw template");
|
||||
)*
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut permalinks = std::collections::HashMap::new();
|
||||
|
||||
$(
|
||||
permalinks.insert($id.to_string(), $perma_link.to_string());
|
||||
)*
|
||||
|
||||
let context = rendering::RenderContext::new(
|
||||
&tera,
|
||||
&config,
|
||||
&config.default_language,
|
||||
"",
|
||||
&permalinks,
|
||||
front_matter::InsertAnchor::None,
|
||||
);
|
||||
|
||||
let rendered = rendering::render_content($in_str, &context);
|
||||
assert!(rendered.is_ok(), "Rendering failed");
|
||||
|
||||
let rendered = rendered.unwrap();
|
||||
|
||||
let asserted_int_links = vec![
|
||||
$(
|
||||
($rel_path.to_string(), $opt_anchor.map(|x| x.to_string()))
|
||||
),*
|
||||
];
|
||||
let asserted_ext_links: Vec<&str> = vec![$($abs_path),*];
|
||||
|
||||
assert_eq!(rendered.internal_links, asserted_int_links, "Internal links unequal");
|
||||
assert_eq!(rendered.external_links, asserted_ext_links, "External links unequal");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_internal() {
|
||||
test_links!("Hello World!", [], [], [], []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn absolute_links() {
|
||||
test_links!("[abc](https://google.com/)", [], ["https://google.com/"], [], []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn relative_links() {
|
||||
test_links!(
|
||||
"[abc](@/def/123.md)",
|
||||
["def/123.md" => "https://xyz.com/def/123"],
|
||||
[],
|
||||
["def/123.md":<Option<&str>>::None],
|
||||
[]
|
||||
fn render_content(content: &str, permalinks: HashMap<String, String>) -> Result<Rendered> {
|
||||
let config = config::Config::default_for_test();
|
||||
let tera = tera::Tera::default();
|
||||
let mut context = rendering::RenderContext::new(
|
||||
&tera,
|
||||
&config,
|
||||
&config.default_language,
|
||||
"http://mypage.com",
|
||||
&permalinks,
|
||||
front_matter::InsertAnchor::None,
|
||||
);
|
||||
context.set_current_page_path("mine.md");
|
||||
|
||||
rendering::render_content(content, &context)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn relative_links_no_perma() {
|
||||
test_links!("[abc](@/def/123.md)", [], [], ["def/123.md": <Option<&str>>::None], []);
|
||||
fn can_detect_links() {
|
||||
// no links
|
||||
let rendered = render_content("Hello World!", HashMap::new()).unwrap();
|
||||
assert_eq!(rendered.internal_links.len(), 0);
|
||||
assert_eq!(rendered.external_links.len(), 0);
|
||||
|
||||
// external
|
||||
let rendered = render_content("[abc](https://google.com/)", HashMap::new()).unwrap();
|
||||
assert_eq!(rendered.internal_links.len(), 0);
|
||||
assert_eq!(rendered.external_links.len(), 1);
|
||||
assert_eq!(rendered.external_links[0], "https://google.com/");
|
||||
|
||||
// internal
|
||||
let mut permalinks = HashMap::new();
|
||||
permalinks.insert("def/123.md".to_owned(), "https://xyz.com/def/123".to_owned());
|
||||
let rendered = render_content("[abc](@/def/123.md)", permalinks).unwrap();
|
||||
assert_eq!(rendered.internal_links.len(), 1);
|
||||
assert_eq!(rendered.internal_links[0], ("def/123.md".to_owned(), None));
|
||||
assert_eq!(rendered.external_links.len(), 0);
|
||||
|
||||
// internal with anchors
|
||||
let mut permalinks = HashMap::new();
|
||||
permalinks.insert("def/123.md".to_owned(), "https://xyz.com/def/123".to_owned());
|
||||
let rendered = render_content("[abc](@/def/123.md#hello)", permalinks).unwrap();
|
||||
assert_eq!(rendered.internal_links.len(), 1);
|
||||
assert_eq!(rendered.internal_links[0], ("def/123.md".to_owned(), Some("hello".to_owned())));
|
||||
assert_eq!(rendered.external_links.len(), 0);
|
||||
|
||||
// internal link referring to self
|
||||
let rendered = render_content("[abc](#hello)", HashMap::new()).unwrap();
|
||||
assert_eq!(rendered.internal_links.len(), 1);
|
||||
assert_eq!(rendered.internal_links[0], ("mine.md".to_owned(), Some("hello".to_owned())));
|
||||
assert_eq!(rendered.external_links.len(), 0);
|
||||
|
||||
// Not pointing to anything so that's an error
|
||||
let res = render_content("[abc](@/def/123.md)", HashMap::new());
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
@ -380,7 +380,9 @@ impl Site {
|
||||
.values_mut()
|
||||
.collect::<Vec<_>>()
|
||||
.par_iter_mut()
|
||||
.map(|section| section.render_markdown(permalinks, tera, config))
|
||||
.map(|section| {
|
||||
section.render_markdown(permalinks, tera, config, &self.shortcode_definitions)
|
||||
})
|
||||
.collect::<Result<()>>()?;
|
||||
|
||||
Ok(())
|
||||
@ -426,7 +428,12 @@ impl Site {
|
||||
pub fn add_section(&mut self, mut section: Section, render_md: bool) -> Result<()> {
|
||||
self.permalinks.insert(section.file.relative.clone(), section.permalink.clone());
|
||||
if render_md {
|
||||
section.render_markdown(&self.permalinks, &self.tera, &self.config)?;
|
||||
section.render_markdown(
|
||||
&self.permalinks,
|
||||
&self.tera,
|
||||
&self.config,
|
||||
&self.shortcode_definitions,
|
||||
)?;
|
||||
}
|
||||
let mut library = self.library.write().expect("Get lock for add_section");
|
||||
library.remove_section(§ion.file.path);
|
||||
@ -847,7 +854,13 @@ impl Site {
|
||||
if taxonomy.kind.is_paginated() {
|
||||
self.render_paginated(
|
||||
comp.clone(),
|
||||
&Paginator::from_taxonomy(taxonomy, item, &library, &self.tera, &self.config.theme),
|
||||
&Paginator::from_taxonomy(
|
||||
taxonomy,
|
||||
item,
|
||||
&library,
|
||||
&self.tera,
|
||||
&self.config.theme,
|
||||
),
|
||||
)?;
|
||||
} else {
|
||||
let single_output =
|
||||
|
Loading…
Reference in New Issue
Block a user