mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-12-12 23:51:55 +00:00
197 lines
5.1 KiB
Rust
197 lines
5.1 KiB
Rust
#![allow(non_snake_case)]
|
|
|
|
use crate::{block_attribute, core::Attributes, ignore_attribute, inline_attribute, list_attribute};
|
|
use lazy_static::lazy_static;
|
|
|
|
use serde_json::Error;
|
|
use std::{collections::HashSet, fmt, fmt::Formatter, iter::FromIterator};
|
|
use strum_macros::Display;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Attribute {
|
|
pub key: AttributeKey,
|
|
pub value: AttributeValue,
|
|
pub scope: AttributeScope,
|
|
}
|
|
|
|
impl Attribute {
|
|
// inline
|
|
inline_attribute!(Bold, bool);
|
|
inline_attribute!(Italic, bool);
|
|
inline_attribute!(Underline, bool);
|
|
inline_attribute!(StrikeThrough, bool);
|
|
inline_attribute!(Link, &str);
|
|
inline_attribute!(Color, String);
|
|
inline_attribute!(Font, usize);
|
|
inline_attribute!(Size, usize);
|
|
inline_attribute!(Background, String);
|
|
|
|
// block
|
|
block_attribute!(Header, usize);
|
|
block_attribute!(Indent, usize);
|
|
block_attribute!(Align, String);
|
|
block_attribute!(List, &str);
|
|
block_attribute!(CodeBlock, bool);
|
|
block_attribute!(QuoteBlock, bool);
|
|
|
|
// ignore
|
|
ignore_attribute!(Width, usize);
|
|
ignore_attribute!(Height, usize);
|
|
|
|
// List extension
|
|
list_attribute!(Bullet, "bullet");
|
|
list_attribute!(Ordered, "ordered");
|
|
list_attribute!(Checked, "checked");
|
|
list_attribute!(UnChecked, "unchecked");
|
|
|
|
pub fn to_json(&self) -> String {
|
|
match serde_json::to_string(self) {
|
|
Ok(json) => json,
|
|
Err(e) => {
|
|
log::error!("Attribute serialize to str failed: {}", e);
|
|
"".to_owned()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Attribute {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
let s = format!("{:?}:{:?} {:?}", self.key, self.value.0, self.scope);
|
|
f.write_str(&s)
|
|
}
|
|
}
|
|
|
|
impl std::convert::Into<Attributes> 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.rs/variant-attrs.html
|
|
// #[serde(rename_all = "snake_case")]
|
|
pub enum AttributeKey {
|
|
#[serde(rename = "bold")]
|
|
Bold,
|
|
#[serde(rename = "italic")]
|
|
Italic,
|
|
#[serde(rename = "underline")]
|
|
Underline,
|
|
#[serde(rename = "strikethrough")]
|
|
StrikeThrough,
|
|
#[serde(rename = "font")]
|
|
Font,
|
|
#[serde(rename = "size")]
|
|
Size,
|
|
#[serde(rename = "link")]
|
|
Link,
|
|
#[serde(rename = "color")]
|
|
Color,
|
|
#[serde(rename = "background")]
|
|
Background,
|
|
#[serde(rename = "indent")]
|
|
Indent,
|
|
#[serde(rename = "align")]
|
|
Align,
|
|
#[serde(rename = "code_block")]
|
|
CodeBlock,
|
|
#[serde(rename = "list")]
|
|
List,
|
|
#[serde(rename = "quote_block")]
|
|
QuoteBlock,
|
|
#[serde(rename = "width")]
|
|
Width,
|
|
#[serde(rename = "height")]
|
|
Height,
|
|
#[serde(rename = "header")]
|
|
Header,
|
|
}
|
|
|
|
// pub trait AttributeValueData<'a>: Serialize + Deserialize<'a> {}
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct AttributeValue(pub Option<String>);
|
|
|
|
impl std::convert::From<&usize> for AttributeValue {
|
|
fn from(val: &usize) -> Self { AttributeValue::from(*val) }
|
|
}
|
|
|
|
impl std::convert::From<usize> for AttributeValue {
|
|
fn from(val: usize) -> Self {
|
|
if val > (0 as usize) {
|
|
AttributeValue(Some(format!("{}", val)))
|
|
} else {
|
|
AttributeValue(None)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::convert::From<&str> for AttributeValue {
|
|
fn from(val: &str) -> Self { val.to_owned().into() }
|
|
}
|
|
|
|
impl std::convert::From<String> for AttributeValue {
|
|
fn from(val: String) -> Self {
|
|
if val.is_empty() {
|
|
AttributeValue(None)
|
|
} else {
|
|
AttributeValue(Some(val))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::convert::From<&bool> for AttributeValue {
|
|
fn from(val: &bool) -> Self { AttributeValue::from(*val) }
|
|
}
|
|
|
|
impl std::convert::From<bool> for AttributeValue {
|
|
fn from(val: bool) -> Self {
|
|
let val = match val {
|
|
true => Some("true".to_owned()),
|
|
false => None,
|
|
};
|
|
AttributeValue(val)
|
|
}
|
|
}
|
|
|
|
pub fn is_block_except_header(k: &AttributeKey) -> bool {
|
|
if k == &AttributeKey::Header {
|
|
return false;
|
|
}
|
|
BLOCK_KEYS.contains(k)
|
|
}
|
|
|
|
lazy_static! {
|
|
static ref BLOCK_KEYS: HashSet<AttributeKey> = HashSet::from_iter(vec![
|
|
AttributeKey::Header,
|
|
AttributeKey::Indent,
|
|
AttributeKey::Align,
|
|
AttributeKey::CodeBlock,
|
|
AttributeKey::List,
|
|
AttributeKey::QuoteBlock,
|
|
]);
|
|
static ref INLINE_KEYS: HashSet<AttributeKey> = HashSet::from_iter(vec![
|
|
AttributeKey::Bold,
|
|
AttributeKey::Italic,
|
|
AttributeKey::Underline,
|
|
AttributeKey::StrikeThrough,
|
|
AttributeKey::Link,
|
|
AttributeKey::Color,
|
|
AttributeKey::Font,
|
|
AttributeKey::Size,
|
|
AttributeKey::Background,
|
|
]);
|
|
static ref INGORE_KEYS: HashSet<AttributeKey> =
|
|
HashSet::from_iter(vec![AttributeKey::Width, AttributeKey::Height,]);
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub enum AttributeScope {
|
|
Inline,
|
|
Block,
|
|
Embeds,
|
|
Ignore,
|
|
}
|