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