Add databake support

This commit is contained in:
Isaac Mills 2024-04-19 22:36:35 -04:00
parent f6c85b5238
commit 4266b9ea90
Signed by: fnmain
GPG key ID: B67D7410F33A0F61
4 changed files with 207 additions and 57 deletions

1
Cargo.lock generated
View file

@ -51,6 +51,7 @@ name = "cosmic-jotdown"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmic-text", "cosmic-text",
"databake",
"emath", "emath",
"image", "image",
"jotdown", "jotdown",

View file

@ -14,6 +14,8 @@ rangemap = "1.5.1"
nominals = "0.3.0" nominals = "0.3.0"
emath = "0.27.2" emath = "0.27.2"
image = { version = "0.24.9", default-features = false } image = { version = "0.24.9", default-features = false }
databake = { version = "0.1.7", features = ["derive"], optional = true }
[features] [features]
serde = ["dep:serde", "rangemap/serde1"] serde = ["dep:serde", "rangemap/serde1"]
databake = ["dep:databake"]

View file

@ -3,15 +3,17 @@ use std::borrow::Cow;
use cosmic_text::{self, Align}; use cosmic_text::{self, Align};
use cosmic_text::{Attrs, Buffer, Color, Family, FontSystem, Metrics, Shaping, Style, Weight}; use cosmic_text::{Attrs, Buffer, Color, Family, FontSystem, Metrics, Shaping, Style, Weight};
#[cfg(feature = "databake")]
use databake::Bake;
use emath::{Pos2, Rect, Vec2}; use emath::{Pos2, Rect, Vec2};
use jotdown::{Container, Event, ListKind, OrderedListNumbering, OrderedListStyle}; use jotdown::{Container, Event, ListKind, OrderedListNumbering, OrderedListStyle};
use nominals::{LetterLower, LetterUpper, Nominal, RomanLower, RomanUpper}; use nominals::{LetterLower, LetterUpper, Nominal, RomanLower, RomanUpper};
#[cfg(feature = "serde")] #[cfg(any(feature = "serde", feature = "databake"))]
pub mod serde_suck; pub mod serde_suck;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")] #[cfg(any(feature = "serde", feature = "databake"))]
pub use serde_suck::*; pub use serde_suck::*;
use rangemap::RangeMap; use rangemap::RangeMap;
@ -42,6 +44,20 @@ pub struct Indent {
pub indent: f32, pub indent: f32,
} }
#[cfg(feature = "databake")]
impl databake::Bake for Indent {
fn bake(&self, ctx: &databake::CrateEnv) -> databake::TokenStream {
let indent = self.indent;
let modifier = self.modifier.bake(ctx);
databake::quote! {
cosmic_jotdown::Indent {
indent: #indent
modifier: #modifier
}
}
}
}
pub const INDENT_AMOUNT: f32 = 16.0; pub const INDENT_AMOUNT: f32 = 16.0;
impl<'a, 'b, T: Iterator<Item = Event<'a>>> Iterator for JotdownIntoBuffer<'a, 'b, T> { impl<'a, 'b, T: Iterator<Item = Event<'a>>> Iterator for JotdownIntoBuffer<'a, 'b, T> {
@ -166,17 +182,30 @@ pub struct RichText<'a>(
#[cfg_attr(feature = "serde", serde(with = "AttrsSerde"))] pub Attrs<'a>, #[cfg_attr(feature = "serde", serde(with = "AttrsSerde"))] pub Attrs<'a>,
); );
#[cfg(feature = "databake")]
impl<'a> Bake for RichText<'a> {
fn bake(&self, ctx: &databake::CrateEnv) -> databake::TokenStream {
let field0 = self.0.bake(ctx);
let field1: AttrsSerde = self.1.into();
let field1 = field1.bake(ctx);
databake::quote! {
cosmic_jotdown::RichText(#field0, #field1)
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "databake", derive(databake::Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_jotdown::JotdownItem))]
pub struct JotdownItem<'a> { pub struct JotdownItem<'a> {
pub indent: Indent, pub indent: Indent,
#[cfg_attr(feature = "serde", serde(borrow))] #[cfg_attr(feature = "serde", serde(borrow))]
pub buffer: Vec<RichText<'a>>, pub buffer: Cow<'a, [RichText<'a>]>,
#[cfg_attr(feature = "serde", serde(with = "MetricsSerde"))] pub metrics: (f32, f32),
pub metrics: Metrics,
pub image_url: Option<Cow<'a, str>>, pub image_url: Option<Cow<'a, str>>,
pub margin: f32, pub margin: f32,
pub url_map: Option<RangeMap<usize, Cow<'a, str>>>, pub url_map: Option<Cow<'a, [(usize, usize, Cow<'a, str>)]>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -394,10 +423,16 @@ impl<'a> JotdownItem<'a> {
relative_bounds: measure_buffer(&buffer, Vec2::new(width, f32::MAX)), relative_bounds: measure_buffer(&buffer, Vec2::new(width, f32::MAX)),
buffer, buffer,
metrics: Metrics::new( metrics: Metrics::new(
self.metrics.font_size * metrics.font_size, self.metrics.0 * metrics.font_size,
self.metrics.line_height * metrics.line_height, self.metrics.1 * metrics.line_height,
), ),
url_map: self.url_map, url_map: {
self.url_map.map(|self_url_map| {
let mut url_map = RangeMap::new();
url_map.extend(self_url_map.iter().map(|m| (m.0..m.1, m.2.clone())));
url_map
})
},
image_urls: None, image_urls: None,
} }
} }
@ -408,8 +443,8 @@ impl<'a> JotdownItem<'a> {
modifier: None, modifier: None,
indent: 0.0, indent: 0.0,
}, },
buffer: text, buffer: Cow::Owned(text),
metrics: Metrics::new(1.0, 1.1), metrics: (1.0, 1.1),
url_map: None, url_map: None,
margin: 0.0, margin: 0.0,
image_url: None, image_url: None,
@ -428,8 +463,8 @@ impl<'a> JotdownItem<'a> {
let mut buffer = Buffer::new( let mut buffer = Buffer::new(
font_system, font_system,
Metrics::new( Metrics::new(
metrics.font_size * self.metrics.font_size, metrics.font_size * self.metrics.0,
metrics.line_height * self.metrics.line_height, metrics.line_height * self.metrics.1,
), ),
); );
buffer.set_rich_text( buffer.set_rich_text(
@ -486,16 +521,16 @@ impl<'a, T: Iterator<Item = Event<'a>>> Iterator for JotdownBufferIter<'a, T> {
url_map: if urls.is_empty() { url_map: if urls.is_empty() {
None None
} else { } else {
let mut map = RangeMap::new(); let mut map = Vec::new();
map.extend( map.extend(
urls.into_iter() urls.into_iter()
.map(|(range, url)| (range.start..range.end + 1, url)), .map(|(range, url)| (range.start, range.end + 1, url)),
); );
Some(map) Some(Cow::Owned(map))
}, },
buffer, buffer: Cow::Owned(buffer),
image_url, image_url,
metrics, metrics: (metrics.font_size, metrics.line_height),
margin: match top_level_containers { margin: match top_level_containers {
Some(Container::Heading { level, .. }) => match level { Some(Container::Heading { level, .. }) => match level {
1 => 0.34, 1 => 0.34,

View file

@ -1,17 +1,22 @@
use cosmic_text::{Align, Attrs, CacheKeyFlags, Color, Family, Metrics, Stretch, Style, Weight}; use cosmic_text::{Align, Attrs, CacheKeyFlags, Color, Family, Stretch, Style, Weight};
#[cfg(feature = "databake")]
use databake::Bake;
use jotdown::{ListKind, OrderedListNumbering, OrderedListStyle}; use jotdown::{ListKind, OrderedListNumbering, OrderedListStyle};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "Option<ListKind>")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Option<ListKind>"))]
pub enum ListKindOption { pub enum ListKindOption {
Some(#[serde(with = "ListKindSerde")] ListKind), Some(#[cfg_attr(feature = "serde", serde(with = "ListKindSerde"))] ListKind),
None, None,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "jotdown::ListKind")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "jotdown::ListKind"))]
pub enum ListKindSerde { pub enum ListKindSerde {
Unordered, Unordered,
Ordered { Ordered {
@ -22,8 +27,9 @@ pub enum ListKindSerde {
Task, Task,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "jotdown::OrderedListNumbering")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "jotdown::OrderedListNumbering"))]
pub enum OrderedListNumberingSerde { pub enum OrderedListNumberingSerde {
Decimal, Decimal,
AlphaLower, AlphaLower,
@ -32,23 +38,30 @@ pub enum OrderedListNumberingSerde {
RomanUpper, RomanUpper,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "jotdown::OrderedListStyle")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "jotdown::OrderedListStyle"))]
pub enum OrderedListStyleSerde { pub enum OrderedListStyleSerde {
Period, Period,
Paren, Paren,
ParenParen, ParenParen,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "Metrics")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "cosmic_text::Metrics"))]
#[cfg_attr(feature = "databake", derive(Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_text::Metrics))]
pub struct MetricsSerde { pub struct MetricsSerde {
pub font_size: f32, pub font_size: f32,
pub line_height: f32, pub line_height: f32,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "Family")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Family"))]
#[cfg_attr(feature = "databake", derive(Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_text::Family))]
pub enum FamilySerde<'a> { pub enum FamilySerde<'a> {
Name(&'a str), Name(&'a str),
Serif, Serif,
@ -58,8 +71,24 @@ pub enum FamilySerde<'a> {
Monospace, Monospace,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] impl<'a> From<Family<'a>> for FamilySerde<'a> {
#[serde(remote = "Stretch")] fn from(value: Family<'a>) -> Self {
match value {
Family::Name(n) => FamilySerde::Name(n),
Family::Serif => FamilySerde::Serif,
Family::SansSerif => FamilySerde::SansSerif,
Family::Cursive => FamilySerde::Cursive,
Family::Fantasy => FamilySerde::Fantasy,
Family::Monospace => FamilySerde::Monospace,
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Stretch"))]
#[cfg_attr(feature = "databake", derive(Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_text::Stretch))]
pub enum StretchSerde { pub enum StretchSerde {
UltraCondensed, UltraCondensed,
ExtraCondensed, ExtraCondensed,
@ -72,29 +101,66 @@ pub enum StretchSerde {
UltraExpanded, UltraExpanded,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] impl From<Stretch> for StretchSerde {
#[serde(remote = "Style")] fn from(value: Stretch) -> Self {
match value {
Stretch::UltraCondensed => StretchSerde::UltraCondensed,
Stretch::ExtraCondensed => StretchSerde::ExtraCondensed,
Stretch::Condensed => StretchSerde::Condensed,
Stretch::SemiCondensed => StretchSerde::SemiCondensed,
Stretch::Normal => StretchSerde::Normal,
Stretch::SemiExpanded => StretchSerde::SemiExpanded,
Stretch::Expanded => StretchSerde::Expanded,
Stretch::ExtraExpanded => StretchSerde::ExtraExpanded,
Stretch::UltraExpanded => StretchSerde::UltraExpanded,
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Style"))]
#[cfg_attr(feature = "databake", derive(Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_text::Style))]
pub enum StyleSerde { pub enum StyleSerde {
Normal, Normal,
Italic, Italic,
Oblique, Oblique,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] impl From<Style> for StyleSerde {
#[serde(remote = "Weight")] fn from(value: Style) -> Self {
match value {
Style::Normal => StyleSerde::Normal,
Style::Italic => StyleSerde::Italic,
Style::Oblique => StyleSerde::Oblique,
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Weight"))]
#[cfg_attr(feature = "databake", derive(Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_text::Weight))]
pub struct WeightSerde(pub u16); pub struct WeightSerde(pub u16);
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "Color")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Color"))]
#[cfg_attr(feature = "databake", derive(Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_text::Color))]
pub struct ColorSerde(pub u32); pub struct ColorSerde(pub u32);
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "Option<Color>")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Option<Color>"))]
pub enum ColorOpt { pub enum ColorOpt {
Some(#[serde(with = "ColorSerde")] Color), Some(#[cfg_attr(feature = "serde", serde(with = "ColorSerde"))] Color),
None, None,
} }
#[cfg(feature = "serde")]
mod cache_key_flags { mod cache_key_flags {
use cosmic_text::CacheKeyFlags; use cosmic_text::CacheKeyFlags;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -115,34 +181,80 @@ mod cache_key_flags {
} }
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "Attrs")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Attrs"))]
pub struct AttrsSerde<'a> { pub struct AttrsSerde<'a> {
#[serde(with = "ColorOpt")] #[cfg_attr(feature = "serde", serde(with = "ColorOpt"))]
pub color_opt: Option<Color>, pub color_opt: Option<Color>,
#[serde(with = "FamilySerde")] #[cfg_attr(feature = "serde", serde(with = "FamilySerde"))]
#[serde(borrow)] #[cfg_attr(feature = "serde", serde(borrow))]
pub family: Family<'a>, pub family: Family<'a>,
#[serde(with = "StretchSerde")] #[cfg_attr(feature = "serde", serde(with = "StretchSerde"))]
pub stretch: Stretch, pub stretch: Stretch,
#[serde(with = "StyleSerde")] #[cfg_attr(feature = "serde", serde(with = "StyleSerde"))]
pub style: Style, pub style: Style,
#[serde(with = "WeightSerde")] #[cfg_attr(feature = "serde", serde(with = "WeightSerde"))]
pub weight: Weight, pub weight: Weight,
pub metadata: usize, pub metadata: usize,
#[serde(with = "cache_key_flags")] #[cfg_attr(feature = "serde", serde(with = "cache_key_flags"))]
pub cache_key_flags: CacheKeyFlags, pub cache_key_flags: CacheKeyFlags,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] impl<'a> From<Attrs<'a>> for AttrsSerde<'a> {
#[serde(remote = "Option<Align>")] fn from(value: Attrs<'a>) -> Self {
AttrsSerde {
color_opt: value.color_opt,
family: value.family,
stretch: value.stretch,
style: value.style,
weight: value.weight,
metadata: value.metadata,
cache_key_flags: value.cache_key_flags,
}
}
}
#[cfg(feature = "databake")]
impl<'a> Bake for AttrsSerde<'a> {
fn bake(&self, ctx: &databake::CrateEnv) -> databake::TokenStream {
let color = self.color_opt.map(|c| ColorSerde(c.0)).bake(ctx);
let family: FamilySerde = self.family.into();
let family = family.bake(ctx);
let stretch: StretchSerde = self.stretch.into();
let stretch = stretch.bake(ctx);
let style: StyleSerde = self.style.into();
let style = style.bake(ctx);
let weight: WeightSerde = WeightSerde(self.weight.0);
let weight = weight.bake(ctx);
let metadata = self.metadata.bake(ctx);
databake::quote! {
cosmic_text::Attrs {
color_opt: #color,
family: #family,
stretch: #stretch,
style: #style,
weight: #weight,
metadata: #metadata,
cache_key_flags: cosmic_text::CacheKeyFlags::empty()
}
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Option<Align>"))]
pub enum AlignSerde { pub enum AlignSerde {
Some(#[serde(with = "AlignRef")] Align), Some(#[cfg_attr(feature = "serde", serde(with = "AlignRef"))] Align),
None, None,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug)]
#[serde(remote = "Align")] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Align"))]
#[cfg_attr(feature = "databake", derive(Bake))]
#[cfg_attr(feature = "databake", databake(path = cosmic_text::Align))]
pub enum AlignRef { pub enum AlignRef {
Left, Left,
Right, Right,