|
|
@@ -1,4 +1,5 @@ |
|
|
|
use pulldown_cmark as cmark; |
|
|
|
use regex::Regex; |
|
|
|
use slug::slugify; |
|
|
|
use syntect::easy::HighlightLines; |
|
|
|
use syntect::html::{ |
|
|
@@ -60,11 +61,31 @@ fn find_anchor(anchors: &[String], name: String, level: u8) -> String { |
|
|
|
find_anchor(anchors, name, level + 1) |
|
|
|
} |
|
|
|
|
|
|
|
// Returns whether the given string starts with a schema. |
|
|
|
// |
|
|
|
// Although there exists [a list of registered URI schemes][uri-schemes], a link may use arbitrary, |
|
|
|
// private schemes. This function checks if the given string starts with something that just looks |
|
|
|
// like a scheme, i.e., a case-insensitive identifier followed by a colon. |
|
|
|
// |
|
|
|
// [uri-schemes]: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml |
|
|
|
fn starts_with_schema(s: &str) -> bool { |
|
|
|
lazy_static! { |
|
|
|
static ref PATTERN: Regex = Regex::new(r"^[0-9A-Za-z\-]+:").unwrap(); |
|
|
|
} |
|
|
|
|
|
|
|
PATTERN.is_match(s) |
|
|
|
} |
|
|
|
|
|
|
|
// Colocated asset links refers to the files in the same directory, |
|
|
|
// there it should be a filename only |
|
|
|
fn is_colocated_asset_link(link: &str) -> bool { |
|
|
|
!link.contains('/') // http://, ftp://, ../ etc |
|
|
|
&& !link.starts_with("mailto:") |
|
|
|
&& !starts_with_schema(link) |
|
|
|
} |
|
|
|
|
|
|
|
// Returns whether a link starts with an HTTP(s) scheme. |
|
|
|
fn is_external_link(link: &str) -> bool { |
|
|
|
link.starts_with("http:") || link.starts_with("https:") |
|
|
|
} |
|
|
|
|
|
|
|
fn fix_link( |
|
|
@@ -103,7 +124,7 @@ fn fix_link( |
|
|
|
} else if is_colocated_asset_link(&link) { |
|
|
|
format!("{}{}", context.current_page_permalink, link) |
|
|
|
} else { |
|
|
|
if !link.starts_with('#') && !link.starts_with("mailto:") { |
|
|
|
if is_external_link(link) { |
|
|
|
external_links.push(link.to_owned()); |
|
|
|
} |
|
|
|
link.to_string() |
|
|
@@ -328,3 +349,41 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<Render |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
mod tests { |
|
|
|
use super::*; |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_starts_with_schema() { |
|
|
|
// registered |
|
|
|
assert!(starts_with_schema("https://example.com/")); |
|
|
|
assert!(starts_with_schema("ftp://example.com/")); |
|
|
|
assert!(starts_with_schema("mailto:user@example.com")); |
|
|
|
assert!(starts_with_schema("xmpp:node@example.com")); |
|
|
|
assert!(starts_with_schema("tel:18008675309")); |
|
|
|
assert!(starts_with_schema("sms:18008675309")); |
|
|
|
assert!(starts_with_schema("h323:user@example.com")); |
|
|
|
|
|
|
|
// arbitrary |
|
|
|
assert!(starts_with_schema("zola:post?content=hi")); |
|
|
|
|
|
|
|
// case-insensitive |
|
|
|
assert!(starts_with_schema("MailTo:user@example.com")); |
|
|
|
assert!(starts_with_schema("MAILTO:user@example.com")); |
|
|
|
} |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_is_external_link() { |
|
|
|
assert!(is_external_link("http://example.com/")); |
|
|
|
assert!(is_external_link("https://example.com/")); |
|
|
|
assert!(is_external_link("https://example.com/index.html#introduction")); |
|
|
|
|
|
|
|
assert!(!is_external_link("mailto:user@example.com")); |
|
|
|
assert!(!is_external_link("tel:18008675309")); |
|
|
|
|
|
|
|
assert!(!is_external_link("#introduction")); |
|
|
|
|
|
|
|
assert!(!is_external_link("http.jpg")) |
|
|
|
} |
|
|
|
} |