1use bitmask_enum::bitmask;
2use chromashift::Hex;
3use core::fmt;
4use css_lexer::Span;
5use std::collections::HashMap;
6use strum::{Display, VariantNames};
7
8mod css;
9
10#[cfg(any(feature = "anstyle", feature = "owo-colors"))]
11mod default_ansi_theme;
12#[cfg(any(feature = "anstyle", feature = "owo-colors"))]
13pub use default_ansi_theme::{AnsiTheme, DefaultAnsiTheme};
14
15#[cfg(any(feature = "anstyle", feature = "owo-colors"))]
16mod ansi_highlight_cursor_stream;
17#[cfg(any(feature = "anstyle", feature = "owo-colors"))]
18pub use ansi_highlight_cursor_stream::AnsiHighlightCursorStream;
19
20#[cfg(feature = "miette")]
21mod highlight;
22#[cfg(feature = "miette")]
23pub use highlight::CssHighlighter;
24
25#[cfg(test)]
26mod test_helpers;
27#[cfg(test)]
28mod tests;
29
30#[derive(Display, VariantNames, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub enum SemanticKind {
33 None,
34
35 Id,
37 Tag,
38 Class,
39 Wildcard,
40 Attribute,
41 Namespace,
42 Combinator,
43 PseudoClass,
44 PseudoElement,
45 LegacyPseudoElement,
46 FunctionalPseudoClass,
47 FunctionalPseudoElement,
48
49 AtKeyword,
51 Prelude,
52
53 Declaration,
55 StyleValueKeyword,
56 StyleValueDimension,
57 StyleValueNumber,
58 StyleValueString,
59 StyleValueUrl,
60 StyleValueColor,
61 StyleValueFunction,
62 StyleValueImportant,
63
64 Punctuation,
65}
66
67impl SemanticKind {
68 pub fn bits(&self) -> u8 {
69 *self as u8
70 }
71}
72
73#[derive(VariantNames)]
75#[bitmask(u8)]
76pub enum SemanticModifier {
77 Unknown,
78 Deprecated,
79 Experimental,
80 Vendor,
81 Custom,
82}
83
84impl fmt::Display for SemanticModifier {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 if self.contains(Self::Unknown) {
87 write!(f, " unknown")?;
88 }
89 if self.contains(Self::Deprecated) {
90 write!(f, " deprecated")?;
91 }
92 if self.contains(Self::Experimental) {
93 write!(f, " experimental")?;
94 }
95 if self.contains(Self::Experimental) {
96 write!(f, " vendor")?;
97 }
98 if self.contains(Self::Custom) {
99 write!(f, " custom")?;
100 }
101 Ok(())
102 }
103}
104
105#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
106pub enum SemanticDecoration {
107 None,
108 BackgroundColor(Hex),
109}
110
111#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
112pub struct Highlight {
113 kind: SemanticKind,
114 modifier: SemanticModifier,
115 decoration: SemanticDecoration,
116 span: Span,
117}
118
119impl Highlight {
120 #[inline(always)]
121 pub fn span(&self) -> Span {
122 self.span
123 }
124
125 #[inline(always)]
126 pub fn modifier(&self) -> SemanticModifier {
127 self.modifier
128 }
129
130 #[inline(always)]
131 pub fn kind(&self) -> SemanticKind {
132 self.kind
133 }
134
135 #[inline(always)]
136 pub fn decoration(&self) -> SemanticDecoration {
137 self.decoration
138 }
139}
140
141#[derive(Default)]
142pub struct TokenHighlighter {
143 highlights: HashMap<Span, Highlight>,
144}
145
146impl TokenHighlighter {
147 pub fn new() -> Self {
148 Self { highlights: HashMap::new() }
149 }
150
151 pub fn get(&self, span: Span) -> Option<&Highlight> {
152 self.highlights.get(&span)
153 }
154
155 pub fn highlights(&self) -> impl Iterator<Item = &Highlight> {
156 self.highlights.values()
157 }
158
159 fn insert(&mut self, span: Span, kind: SemanticKind, modifier: SemanticModifier) {
160 self.insert_with_decoration(span, kind, modifier, SemanticDecoration::None);
161 }
162
163 fn insert_with_decoration(
164 &mut self,
165 span: Span,
166 kind: SemanticKind,
167 modifier: SemanticModifier,
168 decoration: SemanticDecoration,
169 ) {
170 self.highlights.insert(span, Highlight { span, kind, modifier, decoration });
171 }
172}