use crate::core::{Attributes, REMOVE_FLAG}; use derive_more::Display; use lazy_static::lazy_static; use std::{collections::HashSet, fmt, fmt::Formatter, iter::FromIterator}; lazy_static! { static ref BLOCK_KEYS: HashSet = HashSet::from_iter(vec![ AttributeKey::Header, AttributeKey::Align, AttributeKey::List, AttributeKey::CodeBlock, AttributeKey::QuoteBlock, AttributeKey::Indent, ]); static ref INLINE_KEYS: HashSet = HashSet::from_iter(vec![ AttributeKey::Bold, AttributeKey::Italic, AttributeKey::Underline, AttributeKey::StrikeThrough, AttributeKey::Link, AttributeKey::Color, AttributeKey::Background, ]); } #[derive(Debug, PartialEq, Eq, Clone)] pub enum AttributeScope { Inline, Block, Embeds, Ignore, } #[derive(Debug, Clone)] pub struct Attribute { pub key: AttributeKey, pub value: AttributeValue, pub scope: AttributeScope, } impl fmt::Display for Attribute { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let s = format!("{:?}:{} {:?}", self.key, self.value.as_ref(), self.scope); f.write_str(&s) } } impl std::convert::Into for Attribute { fn into(self) -> Attributes { let mut attributes = Attributes::new(); attributes.add(self); attributes } } #[derive(Clone, Debug, Display, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub enum AttributeKey { #[display(fmt = "bold")] Bold, #[display(fmt = "italic")] Italic, #[display(fmt = "underline")] Underline, #[display(fmt = "strike_through")] StrikeThrough, #[display(fmt = "font")] Font, #[display(fmt = "size")] Size, #[display(fmt = "link")] Link, #[display(fmt = "color")] Color, #[display(fmt = "background")] Background, #[display(fmt = "indent")] Indent, #[display(fmt = "align")] Align, #[display(fmt = "code_block")] CodeBlock, #[display(fmt = "list")] List, #[display(fmt = "quote_block")] QuoteBlock, #[display(fmt = "width")] Width, #[display(fmt = "height")] Height, #[display(fmt = "style")] Style, #[display(fmt = "header")] Header, #[display(fmt = "left")] LeftAlignment, #[display(fmt = "center")] CenterAlignment, #[display(fmt = "right")] RightAlignment, #[display(fmt = "justify")] JustifyAlignment, #[display(fmt = "bullet")] Bullet, #[display(fmt = "ordered")] Ordered, #[display(fmt = "checked")] Checked, #[display(fmt = "unchecked")] UnChecked, } impl AttributeKey { pub fn remove(&self) -> Attribute { self.value(REMOVE_FLAG) } pub fn value>(&self, value: T) -> Attribute { let key = self.clone(); let value: AttributeValue = value.into(); match self { AttributeKey::Bold | AttributeKey::Italic | AttributeKey::Underline | AttributeKey::StrikeThrough | AttributeKey::Link | AttributeKey::Color | AttributeKey::Background | AttributeKey::Font | AttributeKey::Size => Attribute { key, value, scope: AttributeScope::Inline, }, AttributeKey::Header | AttributeKey::LeftAlignment | AttributeKey::CenterAlignment | AttributeKey::RightAlignment | AttributeKey::JustifyAlignment | AttributeKey::Indent | AttributeKey::Align | AttributeKey::CodeBlock | AttributeKey::List | AttributeKey::Bullet | AttributeKey::Ordered | AttributeKey::Checked | AttributeKey::UnChecked | AttributeKey::QuoteBlock => Attribute { key, value, scope: AttributeScope::Block, }, AttributeKey::Width | AttributeKey::Height | AttributeKey::Style => Attribute { key, value, scope: AttributeScope::Ignore, }, } } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AttributeValue(pub(crate) String); impl AsRef for AttributeValue { fn as_ref(&self) -> &str { &self.0 } } impl std::convert::From<&usize> for AttributeValue { fn from(val: &usize) -> Self { AttributeValue(format!("{}", val)) } } impl std::convert::From<&str> for AttributeValue { fn from(val: &str) -> Self { AttributeValue(val.to_owned()) } } impl std::convert::From for AttributeValue { fn from(val: bool) -> Self { let val = match val { true => "true", false => "", }; AttributeValue(val.to_owned()) } }