From b3339bc4c7a85bbe25f7cc4ef1357e81aa541283 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Wed, 10 Apr 2024 14:15:16 -0400 Subject: [PATCH] Add serde support --- Cargo.lock | 30 ++----- Cargo.toml | 7 +- src/lib.rs | 40 +++++++--- src/serde_suck.rs | 195 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 237 insertions(+), 35 deletions(-) create mode 100644 src/serde_suck.rs diff --git a/Cargo.lock b/Cargo.lock index 10c8388..a76eb77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - [[package]] name = "bitflags" version = "2.5.0" @@ -41,7 +35,8 @@ dependencies = [ "cosmic-text", "jotdown", "log", - "range-map", + "rangemap", + "serde", ] [[package]] @@ -158,15 +153,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - [[package]] name = "proc-macro2" version = "1.0.79" @@ -185,20 +171,14 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "range-map" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a5a2d6c7039059af621472a4389be1215a816df61aa4d531cfe85264aee95f" -dependencies = [ - "num-traits", -] - [[package]] name = "rangemap" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" +dependencies = [ + "serde", +] [[package]] name = "read-fonts" diff --git a/Cargo.toml b/Cargo.toml index 99abcfc..408bce8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,9 @@ edition = "2021" cosmic-text = "0.11.2" jotdown = { git = "https://git.nations.lol/fnmain/jotdown" } log = "0.4.21" -range-map = "0.2.0" +serde = { version = "1.0.197", features = ["derive"], optional = true } +rangemap = "1.5.1" + +[features] +default = ["serde"] +serde = ["dep:serde", "rangemap/serde1"] diff --git a/src/lib.rs b/src/lib.rs index a2a35bc..789e030 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,18 @@ use std::borrow::Cow; -use cosmic_text::{Attrs, Buffer, Color, Family, FontSystem, Metrics, Shaping, Style, Weight}; +use cosmic_text::{ + Attrs, AttrsOwned, Buffer, Color, Family, FontSystem, Metrics, Shaping, Style, Weight, +}; use jotdown::{Container, Event, ListKind}; pub use jotdown; -use range_map::RangeMap; +use rangemap::RangeMap; +#[cfg(feature = "serde")] +mod serde_suck; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +pub use serde_suck::*; pub struct JotdownBufferIter<'a, T: Iterator>> { djot: T, @@ -18,13 +26,15 @@ struct JotdownIntoBuffer<'a, 'b, T: Iterator>> { indent: &'b mut Vec, image_url: Option>, link_start: usize, - urls: Vec<(range_map::Range, &'a str)>, + urls: Vec<(std::ops::Range, Cow<'a, str>)>, location: usize, added: bool, } #[derive(Default, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Indent { + #[cfg_attr(feature = "serde", serde(with = "ListKindOption"))] pub modifier: Option, pub indent: f32, } @@ -115,7 +125,7 @@ impl<'a, 'b, T: Iterator>> Iterator for JotdownIntoBuffer<'a, ' } Container::Link(Cow::Borrowed(url), _) => { self.urls - .push((range_map::Range::new(self.link_start, self.location), url)); + .push((self.link_start..self.location, Cow::Borrowed(url))); self.attrs = self.attrs.color(Color::rgb(255, 255, 255)); } _ => {} @@ -130,12 +140,20 @@ impl<'a, 'b, T: Iterator>> Iterator for JotdownIntoBuffer<'a, ' } } +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct RichText( + String, + #[cfg_attr(feature = "serde", serde(with = "AttrsSerde"))] AttrsOwned, +); + +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct JotdownItem<'a> { pub indent: Indent, - pub buffer: Vec<(&'a str, Attrs<'static>)>, + pub buffer: Vec, + #[cfg_attr(feature = "serde", serde(with = "MetricsSerde"))] pub metrics: Metrics, pub image_url: Option>, - pub url_map: Option>, + pub url_map: Option>>, } impl<'a> JotdownItem<'a> { @@ -154,7 +172,7 @@ impl<'a> JotdownItem<'a> { ); buffer.set_rich_text( font_system, - self.buffer.iter().cloned(), + self.buffer.iter().map(|r| (r.0.as_str(), r.1.as_attrs())), Attrs::new().family(Family::SansSerif), Shaping::Advanced, ); @@ -182,7 +200,9 @@ impl<'a, T: Iterator>> Iterator for JotdownBufferIter<'a, T> { urls: Vec::new(), }; - let buffer: Vec<(&str, Attrs<'static>)> = (&mut jot).collect(); + let buffer = (&mut jot) + .map(|r| RichText(r.0.to_owned(), AttrsOwned::new(r.1))) + .collect::>(); let image_url = jot.image_url; let urls = jot.urls; let added = jot.added; @@ -196,7 +216,9 @@ impl<'a, T: Iterator>> Iterator for JotdownBufferIter<'a, T> { url_map: if urls.is_empty() { None } else { - RangeMap::try_from_iter(urls.into_iter()).ok() + let mut map = RangeMap::new(); + map.extend(urls.into_iter()); + Some(map) }, buffer, image_url, diff --git a/src/serde_suck.rs b/src/serde_suck.rs new file mode 100644 index 0000000..a4a891d --- /dev/null +++ b/src/serde_suck.rs @@ -0,0 +1,195 @@ +use cosmic_text::{ + Align, Attrs, AttrsOwned, CacheKeyFlags, Color, FamilyOwned, Metrics, Stretch, Style, Weight, +}; + +use jotdown::{ListKind, OrderedListNumbering, OrderedListStyle}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Option")] +pub enum ListKindOption { + Some(#[serde(with = "ListKindSerde")] ListKind), + None, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "jotdown::ListKind")] +pub enum ListKindSerde { + Unordered, + Ordered { + numbering: OrderedListNumbering, + style: OrderedListStyle, + start: u64, + }, + Task, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "jotdown::OrderedListNumbering")] +pub enum OrderedListNumberingSerde { + Decimal, + AlphaLower, + AlphaUpper, + RomanLower, + RomanUpper, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "jotdown::OrderedListStyle")] +pub enum OrderedListStyleSerde { + Period, + Paren, + ParenParen, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Metrics")] +pub struct MetricsSerde { + pub font_size: f32, + pub line_height: f32, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "FamilyOwned")] +pub enum FamilySerde { + Name(String), + Serif, + SansSerif, + Cursive, + Fantasy, + Monospace, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Stretch")] +pub enum StretchSerde { + UltraCondensed, + ExtraCondensed, + Condensed, + SemiCondensed, + Normal, + SemiExpanded, + Expanded, + ExtraExpanded, + UltraExpanded, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Style")] +pub enum StyleSerde { + Normal, + Italic, + Oblique, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Weight")] +pub struct WeightSerde(pub u16); + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Color")] +pub struct ColorSerde(pub u32); + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Option")] +pub enum ColorOpt { + Some(#[serde(with = "ColorSerde")] Color), + None, +} + +mod cache_key_flags { + use cosmic_text::CacheKeyFlags; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(_: &CacheKeyFlags, serializer: S) -> Result + where + S: Serializer, + { + ().serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let _: () = <()>::deserialize(deserializer)?; + Ok(CacheKeyFlags::empty()) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "AttrsOwned")] +pub struct AttrsSerde { + #[serde(with = "ColorOpt")] + pub color_opt: Option, + #[serde(with = "FamilySerde")] + pub family_owned: FamilyOwned, + #[serde(with = "StretchSerde")] + pub stretch: Stretch, + #[serde(with = "StyleSerde")] + pub style: Style, + #[serde(with = "WeightSerde")] + pub weight: Weight, + pub metadata: usize, + #[serde(with = "cache_key_flags")] + pub cache_key_flags: CacheKeyFlags, +} + +impl<'a> From> for AttrsSerde { + fn from(value: Attrs<'a>) -> Self { + Self { + color_opt: value.color_opt, + family_owned: FamilyOwned::new(value.family), + stretch: value.stretch, + style: value.style, + weight: value.weight, + metadata: value.metadata, + cache_key_flags: value.cache_key_flags, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Option")] +pub enum AlignSerde { + Some(#[serde(with = "AlignRef")] Align), + None, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(remote = "Align")] +pub enum AlignRef { + Left, + Right, + Center, + Justified, + End, +} + +impl AttrsSerde { + pub fn as_attrs(&self) -> Attrs<'_> { + Attrs { + color_opt: self.color_opt, + family: self.family_owned.as_family(), + stretch: self.stretch, + style: self.style, + weight: self.weight, + metadata: self.metadata, + cache_key_flags: CacheKeyFlags::empty(), + } + } +} + +impl From for AttrsSerde { + fn from(value: AttrsOwned) -> Self { + Self { + color_opt: value.color_opt, + family_owned: value.family_owned, + stretch: value.stretch, + style: value.style, + weight: value.weight, + metadata: value.metadata, + cache_key_flags: value.cache_key_flags, + } + } +}