use std::{
fmt::{self, Write},
ops,
};
use ide_db::SymbolKind;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Highlight {
pub tag: HlTag,
pub mods: HlMods,
}
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct HlMods(u32);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum HlTag {
Symbol(SymbolKind),
AttributeBracket,
BoolLiteral,
BuiltinType,
ByteLiteral,
CharLiteral,
Comment,
EscapeSequence,
FormatSpecifier,
InvalidEscapeSequence,
Keyword,
NumericLiteral,
Operator(HlOperator),
Punctuation(HlPunct),
StringLiteral,
UnresolvedReference,
None,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)]
pub enum HlMod {
Associated = 0,
Async,
Attribute,
Callable,
Const,
Consuming,
ControlFlow,
CrateRoot,
DefaultLibrary,
Definition,
Documentation,
Injected,
IntraDocLink,
Library,
Macro,
ProcMacro,
Mutable,
Public,
Reference,
Static,
Trait,
Unsafe,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum HlPunct {
Bracket,
Brace,
Parenthesis,
Angle,
Comma,
Dot,
Colon,
Semi,
MacroBang,
Other,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum HlOperator {
Bitwise,
Arithmetic,
Logical,
Comparison,
Other,
}
impl HlTag {
fn as_str(self) -> &'static str {
match self {
HlTag::Symbol(symbol) => match symbol {
SymbolKind::Attribute => "attribute",
SymbolKind::BuiltinAttr => "builtin_attr",
SymbolKind::Const => "constant",
SymbolKind::ConstParam => "const_param",
SymbolKind::Derive => "derive",
SymbolKind::DeriveHelper => "derive_helper",
SymbolKind::Enum => "enum",
SymbolKind::Field => "field",
SymbolKind::Function => "function",
SymbolKind::Impl => "self_type",
SymbolKind::InlineAsmRegOrRegClass => "reg",
SymbolKind::Label => "label",
SymbolKind::LifetimeParam => "lifetime",
SymbolKind::Local => "variable",
SymbolKind::Macro => "macro",
SymbolKind::Method => "method",
SymbolKind::ProcMacro => "proc_macro",
SymbolKind::Module => "module",
SymbolKind::SelfParam => "self_keyword",
SymbolKind::SelfType => "self_type_keyword",
SymbolKind::Static => "static",
SymbolKind::Struct => "struct",
SymbolKind::ToolModule => "tool_module",
SymbolKind::Trait => "trait",
SymbolKind::TraitAlias => "trait_alias",
SymbolKind::TypeAlias => "type_alias",
SymbolKind::TypeParam => "type_param",
SymbolKind::Union => "union",
SymbolKind::ValueParam => "value_param",
SymbolKind::Variant => "enum_variant",
},
HlTag::AttributeBracket => "attribute_bracket",
HlTag::BoolLiteral => "bool_literal",
HlTag::BuiltinType => "builtin_type",
HlTag::ByteLiteral => "byte_literal",
HlTag::CharLiteral => "char_literal",
HlTag::Comment => "comment",
HlTag::EscapeSequence => "escape_sequence",
HlTag::InvalidEscapeSequence => "invalid_escape_sequence",
HlTag::FormatSpecifier => "format_specifier",
HlTag::Keyword => "keyword",
HlTag::Punctuation(punct) => match punct {
HlPunct::Bracket => "bracket",
HlPunct::Brace => "brace",
HlPunct::Parenthesis => "parenthesis",
HlPunct::Angle => "angle",
HlPunct::Comma => "comma",
HlPunct::Dot => "dot",
HlPunct::Colon => "colon",
HlPunct::Semi => "semicolon",
HlPunct::MacroBang => "macro_bang",
HlPunct::Other => "punctuation",
},
HlTag::NumericLiteral => "numeric_literal",
HlTag::Operator(op) => match op {
HlOperator::Bitwise => "bitwise",
HlOperator::Arithmetic => "arithmetic",
HlOperator::Logical => "logical",
HlOperator::Comparison => "comparison",
HlOperator::Other => "operator",
},
HlTag::StringLiteral => "string_literal",
HlTag::UnresolvedReference => "unresolved_reference",
HlTag::None => "none",
}
}
}
impl fmt::Display for HlTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_str(), f)
}
}
impl HlMod {
const ALL: &'static [HlMod; HlMod::Unsafe as usize + 1] = &[
HlMod::Associated,
HlMod::Async,
HlMod::Attribute,
HlMod::Callable,
HlMod::Const,
HlMod::Consuming,
HlMod::ControlFlow,
HlMod::CrateRoot,
HlMod::DefaultLibrary,
HlMod::Definition,
HlMod::Documentation,
HlMod::Injected,
HlMod::IntraDocLink,
HlMod::Library,
HlMod::Macro,
HlMod::Mutable,
HlMod::ProcMacro,
HlMod::Public,
HlMod::Reference,
HlMod::Static,
HlMod::Trait,
HlMod::Unsafe,
];
fn as_str(self) -> &'static str {
match self {
HlMod::Associated => "associated",
HlMod::Async => "async",
HlMod::Attribute => "attribute",
HlMod::Callable => "callable",
HlMod::Consuming => "consuming",
HlMod::Const => "const",
HlMod::ControlFlow => "control",
HlMod::CrateRoot => "crate_root",
HlMod::DefaultLibrary => "default_library",
HlMod::Definition => "declaration",
HlMod::Documentation => "documentation",
HlMod::Injected => "injected",
HlMod::IntraDocLink => "intra_doc_link",
HlMod::Library => "library",
HlMod::Macro => "macro",
HlMod::ProcMacro => "proc_macro",
HlMod::Mutable => "mutable",
HlMod::Public => "public",
HlMod::Reference => "reference",
HlMod::Static => "static",
HlMod::Trait => "trait",
HlMod::Unsafe => "unsafe",
}
}
fn mask(self) -> u32 {
debug_assert!(Self::ALL.len() <= 32, "HlMod::mask is not enough to cover all variants");
1 << (self as u32)
}
}
impl fmt::Display for HlMod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_str(), f)
}
}
impl fmt::Display for Highlight {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.tag.fmt(f)?;
for modifier in self.mods.iter() {
f.write_char('.')?;
modifier.fmt(f)?;
}
Ok(())
}
}
impl From<HlTag> for Highlight {
fn from(tag: HlTag) -> Highlight {
Highlight::new(tag)
}
}
impl From<HlOperator> for Highlight {
fn from(op: HlOperator) -> Highlight {
Highlight::new(HlTag::Operator(op))
}
}
impl From<HlPunct> for Highlight {
fn from(punct: HlPunct) -> Highlight {
Highlight::new(HlTag::Punctuation(punct))
}
}
impl From<SymbolKind> for Highlight {
fn from(sym: SymbolKind) -> Highlight {
Highlight::new(HlTag::Symbol(sym))
}
}
impl Highlight {
pub(crate) fn new(tag: HlTag) -> Highlight {
Highlight { tag, mods: HlMods::default() }
}
pub fn is_empty(&self) -> bool {
self.tag == HlTag::None && self.mods.is_empty()
}
}
impl ops::BitOr<HlMod> for HlTag {
type Output = Highlight;
fn bitor(self, rhs: HlMod) -> Highlight {
Highlight::new(self) | rhs
}
}
impl ops::BitOrAssign<HlMod> for HlMods {
fn bitor_assign(&mut self, rhs: HlMod) {
self.0 |= rhs.mask();
}
}
impl ops::BitOrAssign<HlMod> for Highlight {
fn bitor_assign(&mut self, rhs: HlMod) {
self.mods |= rhs;
}
}
impl ops::BitOr<HlMod> for Highlight {
type Output = Highlight;
fn bitor(mut self, rhs: HlMod) -> Highlight {
self |= rhs;
self
}
}
impl HlMods {
pub fn is_empty(&self) -> bool {
self.0 == 0
}
pub fn contains(self, m: HlMod) -> bool {
self.0 & m.mask() == m.mask()
}
pub fn iter(self) -> impl Iterator<Item = HlMod> {
HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask())
}
}