Skip to content

Commit 558ac53

Browse files
committed
cm::escape_inline: add function to escape input for inline text.
1 parent 7519cd7 commit 558ac53

File tree

5 files changed

+89
-0
lines changed

5 files changed

+89
-0
lines changed

changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# [v0.42.0] - unreleased
22

3+
New APIs:
4+
5+
* `cm::escape_inline` (aliased at crate level as `escape_commonmark_inline`)
6+
is added; escapes input text suitable for inclusion in a CommonMark document
7+
where regular inline processing takes place.
8+
39
Changed APIs:
410

511
* `html::collect_text` now returns a `String`. `html::collect_text_append` is

src/cm.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,3 +1038,48 @@ fn minimize_commonmark(text: &mut Vec<u8>, original_options: &Options) {
10381038
}
10391039
}
10401040
}
1041+
1042+
/// Escapes the input, rendering it suitable for inclusion in a CommonMark
1043+
/// document in a place where regular inline parsing is occurring. Note that
1044+
/// this is not minimal --- there will be more escaping backslashes in the
1045+
/// output than is strictly necessary. The rendering will not be affected,
1046+
/// however.
1047+
pub fn escape_inline(text: &str) -> String {
1048+
use std::fmt::Write;
1049+
1050+
let mut result = String::with_capacity(text.len() * 3 / 2);
1051+
1052+
for c in text.chars() {
1053+
if c < '\x20'
1054+
|| c == '*'
1055+
|| c == '_'
1056+
|| c == '['
1057+
|| c == ']'
1058+
|| c == '#'
1059+
|| c == '<'
1060+
|| c == '>'
1061+
|| c == '\\'
1062+
|| c == '`'
1063+
|| c == '!'
1064+
|| c == '&'
1065+
|| c == '!'
1066+
|| c == '-'
1067+
|| c == '+'
1068+
|| c == '='
1069+
|| c == '.'
1070+
|| c == '('
1071+
|| c == ')'
1072+
|| c == '"'
1073+
{
1074+
if ispunct(c as u8) {
1075+
write!(&mut result, "\\{}", c).unwrap();
1076+
} else {
1077+
write!(&mut result, "&#{};", c as u8).unwrap();
1078+
}
1079+
} else {
1080+
result.push(c);
1081+
}
1082+
}
1083+
1084+
result
1085+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ mod strings;
8181
mod tests;
8282
mod xml;
8383

84+
pub use cm::escape_inline as escape_commonmark_inline;
8485
pub use cm::format_document as format_commonmark;
8586
pub use cm::format_document_with_plugins as format_commonmark_with_plugins;
8687
pub use html::format_document as format_html;

src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod commonmark;
1212
mod core;
1313
mod description_lists;
1414
mod empty;
15+
mod escape;
1516
mod escaped_char_spans;
1617
mod footnotes;
1718
mod front_matter;

src/tests/escape.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use crate::{cm::escape_inline, entity, markdown_to_html, Options};
2+
3+
/// Assert that the input escapes to the expected result, and that the expected
4+
/// result renders to HTML which displays the input text.
5+
#[track_caller]
6+
fn assert_escape_inline(input: &str, expected: &str) {
7+
let actual = escape_inline(input);
8+
assert_eq!(expected, actual);
9+
let mut html = markdown_to_html(expected, &Options::default());
10+
html = html
11+
.strip_prefix("<p>")
12+
.expect("html should be one paragraph")
13+
.to_string();
14+
html = html
15+
.strip_suffix("</p>\n")
16+
.expect("html should be one paragraph")
17+
.to_string();
18+
assert_eq!(
19+
input,
20+
std::str::from_utf8(&entity::unescape_html(html.as_bytes())).unwrap()
21+
);
22+
}
23+
24+
#[test]
25+
fn escape_inline_baseline() {
26+
assert_escape_inline("abcdefg", "abcdefg");
27+
assert_escape_inline("*hello*", r#"\*hello\*"#);
28+
assert_escape_inline(
29+
"[A link](https://link.com)",
30+
r#"\[A link\]\(https://link\.com\)"#,
31+
);
32+
assert_escape_inline(
33+
r#"some <"complicated"> & '/problematic\' input"#,
34+
r#"some \<\"complicated\"\> \& '/problematic\\' input"#,
35+
);
36+
}

0 commit comments

Comments
 (0)