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