highlight_map.rs

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