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