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