]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/syntax_highlighting/tags.rs
Code blocks with tilde also works like code block
[rust.git] / 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::Enum => "enum",
138                 SymbolKind::Field => "field",
139                 SymbolKind::Function => "function",
140                 SymbolKind::Impl => "self_type",
141                 SymbolKind::Label => "label",
142                 SymbolKind::LifetimeParam => "lifetime",
143                 SymbolKind::Local => "variable",
144                 SymbolKind::Macro => "macro",
145                 SymbolKind::Module => "module",
146                 SymbolKind::SelfParam => "self_keyword",
147                 SymbolKind::SelfType => "self_type_keyword",
148                 SymbolKind::Static => "static",
149                 SymbolKind::Struct => "struct",
150                 SymbolKind::ToolModule => "tool_module",
151                 SymbolKind::Trait => "trait",
152                 SymbolKind::TypeAlias => "type_alias",
153                 SymbolKind::TypeParam => "type_param",
154                 SymbolKind::Union => "union",
155                 SymbolKind::ValueParam => "value_param",
156                 SymbolKind::Variant => "enum_variant",
157             },
158             HlTag::AttributeBracket => "attribute_bracket",
159             HlTag::BoolLiteral => "bool_literal",
160             HlTag::BuiltinType => "builtin_type",
161             HlTag::ByteLiteral => "byte_literal",
162             HlTag::CharLiteral => "char_literal",
163             HlTag::Comment => "comment",
164             HlTag::EscapeSequence => "escape_sequence",
165             HlTag::FormatSpecifier => "format_specifier",
166             HlTag::Keyword => "keyword",
167             HlTag::Punctuation(punct) => match punct {
168                 HlPunct::Bracket => "bracket",
169                 HlPunct::Brace => "brace",
170                 HlPunct::Parenthesis => "parenthesis",
171                 HlPunct::Angle => "angle",
172                 HlPunct::Comma => "comma",
173                 HlPunct::Dot => "dot",
174                 HlPunct::Colon => "colon",
175                 HlPunct::Semi => "semicolon",
176                 HlPunct::MacroBang => "macro_bang",
177                 HlPunct::Other => "punctuation",
178             },
179             HlTag::NumericLiteral => "numeric_literal",
180             HlTag::Operator(op) => match op {
181                 HlOperator::Bitwise => "bitwise",
182                 HlOperator::Arithmetic => "arithmetic",
183                 HlOperator::Logical => "logical",
184                 HlOperator::Comparison => "comparison",
185                 HlOperator::Other => "operator",
186             },
187             HlTag::StringLiteral => "string_literal",
188             HlTag::UnresolvedReference => "unresolved_reference",
189             HlTag::None => "none",
190         }
191     }
192 }
193
194 impl fmt::Display for HlTag {
195     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196         fmt::Display::fmt(self.as_str(), f)
197     }
198 }
199
200 impl HlMod {
201     const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[
202         HlMod::Associated,
203         HlMod::Async,
204         HlMod::Attribute,
205         HlMod::Callable,
206         HlMod::Consuming,
207         HlMod::ControlFlow,
208         HlMod::CrateRoot,
209         HlMod::DefaultLibrary,
210         HlMod::Definition,
211         HlMod::Documentation,
212         HlMod::Injected,
213         HlMod::IntraDocLink,
214         HlMod::Library,
215         HlMod::Mutable,
216         HlMod::Public,
217         HlMod::Reference,
218         HlMod::Static,
219         HlMod::Trait,
220         HlMod::Unsafe,
221     ];
222
223     fn as_str(self) -> &'static str {
224         match self {
225             HlMod::Associated => "associated",
226             HlMod::Async => "async",
227             HlMod::Attribute => "attribute",
228             HlMod::Callable => "callable",
229             HlMod::Consuming => "consuming",
230             HlMod::ControlFlow => "control",
231             HlMod::CrateRoot => "crate_root",
232             HlMod::DefaultLibrary => "default_library",
233             HlMod::Definition => "declaration",
234             HlMod::Documentation => "documentation",
235             HlMod::Injected => "injected",
236             HlMod::IntraDocLink => "intra_doc_link",
237             HlMod::Library => "library",
238             HlMod::Mutable => "mutable",
239             HlMod::Public => "public",
240             HlMod::Reference => "reference",
241             HlMod::Static => "static",
242             HlMod::Trait => "trait",
243             HlMod::Unsafe => "unsafe",
244         }
245     }
246
247     fn mask(self) -> u32 {
248         1 << (self as u32)
249     }
250 }
251
252 impl fmt::Display for HlMod {
253     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254         fmt::Display::fmt(self.as_str(), f)
255     }
256 }
257
258 impl fmt::Display for Highlight {
259     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260         self.tag.fmt(f)?;
261         for modifier in self.mods.iter() {
262             f.write_char('.')?;
263             modifier.fmt(f)?;
264         }
265         Ok(())
266     }
267 }
268
269 impl From<HlTag> for Highlight {
270     fn from(tag: HlTag) -> Highlight {
271         Highlight::new(tag)
272     }
273 }
274
275 impl From<HlOperator> for Highlight {
276     fn from(op: HlOperator) -> Highlight {
277         Highlight::new(HlTag::Operator(op))
278     }
279 }
280
281 impl From<HlPunct> for Highlight {
282     fn from(punct: HlPunct) -> Highlight {
283         Highlight::new(HlTag::Punctuation(punct))
284     }
285 }
286
287 impl From<SymbolKind> for Highlight {
288     fn from(sym: SymbolKind) -> Highlight {
289         Highlight::new(HlTag::Symbol(sym))
290     }
291 }
292
293 impl Highlight {
294     pub(crate) fn new(tag: HlTag) -> Highlight {
295         Highlight { tag, mods: HlMods::default() }
296     }
297     pub fn is_empty(&self) -> bool {
298         self.tag == HlTag::None && self.mods == HlMods::default()
299     }
300 }
301
302 impl ops::BitOr<HlMod> for HlTag {
303     type Output = Highlight;
304
305     fn bitor(self, rhs: HlMod) -> Highlight {
306         Highlight::new(self) | rhs
307     }
308 }
309
310 impl ops::BitOrAssign<HlMod> for HlMods {
311     fn bitor_assign(&mut self, rhs: HlMod) {
312         self.0 |= rhs.mask();
313     }
314 }
315
316 impl ops::BitOrAssign<HlMod> for Highlight {
317     fn bitor_assign(&mut self, rhs: HlMod) {
318         self.mods |= rhs;
319     }
320 }
321
322 impl ops::BitOr<HlMod> for Highlight {
323     type Output = Highlight;
324
325     fn bitor(mut self, rhs: HlMod) -> Highlight {
326         self |= rhs;
327         self
328     }
329 }
330
331 impl HlMods {
332     pub fn contains(self, m: HlMod) -> bool {
333         self.0 & m.mask() == m.mask()
334     }
335
336     pub fn iter(self) -> impl Iterator<Item = HlMod> {
337         HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask())
338     }
339 }