]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/syntax_highlighting/tags.rs
a0286b72d949d6f35e0720f82170ccde98b99e37
[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 crate::SymbolKind;
7
8 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9 pub struct Highlight {
10     pub tag: HighlightTag,
11     pub modifiers: HighlightModifiers,
12 }
13
14 #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
15 pub struct HighlightModifiers(u32);
16
17 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18 pub enum HighlightTag {
19     Symbol(SymbolKind),
20
21     BoolLiteral,
22     BuiltinType,
23     ByteLiteral,
24     CharLiteral,
25     NumericLiteral,
26     StringLiteral,
27     Attribute,
28     Comment,
29     EscapeSequence,
30     FormatSpecifier,
31     Keyword,
32     Punctuation,
33     Operator,
34     UnresolvedReference,
35
36     // For things which don't have proper Tag, but want to use modifiers.
37     Dummy,
38 }
39
40 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
41 #[repr(u8)]
42 pub enum HighlightModifier {
43     /// Used to differentiate individual elements within attributes.
44     Attribute = 0,
45     /// Used with keywords like `if` and `break`.
46     ControlFlow,
47     /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is
48     /// not.
49     Definition,
50     Documentation,
51     Injected,
52     Mutable,
53     Consuming,
54     Callable,
55     /// Used for associated functions
56     Static,
57     /// Used for items in impls&traits.
58     Associated,
59
60     /// Keep this last!
61     Unsafe,
62 }
63
64 impl HighlightTag {
65     fn as_str(self) -> &'static str {
66         match self {
67             HighlightTag::Symbol(symbol) => match symbol {
68                 SymbolKind::Const => "constant",
69                 SymbolKind::Static => "static",
70                 SymbolKind::Enum => "enum",
71                 SymbolKind::Variant => "enum_variant",
72                 SymbolKind::Struct => "struct",
73                 SymbolKind::Union => "union",
74                 SymbolKind::Field => "field",
75                 SymbolKind::Module => "module",
76                 SymbolKind::Trait => "trait",
77                 SymbolKind::Function => "function",
78                 SymbolKind::TypeAlias => "type_alias",
79                 SymbolKind::TypeParam => "type_param",
80                 SymbolKind::ConstParam => "const_param",
81                 SymbolKind::LifetimeParam => "lifetime",
82                 SymbolKind::Macro => "macro",
83                 SymbolKind::Local => "variable",
84                 SymbolKind::Label => "label",
85                 SymbolKind::ValueParam => "value_param",
86                 SymbolKind::SelfParam => "self_keyword",
87                 SymbolKind::Impl => "self_type",
88             },
89             HighlightTag::Attribute => "attribute",
90             HighlightTag::BoolLiteral => "bool_literal",
91             HighlightTag::BuiltinType => "builtin_type",
92             HighlightTag::ByteLiteral => "byte_literal",
93             HighlightTag::CharLiteral => "char_literal",
94             HighlightTag::Comment => "comment",
95             HighlightTag::EscapeSequence => "escape_sequence",
96             HighlightTag::FormatSpecifier => "format_specifier",
97             HighlightTag::Keyword => "keyword",
98             HighlightTag::Punctuation => "punctuation",
99             HighlightTag::NumericLiteral => "numeric_literal",
100             HighlightTag::Operator => "operator",
101             HighlightTag::StringLiteral => "string_literal",
102             HighlightTag::UnresolvedReference => "unresolved_reference",
103             HighlightTag::Dummy => "dummy",
104         }
105     }
106 }
107
108 impl fmt::Display for HighlightTag {
109     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110         fmt::Display::fmt(self.as_str(), f)
111     }
112 }
113
114 impl HighlightModifier {
115     const ALL: &'static [HighlightModifier; HighlightModifier::Unsafe as u8 as usize + 1] = &[
116         HighlightModifier::Attribute,
117         HighlightModifier::ControlFlow,
118         HighlightModifier::Definition,
119         HighlightModifier::Documentation,
120         HighlightModifier::Injected,
121         HighlightModifier::Mutable,
122         HighlightModifier::Consuming,
123         HighlightModifier::Callable,
124         HighlightModifier::Static,
125         HighlightModifier::Associated,
126         HighlightModifier::Unsafe,
127     ];
128
129     fn as_str(self) -> &'static str {
130         match self {
131             HighlightModifier::Attribute => "attribute",
132             HighlightModifier::ControlFlow => "control",
133             HighlightModifier::Definition => "declaration",
134             HighlightModifier::Documentation => "documentation",
135             HighlightModifier::Injected => "injected",
136             HighlightModifier::Mutable => "mutable",
137             HighlightModifier::Consuming => "consuming",
138             HighlightModifier::Unsafe => "unsafe",
139             HighlightModifier::Callable => "callable",
140             HighlightModifier::Static => "static",
141             HighlightModifier::Associated => "associated",
142         }
143     }
144
145     fn mask(self) -> u32 {
146         1 << (self as u32)
147     }
148 }
149
150 impl fmt::Display for HighlightModifier {
151     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152         fmt::Display::fmt(self.as_str(), f)
153     }
154 }
155
156 impl fmt::Display for Highlight {
157     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158         write!(f, "{}", self.tag)?;
159         for modifier in self.modifiers.iter() {
160             write!(f, ".{}", modifier)?
161         }
162         Ok(())
163     }
164 }
165
166 impl From<HighlightTag> for Highlight {
167     fn from(tag: HighlightTag) -> Highlight {
168         Highlight::new(tag)
169     }
170 }
171
172 impl Highlight {
173     pub(crate) fn new(tag: HighlightTag) -> Highlight {
174         Highlight { tag, modifiers: HighlightModifiers::default() }
175     }
176     pub fn is_empty(&self) -> bool {
177         self.tag == HighlightTag::Dummy && self.modifiers == HighlightModifiers::default()
178     }
179 }
180
181 impl ops::BitOr<HighlightModifier> for HighlightTag {
182     type Output = Highlight;
183
184     fn bitor(self, rhs: HighlightModifier) -> Highlight {
185         Highlight::new(self) | rhs
186     }
187 }
188
189 impl ops::BitOrAssign<HighlightModifier> for HighlightModifiers {
190     fn bitor_assign(&mut self, rhs: HighlightModifier) {
191         self.0 |= rhs.mask();
192     }
193 }
194
195 impl ops::BitOrAssign<HighlightModifier> for Highlight {
196     fn bitor_assign(&mut self, rhs: HighlightModifier) {
197         self.modifiers |= rhs;
198     }
199 }
200
201 impl ops::BitOr<HighlightModifier> for Highlight {
202     type Output = Highlight;
203
204     fn bitor(mut self, rhs: HighlightModifier) -> Highlight {
205         self |= rhs;
206         self
207     }
208 }
209
210 impl HighlightModifiers {
211     pub fn contains(self, m: HighlightModifier) -> bool {
212         self.0 & m.mask() == m.mask()
213     }
214
215     pub fn iter(self) -> impl Iterator<Item = HighlightModifier> {
216         HighlightModifier::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask())
217     }
218 }