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}