rs_web/markdown/transforms/
name_highlight.rs

1use pulldown_cmark::{CowStr, Event};
2
3use super::AstTransform;
4use crate::config::HighlightConfig;
5use crate::markdown::TransformContext;
6
7/// Transform that highlights configured names with a CSS class
8pub struct NameHighlightTransform {
9    config: HighlightConfig,
10}
11
12impl NameHighlightTransform {
13    pub fn new(config: HighlightConfig) -> Self {
14        Self { config }
15    }
16}
17
18impl AstTransform for NameHighlightTransform {
19    fn name(&self) -> &'static str {
20        "name_highlight"
21    }
22
23    fn priority(&self) -> i32 {
24        80 // Run before external links transform
25    }
26
27    fn transform<'a>(&self, events: Vec<Event<'a>>, _ctx: &TransformContext<'_>) -> Vec<Event<'a>> {
28        if self.config.names.is_empty() {
29            return events;
30        }
31
32        let mut result = Vec::with_capacity(events.len());
33
34        for event in events {
35            match &event {
36                Event::Text(text) => {
37                    let highlighted = self.highlight_names(text);
38                    if highlighted != text.as_ref() {
39                        result.push(Event::Html(CowStr::from(highlighted)));
40                    } else {
41                        result.push(event);
42                    }
43                }
44                _ => {
45                    result.push(event);
46                }
47            }
48        }
49
50        result
51    }
52}
53
54impl NameHighlightTransform {
55    fn highlight_names(&self, text: &str) -> String {
56        let mut result = text.to_string();
57
58        for name in &self.config.names {
59            if result.contains(name) {
60                let replacement = format!(r#"<span class="{}">{}</span>"#, self.config.class, name);
61                result = result.replace(name, &replacement);
62            }
63        }
64
65        result
66    }
67}