• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Defines token tags we use for syntax highlighting.
2 //! A tag is not unlike a CSS class.
3 
4 use std::{
5     fmt::{self, Write},
6     ops,
7 };
8 
9 use ide_db::SymbolKind;
10 
11 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
12 pub struct Highlight {
13     pub tag: HlTag,
14     pub mods: HlMods,
15 }
16 
17 #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18 pub struct HlMods(u32);
19 
20 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
21 pub enum HlTag {
22     Symbol(SymbolKind),
23 
24     AttributeBracket,
25     BoolLiteral,
26     BuiltinType,
27     ByteLiteral,
28     CharLiteral,
29     Comment,
30     EscapeSequence,
31     FormatSpecifier,
32     Keyword,
33     NumericLiteral,
34     Operator(HlOperator),
35     Punctuation(HlPunct),
36     StringLiteral,
37     UnresolvedReference,
38 
39     // For things which don't have a specific highlight.
40     None,
41 }
42 
43 // Don't forget to adjust the feature description in crates/ide/src/syntax_highlighting.rs.
44 // And make sure to use the lsp strings used when converting to the protocol in crates\rust-analyzer\src\semantic_tokens.rs, not the names of the variants here.
45 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
46 #[repr(u8)]
47 pub enum HlMod {
48     /// Used for items in traits and impls.
49     Associated = 0,
50     /// Used with keywords like `async` and `await`.
51     Async,
52     /// Used to differentiate individual elements within attribute calls.
53     Attribute,
54     /// Callable item or value.
55     Callable,
56     /// Value that is being consumed in a function call
57     Consuming,
58     /// Used with keywords like `if` and `break`.
59     ControlFlow,
60     /// Used for crate names, like `serde`.
61     CrateRoot,
62     /// Used for items from built-in crates (std, core, alloc, test and proc_macro).
63     DefaultLibrary,
64     /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is
65     /// not.
66     Definition,
67     /// Doc-strings like this one.
68     Documentation,
69     /// Highlighting injection like rust code in doc strings or ra_fixture.
70     Injected,
71     /// Used for intra doc links in doc injection.
72     IntraDocLink,
73     /// Used for items from other crates.
74     Library,
75     /// Used to differentiate individual elements within macro calls.
76     Macro,
77     /// Mutable binding.
78     Mutable,
79     /// Used for public items.
80     Public,
81     /// Immutable reference.
82     Reference,
83     /// Used for associated functions.
84     Static,
85     /// Used for items in traits and trait impls.
86     Trait,
87     // Keep this last!
88     /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations.
89     Unsafe,
90 }
91 
92 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
93 pub enum HlPunct {
94     /// []
95     Bracket,
96     /// {}
97     Brace,
98     /// ()
99     Parenthesis,
100     /// <>
101     Angle,
102     /// ,
103     Comma,
104     /// .
105     Dot,
106     /// :
107     Colon,
108     /// ;
109     Semi,
110     /// ! (only for macro calls)
111     MacroBang,
112     ///
113     Other,
114 }
115 
116 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
117 pub enum HlOperator {
118     /// |, &, !, ^, |=, &=, ^=
119     Bitwise,
120     /// +, -, *, /, +=, -=, *=, /=
121     Arithmetic,
122     /// &&, ||, !
123     Logical,
124     /// >, <, ==, >=, <=, !=
125     Comparison,
126     ///
127     Other,
128 }
129 
130 impl HlTag {
as_str(self) -> &'static str131     fn as_str(self) -> &'static str {
132         match self {
133             HlTag::Symbol(symbol) => match symbol {
134                 SymbolKind::Attribute => "attribute",
135                 SymbolKind::BuiltinAttr => "builtin_attr",
136                 SymbolKind::Const => "constant",
137                 SymbolKind::ConstParam => "const_param",
138                 SymbolKind::Derive => "derive",
139                 SymbolKind::DeriveHelper => "derive_helper",
140                 SymbolKind::Enum => "enum",
141                 SymbolKind::Field => "field",
142                 SymbolKind::Function => "function",
143                 SymbolKind::Impl => "self_type",
144                 SymbolKind::Label => "label",
145                 SymbolKind::LifetimeParam => "lifetime",
146                 SymbolKind::Local => "variable",
147                 SymbolKind::Macro => "macro",
148                 SymbolKind::Module => "module",
149                 SymbolKind::SelfParam => "self_keyword",
150                 SymbolKind::SelfType => "self_type_keyword",
151                 SymbolKind::Static => "static",
152                 SymbolKind::Struct => "struct",
153                 SymbolKind::ToolModule => "tool_module",
154                 SymbolKind::Trait => "trait",
155                 SymbolKind::TraitAlias => "trait_alias",
156                 SymbolKind::TypeAlias => "type_alias",
157                 SymbolKind::TypeParam => "type_param",
158                 SymbolKind::Union => "union",
159                 SymbolKind::ValueParam => "value_param",
160                 SymbolKind::Variant => "enum_variant",
161             },
162             HlTag::AttributeBracket => "attribute_bracket",
163             HlTag::BoolLiteral => "bool_literal",
164             HlTag::BuiltinType => "builtin_type",
165             HlTag::ByteLiteral => "byte_literal",
166             HlTag::CharLiteral => "char_literal",
167             HlTag::Comment => "comment",
168             HlTag::EscapeSequence => "escape_sequence",
169             HlTag::FormatSpecifier => "format_specifier",
170             HlTag::Keyword => "keyword",
171             HlTag::Punctuation(punct) => match punct {
172                 HlPunct::Bracket => "bracket",
173                 HlPunct::Brace => "brace",
174                 HlPunct::Parenthesis => "parenthesis",
175                 HlPunct::Angle => "angle",
176                 HlPunct::Comma => "comma",
177                 HlPunct::Dot => "dot",
178                 HlPunct::Colon => "colon",
179                 HlPunct::Semi => "semicolon",
180                 HlPunct::MacroBang => "macro_bang",
181                 HlPunct::Other => "punctuation",
182             },
183             HlTag::NumericLiteral => "numeric_literal",
184             HlTag::Operator(op) => match op {
185                 HlOperator::Bitwise => "bitwise",
186                 HlOperator::Arithmetic => "arithmetic",
187                 HlOperator::Logical => "logical",
188                 HlOperator::Comparison => "comparison",
189                 HlOperator::Other => "operator",
190             },
191             HlTag::StringLiteral => "string_literal",
192             HlTag::UnresolvedReference => "unresolved_reference",
193             HlTag::None => "none",
194         }
195     }
196 }
197 
198 impl fmt::Display for HlTag {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result199     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200         fmt::Display::fmt(self.as_str(), f)
201     }
202 }
203 
204 impl HlMod {
205     const ALL: &'static [HlMod; HlMod::Unsafe as usize + 1] = &[
206         HlMod::Associated,
207         HlMod::Async,
208         HlMod::Attribute,
209         HlMod::Callable,
210         HlMod::Consuming,
211         HlMod::ControlFlow,
212         HlMod::CrateRoot,
213         HlMod::DefaultLibrary,
214         HlMod::Definition,
215         HlMod::Documentation,
216         HlMod::Injected,
217         HlMod::IntraDocLink,
218         HlMod::Library,
219         HlMod::Macro,
220         HlMod::Mutable,
221         HlMod::Public,
222         HlMod::Reference,
223         HlMod::Static,
224         HlMod::Trait,
225         HlMod::Unsafe,
226     ];
227 
as_str(self) -> &'static str228     fn as_str(self) -> &'static str {
229         match self {
230             HlMod::Associated => "associated",
231             HlMod::Async => "async",
232             HlMod::Attribute => "attribute",
233             HlMod::Callable => "callable",
234             HlMod::Consuming => "consuming",
235             HlMod::ControlFlow => "control",
236             HlMod::CrateRoot => "crate_root",
237             HlMod::DefaultLibrary => "default_library",
238             HlMod::Definition => "declaration",
239             HlMod::Documentation => "documentation",
240             HlMod::Injected => "injected",
241             HlMod::IntraDocLink => "intra_doc_link",
242             HlMod::Library => "library",
243             HlMod::Macro => "macro",
244             HlMod::Mutable => "mutable",
245             HlMod::Public => "public",
246             HlMod::Reference => "reference",
247             HlMod::Static => "static",
248             HlMod::Trait => "trait",
249             HlMod::Unsafe => "unsafe",
250         }
251     }
252 
mask(self) -> u32253     fn mask(self) -> u32 {
254         1 << (self as u32)
255     }
256 }
257 
258 impl fmt::Display for HlMod {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result259     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260         fmt::Display::fmt(self.as_str(), f)
261     }
262 }
263 
264 impl fmt::Display for Highlight {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result265     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266         self.tag.fmt(f)?;
267         for modifier in self.mods.iter() {
268             f.write_char('.')?;
269             modifier.fmt(f)?;
270         }
271         Ok(())
272     }
273 }
274 
275 impl From<HlTag> for Highlight {
from(tag: HlTag) -> Highlight276     fn from(tag: HlTag) -> Highlight {
277         Highlight::new(tag)
278     }
279 }
280 
281 impl From<HlOperator> for Highlight {
from(op: HlOperator) -> Highlight282     fn from(op: HlOperator) -> Highlight {
283         Highlight::new(HlTag::Operator(op))
284     }
285 }
286 
287 impl From<HlPunct> for Highlight {
from(punct: HlPunct) -> Highlight288     fn from(punct: HlPunct) -> Highlight {
289         Highlight::new(HlTag::Punctuation(punct))
290     }
291 }
292 
293 impl From<SymbolKind> for Highlight {
from(sym: SymbolKind) -> Highlight294     fn from(sym: SymbolKind) -> Highlight {
295         Highlight::new(HlTag::Symbol(sym))
296     }
297 }
298 
299 impl Highlight {
new(tag: HlTag) -> Highlight300     pub(crate) fn new(tag: HlTag) -> Highlight {
301         Highlight { tag, mods: HlMods::default() }
302     }
is_empty(&self) -> bool303     pub fn is_empty(&self) -> bool {
304         self.tag == HlTag::None && self.mods.is_empty()
305     }
306 }
307 
308 impl ops::BitOr<HlMod> for HlTag {
309     type Output = Highlight;
310 
bitor(self, rhs: HlMod) -> Highlight311     fn bitor(self, rhs: HlMod) -> Highlight {
312         Highlight::new(self) | rhs
313     }
314 }
315 
316 impl ops::BitOrAssign<HlMod> for HlMods {
bitor_assign(&mut self, rhs: HlMod)317     fn bitor_assign(&mut self, rhs: HlMod) {
318         self.0 |= rhs.mask();
319     }
320 }
321 
322 impl ops::BitOrAssign<HlMod> for Highlight {
bitor_assign(&mut self, rhs: HlMod)323     fn bitor_assign(&mut self, rhs: HlMod) {
324         self.mods |= rhs;
325     }
326 }
327 
328 impl ops::BitOr<HlMod> for Highlight {
329     type Output = Highlight;
330 
bitor(mut self, rhs: HlMod) -> Highlight331     fn bitor(mut self, rhs: HlMod) -> Highlight {
332         self |= rhs;
333         self
334     }
335 }
336 
337 impl HlMods {
is_empty(&self) -> bool338     pub fn is_empty(&self) -> bool {
339         self.0 == 0
340     }
341 
contains(self, m: HlMod) -> bool342     pub fn contains(self, m: HlMod) -> bool {
343         self.0 & m.mask() == m.mask()
344     }
345 
iter(self) -> impl Iterator<Item = HlMod>346     pub fn iter(self) -> impl Iterator<Item = HlMod> {
347         HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask())
348     }
349 }
350