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"
dependencies = [
"cosmic-text",
"databake",
"emath",
"image",
"jotdown",

View file

@ -14,6 +14,8 @@ rangemap = "1.5.1"
nominals = "0.3.0"
emath = "0.27.2"
image = { version = "0.24.9", default-features = false }
databake = { version = "0.1.7", features = ["derive"], optional = true }
[features]
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::{Attrs, Buffer, Color, Family, FontSystem, Metrics, Shaping, Style, Weight};
#[cfg(feature = "databake")]
use databake::Bake;
use emath::{Pos2, Rect, Vec2};
use jotdown::{Container, Event, ListKind, OrderedListNumbering, OrderedListStyle};
use nominals::{LetterLower, LetterUpper, Nominal, RomanLower, RomanUpper};
#[cfg(feature = "serde")]
#[cfg(any(feature = "serde", feature = "databake"))]
pub mod serde_suck;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
#[cfg(any(feature = "serde", feature = "databake"))]
pub use serde_suck::*;
use rangemap::RangeMap;
@ -42,6 +44,20 @@ pub struct Indent {
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;
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(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)]
#[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 indent: Indent,
#[cfg_attr(feature = "serde", serde(borrow))]
pub buffer: Vec<RichText<'a>>,
#[cfg_attr(feature = "serde", serde(with = "MetricsSerde"))]
pub metrics: Metrics,
pub buffer: Cow<'a, [RichText<'a>]>,
pub metrics: (f32, f32),
pub image_url: Option<Cow<'a, str>>,
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)]
@ -394,10 +423,16 @@ impl<'a> JotdownItem<'a> {
relative_bounds: measure_buffer(&buffer, Vec2::new(width, f32::MAX)),
buffer,
metrics: Metrics::new(
self.metrics.font_size * metrics.font_size,
self.metrics.line_height * metrics.line_height,
self.metrics.0 * metrics.font_size,
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,
}
}
@ -408,8 +443,8 @@ impl<'a> JotdownItem<'a> {
modifier: None,
indent: 0.0,
},
buffer: text,
metrics: Metrics::new(1.0, 1.1),
buffer: Cow::Owned(text),
metrics: (1.0, 1.1),
url_map: None,
margin: 0.0,
image_url: None,
@ -428,8 +463,8 @@ impl<'a> JotdownItem<'a> {
let mut buffer = Buffer::new(
font_system,
Metrics::new(
metrics.font_size * self.metrics.font_size,
metrics.line_height * self.metrics.line_height,
metrics.font_size * self.metrics.0,
metrics.line_height * self.metrics.1,
),
);
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() {
None
} else {
let mut map = RangeMap::new();
let mut map = Vec::new();
map.extend(
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,
metrics,
metrics: (metrics.font_size, metrics.line_height),
margin: match top_level_containers {
Some(Container::Heading { level, .. }) => match level {
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};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Option<ListKind>")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Option<ListKind>"))]
pub enum ListKindOption {
Some(#[serde(with = "ListKindSerde")] ListKind),
Some(#[cfg_attr(feature = "serde", serde(with = "ListKindSerde"))] ListKind),
None,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "jotdown::ListKind")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "jotdown::ListKind"))]
pub enum ListKindSerde {
Unordered,
Ordered {
@ -22,8 +27,9 @@ pub enum ListKindSerde {
Task,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "jotdown::OrderedListNumbering")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "jotdown::OrderedListNumbering"))]
pub enum OrderedListNumberingSerde {
Decimal,
AlphaLower,
@ -32,23 +38,30 @@ pub enum OrderedListNumberingSerde {
RomanUpper,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "jotdown::OrderedListStyle")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "jotdown::OrderedListStyle"))]
pub enum OrderedListStyleSerde {
Period,
Paren,
ParenParen,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Metrics")]
#[derive(Clone, Debug)]
#[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 font_size: f32,
pub line_height: f32,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Family")]
#[derive(Clone, Debug)]
#[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> {
Name(&'a str),
Serif,
@ -58,8 +71,24 @@ pub enum FamilySerde<'a> {
Monospace,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Stretch")]
impl<'a> From<Family<'a>> for FamilySerde<'a> {
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 {
UltraCondensed,
ExtraCondensed,
@ -72,29 +101,66 @@ pub enum StretchSerde {
UltraExpanded,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Style")]
impl From<Stretch> for StretchSerde {
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 {
Normal,
Italic,
Oblique,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Weight")]
impl From<Style> for StyleSerde {
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);
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Color")]
#[derive(Clone, Debug)]
#[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);
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Option<Color>")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Option<Color>"))]
pub enum ColorOpt {
Some(#[serde(with = "ColorSerde")] Color),
Some(#[cfg_attr(feature = "serde", serde(with = "ColorSerde"))] Color),
None,
}
#[cfg(feature = "serde")]
mod cache_key_flags {
use cosmic_text::CacheKeyFlags;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -115,34 +181,80 @@ mod cache_key_flags {
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Attrs")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(remote = "Attrs"))]
pub struct AttrsSerde<'a> {
#[serde(with = "ColorOpt")]
#[cfg_attr(feature = "serde", serde(with = "ColorOpt"))]
pub color_opt: Option<Color>,
#[serde(with = "FamilySerde")]
#[serde(borrow)]
#[cfg_attr(feature = "serde", serde(with = "FamilySerde"))]
#[cfg_attr(feature = "serde", serde(borrow))]
pub family: Family<'a>,
#[serde(with = "StretchSerde")]
#[cfg_attr(feature = "serde", serde(with = "StretchSerde"))]
pub stretch: Stretch,
#[serde(with = "StyleSerde")]
#[cfg_attr(feature = "serde", serde(with = "StyleSerde"))]
pub style: Style,
#[serde(with = "WeightSerde")]
#[cfg_attr(feature = "serde", serde(with = "WeightSerde"))]
pub weight: Weight,
pub metadata: usize,
#[serde(with = "cache_key_flags")]
#[cfg_attr(feature = "serde", serde(with = "cache_key_flags"))]
pub cache_key_flags: CacheKeyFlags,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Option<Align>")]
impl<'a> From<Attrs<'a>> for AttrsSerde<'a> {
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 {
Some(#[serde(with = "AlignRef")] Align),
Some(#[cfg_attr(feature = "serde", serde(with = "AlignRef"))] Align),
None,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Align")]
#[derive(Clone, Debug)]
#[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 {
Left,
Right,