#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum Role {
#[default]
Body,
Heading(u8),
Code,
Link,
Mark(Option<MarkColor>),
ListMarker,
QuoteGutter,
Rule,
Delimiter,
Image,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum MarkColor {
Red,
Orange,
Yellow,
Green,
Blue,
Purple,
Brown,
}
impl MarkColor {
pub fn from_attrs(attrs: &[(String, Option<String>)]) -> Option<Self> {
attrs
.iter()
.find(|(k, _)| k == "data-color")
.and_then(|(_, v)| v.as_deref())
.and_then(Self::from_attr)
}
pub fn from_attr(value: &str) -> Option<Self> {
Some(match value {
"red" => Self::Red,
"orange" => Self::Orange,
"yellow" => Self::Yellow,
"green" => Self::Green,
"blue" => Self::Blue,
"purple" => Self::Purple,
"brown" => Self::Brown,
_ => return None,
})
}
pub const fn name(self) -> &'static str {
match self {
Self::Red => "red",
Self::Orange => "orange",
Self::Yellow => "yellow",
Self::Green => "green",
Self::Blue => "blue",
Self::Purple => "purple",
Self::Brown => "brown",
}
}
pub const fn index(self) -> usize {
match self {
Self::Red => 0,
Self::Orange => 1,
Self::Yellow => 2,
Self::Green => 3,
Self::Blue => 4,
Self::Purple => 5,
Self::Brown => 6,
}
}
pub const ALL: [Self; 7] = [
Self::Red,
Self::Orange,
Self::Yellow,
Self::Green,
Self::Blue,
Self::Purple,
Self::Brown,
];
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Token {
Punctuation,
Keyword,
Entity,
Support,
Constant,
String,
Comment,
Invalid,
}
impl Token {
pub const fn name(self) -> &'static str {
match self {
Self::Punctuation => "punctuation",
Self::Keyword => "keyword",
Self::Entity => "entity",
Self::Support => "support",
Self::Constant => "constant",
Self::String => "string",
Self::Comment => "comment",
Self::Invalid => "invalid",
}
}
pub fn from_name(name: &str) -> Option<Self> {
Self::ALL.into_iter().find(|t| t.name() == name)
}
pub const fn index(self) -> usize {
match self {
Self::Punctuation => 0,
Self::Keyword => 1,
Self::Entity => 2,
Self::Support => 3,
Self::Constant => 4,
Self::String => 5,
Self::Comment => 6,
Self::Invalid => 7,
}
}
pub const ALL: [Self; 8] = [
Self::Punctuation,
Self::Keyword,
Self::Entity,
Self::Support,
Self::Constant,
Self::String,
Self::Comment,
Self::Invalid,
];
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum Baseline {
#[default]
Normal,
Super,
Sub,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct Style {
pub bold: bool,
pub italic: bool,
pub underline: bool,
pub strikethrough: bool,
pub role: Role,
pub baseline: Baseline,
pub token: Option<Token>,
}
impl Style {
pub const fn bold(mut self) -> Self {
self.bold = true;
self
}
pub const fn italic(mut self) -> Self {
self.italic = true;
self
}
pub const fn underline(mut self) -> Self {
self.underline = true;
self
}
pub const fn strikethrough(mut self) -> Self {
self.strikethrough = true;
self
}
pub const fn role(mut self, r: Role) -> Self {
self.role = r;
self
}
pub const fn baseline(mut self, b: Baseline) -> Self {
self.baseline = b;
self
}
pub const fn token(mut self, t: Option<Token>) -> Self {
self.token = t;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_colour_tables_agree_with_each_other() {
for (i, c) in MarkColor::ALL.into_iter().enumerate() {
assert_eq!(c.index(), i, "{} is not where ALL puts it", c.name());
assert_eq!(MarkColor::from_attr(c.name()), Some(c), "name round-trip");
}
assert_eq!(MarkColor::from_attr("chartreuse"), None);
assert_eq!(MarkColor::from_attr(""), None);
}
#[test]
fn the_token_tables_agree_with_each_other() {
for (i, t) in Token::ALL.into_iter().enumerate() {
assert_eq!(t.index(), i, "{} is not where ALL puts it", t.name());
assert_eq!(Token::from_name(t.name()), Some(t), "name round-trip");
}
assert_eq!(Token::from_name("meta"), None);
assert_eq!(Token::from_name(""), None);
}
#[test]
fn a_colour_is_read_out_of_the_data_color_attribute_and_nothing_else() {
let attr = |k: &str, v: &str| vec![(k.to_string(), Some(v.to_string()))];
assert_eq!(
MarkColor::from_attrs(&attr("data-color", "green")),
Some(MarkColor::Green)
);
assert_eq!(MarkColor::from_attrs(&[]), None);
assert_eq!(MarkColor::from_attrs(&attr("id", "red")), None);
assert_eq!(
MarkColor::from_attrs(&[("data-color".to_string(), None)]),
None
);
}
}