Skip to content

Commit

Permalink
Merge pull request #471 from kivikakk/bw-wikilink-title-escape
Browse files Browse the repository at this point in the history
Add support for backslash escape in wikilinks
  • Loading branch information
digitalmoksha authored Sep 28, 2024
2 parents ecec20a + 01bec6d commit 5066a0e
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 8 deletions.
68 changes: 62 additions & 6 deletions src/parser/inlines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1730,7 +1730,7 @@ impl<'a, 'r, 'o, 'c, 'd, 'i> Subject<'a, 'r, 'o, 'c, 'd, 'i> {
let startpos = self.pos;
let component = self.wikilink_url_link_label()?;
let url_clean = strings::clean_url(component.url);
let (link_label, link_label_start_column, link_label_end_column) =
let (link_label, link_label_start_column, _link_label_end_column) =
match component.link_label {
Some((label, sc, ec)) => (entity::unescape_html(label), sc, ec),
None => (
Expand All @@ -1744,11 +1744,8 @@ impl<'a, 'r, 'o, 'c, 'd, 'i> Subject<'a, 'r, 'o, 'c, 'd, 'i> {
url: String::from_utf8(url_clean).unwrap(),
};
let inl = self.make_inline(NodeValue::WikiLink(nl), startpos - 1, self.pos - 1);
inl.append(self.make_inline(
NodeValue::Text(String::from_utf8(link_label).unwrap()),
link_label_start_column,
link_label_end_column,
));

self.label_backslash_escapes(inl, link_label, link_label_start_column);

Some(inl)
}
Expand Down Expand Up @@ -1844,6 +1841,65 @@ impl<'a, 'r, 'o, 'c, 'd, 'i> Subject<'a, 'r, 'o, 'c, 'd, 'i> {
true
}

// Given a label, handles backslash escaped characters. Appends the resulting
// nodes to the container
fn label_backslash_escapes(
&mut self,
container: &'a AstNode<'a>,
label: Vec<u8>,
start_column: usize,
) {
let mut startpos = 0;
let mut offset = 0;
let len = label.len();

while offset < len {
let c = label[offset];

if c == b'\\' && (offset + 1) < len && ispunct(label[offset + 1]) {
let preceding_text = self.make_inline(
NodeValue::Text(String::from_utf8(label[startpos..offset].to_owned()).unwrap()),
start_column + startpos,
start_column + offset - 1,
);

container.append(preceding_text);

let inline_text = self.make_inline(
NodeValue::Text(String::from_utf8(vec![label[offset + 1]]).unwrap()),
start_column + offset,
start_column + offset + 1,
);

if self.options.render.escaped_char_spans {
let span = self.make_inline(
NodeValue::Escaped,
start_column + offset,
start_column + offset + 1,
);

span.append(inline_text);
container.append(span);
} else {
container.append(inline_text);
}

offset += 2;
startpos = offset;
} else {
offset += 1;
}
}

if startpos != offset {
container.append(self.make_inline(
NodeValue::Text(String::from_utf8(label[startpos..offset].to_owned()).unwrap()),
start_column + startpos,
start_column + offset - 1,
));
}
}

pub fn spnl(&mut self) {
self.skip_spaces();
if self.skip_line_end() {
Expand Down
24 changes: 23 additions & 1 deletion src/tests/fixtures/wikilinks_title_after_pipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,26 @@ HTML entities are recognized both in the name of page and in the link title.
[[Gesch&uuml;tztes Leerzeichen|&#xDC;ber &amp;nbsp;]]
.
<p><a href="Gesch%C3%BCtztes%20Leerzeichen" data-wikilink="true">Über &amp;nbsp;</a></p>
````````````````````````````````
````````````````````````````````

Escaping characters is supported

```````````````````````````````` example
[[https://example.org|foo\[\]bar]]
.
<p><a href="https://example.org" data-wikilink="true">foo[]bar</a></p>
````````````````````````````````

```````````````````````````````` example
[[Name \[of\] page]]
.
<p><a href="Name%20%5Bof%5D%20page" data-wikilink="true">Name [of] page</a></p>
````````````````````````````````

Emphasis or other inline markdown is not supported

```````````````````````````````` example
[[Name _of_ page]]
.
<p><a href="Name%20_of_%20page" data-wikilink="true">Name _of_ page</a></p>
````````````````````````````````
24 changes: 23 additions & 1 deletion src/tests/fixtures/wikilinks_title_before_pipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,26 @@ HTML entities are recognized both in the name of page and in the link title.
[[&#xDC;ber &amp;nbsp;|Gesch&uuml;tztes Leerzeichen]]
.
<p><a href="Gesch%C3%BCtztes%20Leerzeichen" data-wikilink="true">Über &amp;nbsp;</a></p>
````````````````````````````````
````````````````````````````````

Escaping characters is supported

```````````````````````````````` example
[[foo\[\]bar|https://example.org]]
.
<p><a href="https://example.org" data-wikilink="true">foo[]bar</a></p>
````````````````````````````````

```````````````````````````````` example
[[Name \[of\] page]]
.
<p><a href="Name%20%5Bof%5D%20page" data-wikilink="true">Name [of] page</a></p>
````````````````````````````````

Emphasis or other inline markdown is not supported

```````````````````````````````` example
[[Name _of_ page]]
.
<p><a href="Name%20_of_%20page" data-wikilink="true">Name _of_ page</a></p>
````````````````````````````````
26 changes: 26 additions & 0 deletions src/tests/wikilinks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ fn wikilinks_sanitizes_the_href_attribute_case_2() {
);
}

#[test]
fn wikilinks_title_escape_chars() {
html_opts!(
[extension.wikilinks_title_before_pipe, render.escaped_char_spans],
concat!("[[Name \\[of\\] page|http://example.com]]",),
concat!("<p><a href=\"http://example.com\" data-wikilink=\"true\">Name <span data-escaped-char>[</span>of<span data-escaped-char>]</span> page</a></p>\n"),
no_roundtrip,
);
}

#[test]
fn wikilinks_supercedes_relaxed_autolinks() {
html_opts!(
Expand Down Expand Up @@ -228,4 +238,20 @@ fn sourcepos() {
])
])
);

assert_ast_match!(
[extension.wikilinks_title_before_pipe],
"This [[link\\[label|http://example.com]] that\n",
(document (1:1-1:44) [
(paragraph (1:1-1:44) [
(text (1:1-1:5) "This ")
(wikilink (1:6-1:39) [
(text (1:8-1:11) "link")
(text (1:12-1:13) "[")
(text (1:14-1:18) "label")
])
(text (1:40-1:44) " that")
])
])
);
}

0 comments on commit 5066a0e

Please sign in to comment.