From ef543b3d2b63f18d1f99e9d35bbcdc1fa11a416a Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Mon, 7 May 2018 21:03:51 +0200 Subject: [PATCH] Make co-located asset link permalinks --- components/front_matter/Cargo.toml | 1 - components/rendering/src/markdown.rs | 47 ++++++++++++++++---------- components/rendering/tests/markdown.rs | 31 +++++++++++++++++ 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/components/front_matter/Cargo.toml b/components/front_matter/Cargo.toml index 7a95233..76c6a9f 100644 --- a/components/front_matter/Cargo.toml +++ b/components/front_matter/Cargo.toml @@ -12,5 +12,4 @@ toml = "0.4" regex = "1" lazy_static = "1" - errors = { path = "../errors" } diff --git a/components/rendering/src/markdown.rs b/components/rendering/src/markdown.rs index 4773274..de580e2 100644 --- a/components/rendering/src/markdown.rs +++ b/components/rendering/src/markdown.rs @@ -30,10 +30,15 @@ fn find_anchor(anchors: &[String], name: String, level: u8) -> String { find_anchor(anchors, name, level + 1) } +fn is_colocated_asset_link(link: &str) -> bool { + !link.contains("/") // http://, ftp://, ../ etc + && !link.starts_with("mailto:") +} + pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<(String, Vec
)> { // the rendered html - let mut html = String::new(); + let mut html = String::with_capacity(content.len()); // Set while parsing let mut error = None; @@ -104,29 +109,37 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<(Strin Event::Html(Owned("".to_string())) }, // Need to handle relative links - Event::Start(Tag::Link(ref link, ref title)) => { - if in_header { - if !title.is_empty() { - temp_header.push(&format!("", link, title)); - } else { - temp_header.push(&format!("", link)); - } - return Event::Html(Owned(String::new())); - } - - if link.starts_with("./") { - match resolve_internal_link(link, context.permalinks) { - Ok(url) => { - return Event::Start(Tag::Link(Owned(url), title.clone())); - }, + Event::Start(Tag::Link(link, title)) => { + // A few situations here: + // - it could be a relative link (starting with `./`) + // - it could be a link to a co-located asset + // - it could be a normal link + // - any of those can be in a header or not: if it's in a header we need to append to a string + let fixed_link = if link.starts_with("./") { + match resolve_internal_link(&link, context.permalinks) { + Ok(url) => url, Err(_) => { error = Some(format!("Relative link {} not found.", link).into()); return Event::Html(Owned(String::new())); } + } + } else if is_colocated_asset_link(&link) { + format!("{}{}", context.current_page_permalink, link) + } else { + link.to_string() + }; + + if in_header { + let html = if title.is_empty() { + format!("", fixed_link) + } else { + format!("", fixed_link, title) }; + temp_header.push(&html); + return Event::Html(Owned(String::new())); } - Event::Start(Tag::Link(link.clone(), title.clone())) + Event::Start(Tag::Link(Owned(fixed_link), title)) }, Event::End(Tag::Link(_, _)) => { if in_header { diff --git a/components/rendering/tests/markdown.rs b/components/rendering/tests/markdown.rs index 3c66f02..f6eb938 100644 --- a/components/rendering/tests/markdown.rs +++ b/components/rendering/tests/markdown.rs @@ -473,3 +473,34 @@ fn can_understand_link_with_title_in_header() { "

Rust

\n" ); } + +#[test] +fn can_make_valid_relative_link_in_header() { + let mut permalinks = HashMap::new(); + permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about/".to_string()); + let tera_ctx = Tera::default(); + let config = Config::default(); + let context = RenderContext::new(&tera_ctx, &config, "", &permalinks, InsertAnchor::None); + let res = render_content( + r#" # [rel link](./pages/about.md)"#, + &context + ).unwrap(); + + assert_eq!( + res.0, + "

rel link

\n" + ); +} + + +#[test] +fn can_make_permalinks_with_colocated_assets() { + let permalinks_ctx = HashMap::new(); + let config = Config::default(); + let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None); + let res = render_content("[an image](image.jpg)", &context).unwrap(); + assert_eq!( + res.0, + "

an image

\n" + ); +}