1use std::{
5 fmt::{self, Write},
6 ops,
7};
8
9use ide_db::SymbolKind;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
12pub struct Highlight {
13 pub tag: HlTag,
14 pub mods: HlMods,
15}
16
17#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18pub struct HlMods(u32);
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
21pub enum HlTag {
22 Symbol(SymbolKind),
23
24 AttributeBracket,
25 BoolLiteral,
26 BuiltinType,
27 ByteLiteral,
28 CharLiteral,
29 Comment,
30 EscapeSequence,
31 FormatSpecifier,
32 InvalidEscapeSequence,
33 Keyword,
34 NumericLiteral,
35 Operator(HlOperator),
36 Punctuation(HlPunct),
37 StringLiteral,
38 UnresolvedReference,
39
40 None,
42}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
47#[repr(u8)]
48pub enum HlMod {
49 Associated = 0,
51 Async,
53 Attribute,
55 Callable,
57 Const,
59 Consuming,
61 ControlFlow,
63 CrateRoot,
65 DefaultLibrary,
67 Definition,
70 Deprecated,
72 Documentation,
74 Injected,
76 IntraDocLink,
78 Library,
80 Macro,
82 ProcMacro,
84 Mutable,
86 Public,
88 Reference,
90 Static,
92 Trait,
94 Unsafe,
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
100pub enum HlPunct {
101 Bracket,
103 Brace,
105 Parenthesis,
107 Angle,
109 Comma,
111 Dot,
113 Colon,
115 Semi,
117 MacroBang,
119 Other,
121}
122
123#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
124pub enum HlOperator {
125 Bitwise,
127 Arithmetic,
129 Logical,
131 Negation,
133 Comparison,
135 Other,
137}
138
139impl HlTag {
140 fn as_str(self) -> &'static str {
141 match self {
142 HlTag::Symbol(symbol) => match symbol {
143 SymbolKind::Attribute => "attribute",
144 SymbolKind::BuiltinAttr => "builtin_attr",
145 SymbolKind::Const => "constant",
146 SymbolKind::ConstParam => "const_param",
147 SymbolKind::Derive => "derive",
148 SymbolKind::DeriveHelper => "derive_helper",
149 SymbolKind::Enum => "enum",
150 SymbolKind::Field => "field",
151 SymbolKind::Function => "function",
152 SymbolKind::Impl => "self_type",
153 SymbolKind::InlineAsmRegOrRegClass => "reg",
154 SymbolKind::Label => "label",
155 SymbolKind::LifetimeParam => "lifetime",
156 SymbolKind::Local => "variable",
157 SymbolKind::Macro => "macro",
158 SymbolKind::Method => "method",
159 SymbolKind::ProcMacro => "proc_macro",
160 SymbolKind::Module => "module",
161 SymbolKind::SelfParam => "self_keyword",
162 SymbolKind::SelfType => "self_type_keyword",
163 SymbolKind::Static => "static",
164 SymbolKind::Struct => "struct",
165 SymbolKind::ToolModule => "tool_module",
166 SymbolKind::Trait => "trait",
167 SymbolKind::TypeAlias => "type_alias",
168 SymbolKind::TypeParam => "type_param",
169 SymbolKind::Union => "union",
170 SymbolKind::ValueParam => "value_param",
171 SymbolKind::Variant => "enum_variant",
172 },
173 HlTag::AttributeBracket => "attribute_bracket",
174 HlTag::BoolLiteral => "bool_literal",
175 HlTag::BuiltinType => "builtin_type",
176 HlTag::ByteLiteral => "byte_literal",
177 HlTag::CharLiteral => "char_literal",
178 HlTag::Comment => "comment",
179 HlTag::EscapeSequence => "escape_sequence",
180 HlTag::InvalidEscapeSequence => "invalid_escape_sequence",
181 HlTag::FormatSpecifier => "format_specifier",
182 HlTag::Keyword => "keyword",
183 HlTag::Punctuation(punct) => match punct {
184 HlPunct::Bracket => "bracket",
185 HlPunct::Brace => "brace",
186 HlPunct::Parenthesis => "parenthesis",
187 HlPunct::Angle => "angle",
188 HlPunct::Comma => "comma",
189 HlPunct::Dot => "dot",
190 HlPunct::Colon => "colon",
191 HlPunct::Semi => "semicolon",
192 HlPunct::MacroBang => "macro_bang",
193 HlPunct::Other => "punctuation",
194 },
195 HlTag::NumericLiteral => "numeric_literal",
196 HlTag::Operator(op) => match op {
197 HlOperator::Bitwise => "bitwise",
198 HlOperator::Arithmetic => "arithmetic",
199 HlOperator::Logical => "logical",
200 HlOperator::Comparison => "comparison",
201 HlOperator::Negation => "negation",
202 HlOperator::Other => "operator",
203 },
204 HlTag::StringLiteral => "string_literal",
205 HlTag::UnresolvedReference => "unresolved_reference",
206 HlTag::None => "none",
207 }
208 }
209}
210
211impl fmt::Display for HlTag {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 fmt::Display::fmt(self.as_str(), f)
214 }
215}
216
217impl HlMod {
218 const ALL: &'static [HlMod; HlMod::Unsafe as usize + 1] = &[
219 HlMod::Associated,
220 HlMod::Async,
221 HlMod::Attribute,
222 HlMod::Callable,
223 HlMod::Const,
224 HlMod::Consuming,
225 HlMod::ControlFlow,
226 HlMod::CrateRoot,
227 HlMod::DefaultLibrary,
228 HlMod::Definition,
229 HlMod::Deprecated,
230 HlMod::Documentation,
231 HlMod::Injected,
232 HlMod::IntraDocLink,
233 HlMod::Library,
234 HlMod::Macro,
235 HlMod::Mutable,
236 HlMod::ProcMacro,
237 HlMod::Public,
238 HlMod::Reference,
239 HlMod::Static,
240 HlMod::Trait,
241 HlMod::Unsafe,
242 ];
243
244 fn as_str(self) -> &'static str {
245 match self {
246 HlMod::Associated => "associated",
247 HlMod::Async => "async",
248 HlMod::Attribute => "attribute",
249 HlMod::Callable => "callable",
250 HlMod::Consuming => "consuming",
251 HlMod::Const => "const",
252 HlMod::ControlFlow => "control",
253 HlMod::CrateRoot => "crate_root",
254 HlMod::DefaultLibrary => "default_library",
255 HlMod::Definition => "declaration",
256 HlMod::Deprecated => "deprecated",
257 HlMod::Documentation => "documentation",
258 HlMod::Injected => "injected",
259 HlMod::IntraDocLink => "intra_doc_link",
260 HlMod::Library => "library",
261 HlMod::Macro => "macro",
262 HlMod::ProcMacro => "proc_macro",
263 HlMod::Mutable => "mutable",
264 HlMod::Public => "public",
265 HlMod::Reference => "reference",
266 HlMod::Static => "static",
267 HlMod::Trait => "trait",
268 HlMod::Unsafe => "unsafe",
269 }
270 }
271
272 fn mask(self) -> u32 {
273 debug_assert!(Self::ALL.len() <= 32, "HlMod::mask is not enough to cover all variants");
274 1 << (self as u32)
275 }
276}
277
278impl fmt::Display for HlMod {
279 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280 fmt::Display::fmt(self.as_str(), f)
281 }
282}
283
284impl fmt::Display for Highlight {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 self.tag.fmt(f)?;
287 for modifier in self.mods.iter() {
288 f.write_char('.')?;
289 modifier.fmt(f)?;
290 }
291 Ok(())
292 }
293}
294
295impl From<HlTag> for Highlight {
296 fn from(tag: HlTag) -> Highlight {
297 Highlight::new(tag)
298 }
299}
300
301impl From<HlOperator> for Highlight {
302 fn from(op: HlOperator) -> Highlight {
303 Highlight::new(HlTag::Operator(op))
304 }
305}
306
307impl From<HlPunct> for Highlight {
308 fn from(punct: HlPunct) -> Highlight {
309 Highlight::new(HlTag::Punctuation(punct))
310 }
311}
312
313impl From<SymbolKind> for Highlight {
314 fn from(sym: SymbolKind) -> Highlight {
315 Highlight::new(HlTag::Symbol(sym))
316 }
317}
318
319impl Highlight {
320 pub(crate) fn new(tag: HlTag) -> Highlight {
321 Highlight { tag, mods: HlMods::default() }
322 }
323 pub fn is_empty(&self) -> bool {
324 self.tag == HlTag::None && self.mods.is_empty()
325 }
326}
327
328impl ops::BitOr<HlMod> for HlTag {
329 type Output = Highlight;
330
331 fn bitor(self, rhs: HlMod) -> Highlight {
332 Highlight::new(self) | rhs
333 }
334}
335
336impl ops::BitOrAssign<HlMod> for HlMods {
337 fn bitor_assign(&mut self, rhs: HlMod) {
338 self.0 |= rhs.mask();
339 }
340}
341
342impl ops::BitOrAssign<HlMod> for Highlight {
343 fn bitor_assign(&mut self, rhs: HlMod) {
344 self.mods |= rhs;
345 }
346}
347
348impl ops::BitOr<HlMod> for Highlight {
349 type Output = Highlight;
350
351 fn bitor(mut self, rhs: HlMod) -> Highlight {
352 self |= rhs;
353 self
354 }
355}
356
357impl HlMods {
358 pub fn is_empty(&self) -> bool {
359 self.0 == 0
360 }
361
362 pub fn contains(self, m: HlMod) -> bool {
363 self.0 & m.mask() == m.mask()
364 }
365
366 pub fn iter(self) -> impl Iterator<Item = HlMod> {
367 HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask())
368 }
369}