Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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