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}