textlane_html/actions/hast/
gemoji.rs1use textlane_core::hast::{Element, Node, Property, PropertyValue};
2use textlane_core::{Allocator, ArenaVec, find_gemoji_shortcodes, read_gemoji_label};
3
4use crate::helpers::prose::{create_text, replace_prose};
5use crate::models::options::Gemoji;
6
7pub fn replace_shortcodes<'a>(
10 node: &mut Node<'a>,
11 options: &Gemoji,
12 alloc: &'a Allocator,
13) {
14 replace_prose(
15 node,
16 &options.ignore,
17 &options.ignore_attributes,
18 alloc,
19 |text, out| {
20 let found = find_gemoji_shortcodes(text);
21 if found.is_empty() {
22 return false;
23 }
24 let mut plain = String::new();
25 let mut last = 0;
26 for (start, end, emoji) in found {
27 plain.push_str(&text[last..start]);
28 match options.accessible {
29 true => {
30 if !plain.is_empty() {
31 out.push(create_text(&std::mem::take(&mut plain), alloc));
32 }
33 let label = read_gemoji_label(&text[start + 1..end - 1]);
34 out.push(create_label(emoji, &format!("{label} emoji"), alloc));
35 }
36 false => plain.push_str(emoji),
37 }
38 last = end;
39 }
40 plain.push_str(&text[last..]);
41 if !plain.is_empty() {
42 out.push(create_text(&plain, alloc));
43 }
44 true
45 },
46 );
47}
48
49fn create_label<'a>(emoji: &str, label: &str, alloc: &'a Allocator) -> Node<'a> {
50 let mut properties = ArenaVec::with_capacity_in(2, alloc);
51 properties.push(Property {
52 name: "role",
53 value: PropertyValue::String("img"),
54 });
55 properties.push(Property {
56 name: "ariaLabel",
57 value: PropertyValue::String(alloc.alloc_str(label)),
58 });
59 let mut children = ArenaVec::with_capacity_in(1, alloc);
60 children.push(create_text(emoji, alloc));
61 Node::Element(Element {
62 tag_name: "span",
63 properties,
64 children,
65 position: None,
66 data: None,
67 content: None,
68 })
69}
70
71#[cfg(test)]
72#[path = "gemoji_unit.rs"]
73mod unit;