highlight_map.rs

 1use crate::syntax_theme::SyntaxTheme;
 2use std::sync::Arc;
 3
 4#[derive(Clone, Debug)]
 5pub struct HighlightMap(Arc<[HighlightId]>);
 6
 7#[derive(Clone, Copy, Debug)]
 8pub struct HighlightId(pub u32);
 9
10const DEFAULT_HIGHLIGHT_ID: HighlightId = HighlightId(u32::MAX);
11
12impl HighlightMap {
13    pub fn new(capture_names: &[String], theme: &SyntaxTheme) -> Self {
14        // For each capture name in the highlight query, find the longest
15        // key in the theme's syntax styles that matches all of the
16        // dot-separated components of the capture name.
17        HighlightMap(
18            capture_names
19                .iter()
20                .map(|capture_name| {
21                    theme
22                        .highlights
23                        .iter()
24                        .enumerate()
25                        .filter_map(|(i, (key, _))| {
26                            let mut len = 0;
27                            let capture_parts = capture_name.split('.');
28                            for key_part in key.split('.') {
29                                if capture_parts.clone().any(|part| part == key_part) {
30                                    len += 1;
31                                } else {
32                                    return None;
33                                }
34                            }
35                            Some((i, len))
36                        })
37                        .max_by_key(|(_, len)| *len)
38                        .map_or(DEFAULT_HIGHLIGHT_ID, |(i, _)| HighlightId(i as u32))
39                })
40                .collect(),
41        )
42    }
43
44    pub fn get(&self, capture_id: u32) -> HighlightId {
45        self.0
46            .get(capture_id as usize)
47            .copied()
48            .unwrap_or(DEFAULT_HIGHLIGHT_ID)
49    }
50}
51
52impl Default for HighlightMap {
53    fn default() -> Self {
54        Self(Arc::new([]))
55    }
56}
57
58impl Default for HighlightId {
59    fn default() -> Self {
60        DEFAULT_HIGHLIGHT_ID
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use gpui::color::Color;
68
69    #[test]
70    fn test_highlight_map() {
71        let theme = SyntaxTheme::new(
72            [
73                ("function", Color::from_u32(0x100000ff)),
74                ("function.method", Color::from_u32(0x200000ff)),
75                ("function.async", Color::from_u32(0x300000ff)),
76                ("variable.builtin.self.rust", Color::from_u32(0x400000ff)),
77                ("variable.builtin", Color::from_u32(0x500000ff)),
78                ("variable", Color::from_u32(0x600000ff)),
79            ]
80            .iter()
81            .map(|(name, color)| (name.to_string(), (*color).into()))
82            .collect(),
83        );
84
85        let capture_names = &[
86            "function.special".to_string(),
87            "function.async.rust".to_string(),
88            "variable.builtin.self".to_string(),
89        ];
90
91        let map = HighlightMap::new(capture_names, &theme);
92        assert_eq!(theme.highlight_name(map.get(0)), Some("function"));
93        assert_eq!(theme.highlight_name(map.get(1)), Some("function.async"));
94        assert_eq!(theme.highlight_name(map.get(2)), Some("variable.builtin"));
95    }
96}