diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd926b..cd33217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,3 +6,4 @@ - Add sections to the index page context - Fix page rendering not working when containing `+++` - Add shortcodes (see README for details) +- Allow relative links to other content in markdown links diff --git a/README.md b/README.md index 791226d..2d5b9b6 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,14 @@ built-in: A gallery containing lots of themes at https://tmtheme-editor.herokuapp.com/#!/editor/theme/Agola%20Dark. More themes can be easily added to gutenberg, just make a PR with the wanted theme. +### Internal links +You can have internal links in your markdown that will be replaced with the full URL when rendering. +To do so, use the normal markdown link syntax, start the link with `./` and point to the `.md` file you want +to link to. The path to the file starts from the `content` directory. + +For example, linking to a file located at `content/pages/about.md` would be `[my link](./pages/about.md). + + ### Shortcodes Gutenberg uses markdown for content but sometimes you want to insert some HTML, for example for a YouTube video. Rather than copy/pasting the HTML around, Gutenberg supports shortcodes, allowing you to define templates using Tera and call those templates inside markdown. diff --git a/src/markdown.rs b/src/markdown.rs index c11e470..0f75694 100644 --- a/src/markdown.rs +++ b/src/markdown.rs @@ -204,6 +204,22 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap, ter highlighter = None; Event::Html(Owned("".to_owned())) }, + // Need to handle relative links + Event::Start(Tag::Link(ref link, ref title)) => { + if link.starts_with("./") { + let permalink = match permalinks.get(&link.replacen("./", "", 1)) { + Some(p) => p, + None => { + error = Some(format!("Relative link {} not found.", link).into()); + return Event::Html(Owned("".to_string())); + } + }; + return Event::Start(Tag::Link(Owned(permalink.clone()), title.clone())); + } + + return Event::Start(Tag::Link(link.clone(), title.clone())); + }, + // need to know when we are in a code block to disable shortcodes in them Event::Start(Tag::Code) => { in_code_block = true; event @@ -212,6 +228,7 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap, ter in_code_block = false; event }, + // If we added shortcodes, don't close a paragraph since there's none Event::End(Tag::Paragraph) => { if added_shortcode { added_shortcode = false; @@ -219,6 +236,7 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap, ter } event }, + // Ignore softbreaks inside shortcodes Event::SoftBreak => { if shortcode_block.is_some() { return Event::Html(Owned("".to_owned())); @@ -369,4 +387,33 @@ A quote "#, &HashMap::new(), &tera, &Config::default()).unwrap(); assert_eq!(res, "

Hello\n

A quote - Keats
"); } + + #[test] + fn test_markdown_to_html_unknown_shortcode() { + let res = markdown_to_html("{{ hello(flash=true) }}", &HashMap::new(), &Tera::default(), &Config::default()); + assert!(res.is_err()); + } + + #[test] + fn test_markdown_to_html_relative_link_exists() { + let mut permalinks = HashMap::new(); + permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string()); + let res = markdown_to_html( + r#"[rel link](./pages/about.md), [abs link](https://vincent.is/about)"#, + &permalinks, + &GUTENBERG_TERA, + &Config::default() + ).unwrap(); + + assert!( + res.contains(r#"

rel link, abs link

"#) + ); + } + + #[test] + fn test_markdown_to_html_relative_link_inexistant() { + let res = markdown_to_html("[rel link](./pages/about.md)", &HashMap::new(), &Tera::default(), &Config::default()); + assert!(res.is_err()); + } + }