#![forbid(unsafe_code)]
pub use hikari_core::{ByteSpan, HighlightSpan, HlClass};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum Semantic {
Keyword,
Symbol,
KeywordArg,
String,
Number,
Literal,
Comment,
Accent,
Muted,
Error,
Warning,
Info,
Hint,
Added,
Removed,
Unchanged,
}
impl Semantic {
#[must_use]
pub const fn all() -> [Semantic; 16] {
use Semantic::{
Accent, Added, Comment, Error, Hint, Info, Keyword, KeywordArg, Literal, Muted, Number,
Removed, String, Symbol, Unchanged, Warning,
};
[
Keyword, Symbol, KeywordArg, String, Number, Literal, Comment, Accent, Muted, Error,
Warning, Info, Hint, Added, Removed, Unchanged,
]
}
}
impl From<Semantic> for HlClass {
fn from(s: Semantic) -> Self {
match s {
Semantic::Keyword => HlClass::Keyword,
Semantic::Symbol => HlClass::Punctuation,
Semantic::KeywordArg => HlClass::KeywordArg,
Semantic::String => HlClass::Str,
Semantic::Number => HlClass::Numeric { float: false },
Semantic::Literal => HlClass::Constant,
Semantic::Comment => HlClass::Comment { multiline: false },
Semantic::Accent => HlClass::Special,
Semantic::Muted => HlClass::Plain,
Semantic::Error => HlClass::Error,
Semantic::Warning => HlClass::Warning,
Semantic::Info => HlClass::Info,
Semantic::Hint => HlClass::Hint,
Semantic::Added => HlClass::Added,
Semantic::Removed => HlClass::Removed,
Semantic::Unchanged => HlClass::Unchanged,
}
}
}
#[must_use]
pub fn hlclass_to_semantic(c: HlClass) -> Semantic {
match c {
HlClass::Keyword => Semantic::Keyword,
HlClass::KeywordArg => Semantic::KeywordArg,
HlClass::Str => Semantic::String,
HlClass::Numeric { .. } => Semantic::Number,
HlClass::Boolean | HlClass::Constant => Semantic::Literal,
HlClass::Comment { .. } => Semantic::Comment,
HlClass::Type
| HlClass::Function
| HlClass::Namespace
| HlClass::Attribute
| HlClass::Escape
| HlClass::Special
| HlClass::Hyperlink => Semantic::Accent,
HlClass::Punctuation | HlClass::Operator => Semantic::Symbol,
HlClass::Error => Semantic::Error,
HlClass::Warning => Semantic::Warning,
HlClass::Info => Semantic::Info,
HlClass::Hint => Semantic::Hint,
HlClass::Added => Semantic::Added,
HlClass::Removed => Semantic::Removed,
HlClass::Plain => Semantic::Muted,
HlClass::Variable | HlClass::Whitespace | HlClass::Unchanged => Semantic::Unchanged,
}
}
#[cfg(test)]
mod tests {
use super::{HlClass, Semantic, hlclass_to_semantic};
#[test]
fn semantic_hlclass_roundtrips_to_identity() {
for s in Semantic::all() {
let hl: HlClass = s.into();
assert_eq!(
hlclass_to_semantic(hl),
s,
"Semantic -> HlClass -> Semantic must be identity for {s:?}",
);
}
}
#[test]
fn serde_is_snake_case_stable() {
assert_eq!(
serde_json::to_string(&Semantic::KeywordArg).unwrap(),
"\"keyword_arg\"",
);
let back: Semantic = serde_json::from_str("\"unchanged\"").unwrap();
assert_eq!(back, Semantic::Unchanged);
}
}