sable-markdown/src/parser/inline/html_entity.rs@main
raw
1use nom::{
2 IResult, Parser,
3 branch::alt,
4 bytes::complete::tag,
5 character::complete::{alpha1, char, digit1, hex_digit1, one_of},
6 combinator::{map, map_opt, recognize},
7 sequence::{delimited, preceded},
8};
9
10use crate::parser::util::ENTITIES;
11
12pub(super) fn html_entity() -> impl FnMut(&str) -> IResult<&str, String> {
13 move |input: &str| alt((html_entity_alpha(), html_entity_numeric)).parse(input)
14}
15
16fn html_entity_alpha() -> impl FnMut(&str) -> IResult<&str, String> {
17 move |input: &str| {
18 map_opt(recognize((char('&'), alpha1, char(';'))), |s: &str| {
19 ENTITIES.get(s).map(|entity| entity.characters.to_owned())
20 })
21 .parse(input)
22 }
23}
24
25fn html_entity_numeric(input: &str) -> IResult<&str, String> {
26 let base16 = map_opt(preceded(one_of("xX"), hex_digit1), |s: &str| {
27 u32::from_str_radix(s, 16).ok()
28 });
29 let base10 = map_opt(digit1, |s: &str| s.parse::<u32>().ok());
30
31 map(
32 map_opt(
33 delimited(tag("&#"), alt((base10, base16)), char(';')),
34 char::from_u32,
35 ),
36 |c: char| c.to_string(),
37 )
38 .parse(input)
39}
40