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