yozuk_sdk/
highlight.rs

1use serde_derive::{Deserialize, Serialize};
2use std::ops::Range;
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5#[serde(rename_all = "snake_case")]
6pub struct Highlight {
7    pub kind: HighlightKind,
8    pub range: Range<usize>,
9}
10
11#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
12#[serde(rename_all = "snake_case")]
13#[non_exhaustive]
14pub enum HighlightKind {
15    Value,
16}
17
18pub struct Highlighter {
19    quotation: char,
20}
21
22impl Default for Highlighter {
23    fn default() -> Self {
24        Self::new('`')
25    }
26}
27
28impl Highlighter {
29    pub fn new(quotation: char) -> Self {
30        Self { quotation }
31    }
32
33    pub fn highlight(&self, s: &str) -> (String, Vec<Highlight>) {
34        let mut plain = String::with_capacity(s.len());
35        let mut highlights = vec![];
36        let mut start: Option<usize> = None;
37        let mut escaped = false;
38        for c in s.chars() {
39            if escaped {
40                escaped = false;
41                plain.push(c);
42            } else if c == '\\' {
43                escaped = true;
44            } else if c == self.quotation {
45                if let Some(start) = start.take() {
46                    highlights.push(Highlight {
47                        kind: HighlightKind::Value,
48                        range: start..plain.len(),
49                    });
50                } else {
51                    start = Some(plain.len());
52                }
53            } else {
54                plain.push(c);
55            }
56        }
57        (plain, highlights)
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn highlighter() {
67        let text = "`quick brown` 🦊 \\`jumps\\`\nover `the` lazy `dog`.";
68        let (plain, highlights) = Highlighter::default().highlight(text);
69        assert_eq!(plain, "quick brown 🦊 `jumps`\nover the lazy dog.");
70        assert_eq!(
71            highlights,
72            vec![
73                Highlight {
74                    kind: HighlightKind::Value,
75                    range: 0..11
76                },
77                Highlight {
78                    kind: HighlightKind::Value,
79                    range: 30..33
80                },
81                Highlight {
82                    kind: HighlightKind::Value,
83                    range: 39..42
84                }
85            ]
86        );
87    }
88}