Skip to content

Commit

Permalink
Merge pull request #461 from kivikakk/bw-fix-relaxed-autolinks
Browse files Browse the repository at this point in the history
Fix edge cases for relaxed-autolink option
  • Loading branch information
kivikakk authored Aug 31, 2024
2 parents 30e8bdf + 56ed78f commit 92efde0
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 17 deletions.
42 changes: 26 additions & 16 deletions src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -838,23 +838,33 @@ impl<'o, 'c: 'o> HtmlFormatter<'o, 'c> {
}
NodeValue::Link(ref nl) => {
// Unreliable sourcepos.
if entering {
self.output.write_all(b"<a")?;
if self.options.render.experimental_inline_sourcepos {
self.render_sourcepos(node)?;
}
self.output.write_all(b" href=\"")?;
let url = nl.url.as_bytes();
if self.options.render.unsafe_ || !dangerous_url(url) {
self.escape_href(url)?;
}
if !nl.title.is_empty() {
self.output.write_all(b"\" title=\"")?;
self.escape(nl.title.as_bytes())?;
let parent_node = node.parent();

if !self.options.parse.relaxed_autolinks
|| (parent_node.is_none()
|| !matches!(
parent_node.unwrap().data.borrow().value,
NodeValue::Link(..)
))
{
if entering {
self.output.write_all(b"<a")?;
if self.options.render.experimental_inline_sourcepos {
self.render_sourcepos(node)?;
}
self.output.write_all(b" href=\"")?;
let url = nl.url.as_bytes();
if self.options.render.unsafe_ || !dangerous_url(url) {
self.escape_href(url)?;
}
if !nl.title.is_empty() {
self.output.write_all(b"\" title=\"")?;
self.escape(nl.title.as_bytes())?;
}
self.output.write_all(b"\">")?;
} else {
self.output.write_all(b"</a>")?;
}
self.output.write_all(b"\">")?;
} else {
self.output.write_all(b"</a>")?;
}
}
NodeValue::Image(ref nl) => {
Expand Down
13 changes: 13 additions & 0 deletions src/parser/autolink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ pub fn www_match<'a>(
};

while i + link_end < contents.len() && !isspace(contents[i + link_end]) {
// basic test to detect whether we're in a normal markdown link - not exhaustive
if relaxed_autolinks && contents[i + link_end - 1] == b']' && contents[i + link_end] == b'('
{
return None;
}
link_end += 1;
}

Expand Down Expand Up @@ -267,6 +272,14 @@ pub fn url_match<'a>(
};

while link_end < size - i && !isspace(contents[i + link_end]) {
// basic test to detect whether we're in a normal markdown link - not exhaustive
if relaxed_autolinks
&& link_end > 0
&& contents[i + link_end - 1] == b']'
&& contents[i + link_end] == b'('
{
return None;
}
link_end += 1;
}

Expand Down
3 changes: 2 additions & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,8 @@ pub struct ParseOptions<'c> {
pub relaxed_tasklist_matching: bool,

/// Relax parsing of autolinks, allow links to be detected inside brackets
/// and allow all url schemes
/// and allow all url schemes. It is intended to allow a very specific type of autolink
/// detection, such as `[this http://and.com that]` or `{http://foo.com}`, on a best can basis.
///
/// ```
/// # use comrak::{markdown_to_html, Options};
Expand Down
38 changes: 38 additions & 0 deletions src/tests/autolink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,35 @@ fn autolink_relaxed_links_in_brackets() {
"[<https://foo.com>]",
"<p>[<a href=\"https://foo.com\">https://foo.com</a>]</p>\n",
],
[
"[http://foo.com/](url)",
"<p><a href=\"url\">http://foo.com/</a></p>\n",
],
["[http://foo.com/](url", "<p>[http://foo.com/](url</p>\n"],
[
"[www.foo.com/](url)",
"<p><a href=\"url\">www.foo.com/</a></p>\n",
],
[
"{https://foo.com}",
"<p>{<a href=\"https://foo.com\">https://foo.com</a>}</p>\n",
],
[
"[this http://and.com that](url)",
"<p><a href=\"url\">this http://and.com that</a></p>\n",
],
[
"[this <http://and.com> that](url)",
"<p><a href=\"url\">this http://and.com that</a></p>\n",
],
[
"{this http://and.com that}(url)",
"<p>{this <a href=\"http://and.com\">http://and.com</a> that}(url)</p>\n",
],
[
"[http://foo.com](url)\n[http://bar.com]\n\n[http://bar.com]: http://bar.com/extra",
"<p><a href=\"url\">http://foo.com</a>\n<a href=\"http://bar.com/extra\">http://bar.com</a></p>\n",
],
];

for example in examples {
Expand Down Expand Up @@ -169,6 +198,15 @@ fn autolink_relaxed_links_curly_braces_balanced() {
);
}

#[test]
fn autolink_relaxed_links_curly_parentheses_balanced() {
html_opts!(
[extension.autolink, parse.relaxed_autolinks],
concat!("http://example.com/(abc))...\n"),
concat!("<p><a href=\"http://example.com/(abc)\">http://example.com/(abc)</a>)...</p>\n"),
);
}

#[test]
fn autolink_relaxed_links_schemes() {
let examples = [
Expand Down

0 comments on commit 92efde0

Please sign in to comment.