Add databake support
This commit is contained in:
parent
f6c85b5238
commit
4266b9ea90
4 changed files with 207 additions and 57 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -51,6 +51,7 @@ name = "cosmic-jotdown"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmic-text",
|
||||
"databake",
|
||||
"emath",
|
||||
"image",
|
||||
"jotdown",
|
||||
|
|
|
@ -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"]
|
||||
|
|
71
src/lib.rs
71
src/lib.rs
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue