Upgrade to new toddle interface 🐳
This commit is contained in:
parent
20fb4e7c37
commit
40ea35cbe7
@ -6,7 +6,7 @@ edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
toddle = { path = "../toddle", default-features = false }
|
||||
toddle = { path = "../toddle", features = ["query"], default-features = false }
|
||||
tide = { path = "../tide" }
|
||||
byteorder = "1"
|
||||
smallvec = "1"
|
||||
|
@ -3,9 +3,9 @@ use std::io::BufWriter;
|
||||
use std::path::{Path, PathBuf};
|
||||
use futures_executor::block_on;
|
||||
|
||||
use typstc::Typesetter;
|
||||
use typstc::toddle::query::FileSystemFontProvider;
|
||||
use typstc::export::pdf::PdfExporter;
|
||||
use typstc::{Typesetter, DynErrorProvider};
|
||||
use typstc::toddle::query::fs::EagerFsProvider;
|
||||
use typstc::export::pdf;
|
||||
|
||||
|
||||
fn main() {
|
||||
@ -37,15 +37,14 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let src = read_to_string(source)
|
||||
.map_err(|_| "failed to read from source file")?;
|
||||
|
||||
let mut typesetter = Typesetter::new();
|
||||
let provider = FileSystemFontProvider::from_index("../fonts/index.json").unwrap();
|
||||
typesetter.add_font_provider(provider);
|
||||
let (fs, entries) = EagerFsProvider::from_index("../fonts", "index.json")?;
|
||||
let provider = DynErrorProvider::new(fs);
|
||||
let typesetter = Typesetter::new((Box::new(provider), entries));
|
||||
|
||||
let layouts = block_on(typesetter.typeset(&src));
|
||||
|
||||
let exporter = PdfExporter::new();
|
||||
let writer = BufWriter::new(File::create(&dest)?);
|
||||
exporter.export(&layouts, typesetter.loader(), writer)?;
|
||||
pdf::export(&layouts, typesetter.loader(), writer)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -11,45 +11,35 @@ use tide::font::{
|
||||
CMap, CMapEncoding, FontStream, GlyphUnit, WidthRecord,
|
||||
};
|
||||
|
||||
use toddle::Error as FontError;
|
||||
use toddle::font::OwnedFont;
|
||||
use toddle::query::{SharedFontLoader, FontIndex};
|
||||
use toddle::{Font, OwnedFont, LoadError};
|
||||
use toddle::types::Tag;
|
||||
use toddle::query::FontIndex;
|
||||
use toddle::tables::{
|
||||
CharMap, Header, HorizontalMetrics, MacStyleFlags,
|
||||
Name, NameEntry, Post, OS2,
|
||||
};
|
||||
|
||||
use crate::GlobalFontLoader;
|
||||
use crate::layout::{MultiLayout, Layout, LayoutAction};
|
||||
use crate::size::Size;
|
||||
|
||||
|
||||
/// Exports layouts into _PDFs_.
|
||||
pub struct PdfExporter {}
|
||||
|
||||
impl PdfExporter {
|
||||
/// Create a new exporter.
|
||||
pub fn new() -> PdfExporter {
|
||||
PdfExporter {}
|
||||
}
|
||||
|
||||
/// Export a layouted list of boxes. The same font loader as used for
|
||||
/// layouting needs to be passed in here since the layout only contains
|
||||
/// indices referencing the loaded fonts. The raw PDF ist written into the
|
||||
/// target writable, returning the number of bytes written.
|
||||
pub fn export<W: Write>(
|
||||
&self,
|
||||
layout: &MultiLayout,
|
||||
loader: &SharedFontLoader,
|
||||
target: W,
|
||||
) -> PdfResult<usize> {
|
||||
ExportProcess::new(layout, loader, target)?.write()
|
||||
}
|
||||
/// Export a layouted list of boxes. The same font loader as used for
|
||||
/// layouting needs to be passed in here since the layout only contains
|
||||
/// indices referencing the loaded fonts. The raw PDF ist written into the
|
||||
/// target writable, returning the number of bytes written.
|
||||
pub fn export<W: Write>(
|
||||
layout: &MultiLayout,
|
||||
loader: &GlobalFontLoader,
|
||||
target: W,
|
||||
) -> PdfResult<usize> {
|
||||
PdfExporter::new(layout, loader, target)?.write()
|
||||
}
|
||||
|
||||
/// The data relevant to the export of one document.
|
||||
struct ExportProcess<'d, W: Write> {
|
||||
struct PdfExporter<'a, W: Write> {
|
||||
writer: PdfWriter<W>,
|
||||
layouts: &'d MultiLayout,
|
||||
layouts: &'a MultiLayout,
|
||||
|
||||
/// Since we cross-reference pages and fonts with their IDs already in the document
|
||||
/// catalog, we need to know exactly which ID is used for what from the beginning.
|
||||
@ -76,18 +66,18 @@ struct Offsets {
|
||||
fonts: (Ref, Ref),
|
||||
}
|
||||
|
||||
impl<'d, W: Write> ExportProcess<'d, W> {
|
||||
impl<'a, W: Write> PdfExporter<'a, W> {
|
||||
/// Prepare the export. Only once [`ExportProcess::write`] is called the
|
||||
/// writing really happens.
|
||||
fn new(
|
||||
layouts: &'d MultiLayout,
|
||||
font_loader: &SharedFontLoader,
|
||||
layouts: &'a MultiLayout,
|
||||
font_loader: &GlobalFontLoader,
|
||||
target: W,
|
||||
) -> PdfResult<ExportProcess<'d, W>> {
|
||||
) -> PdfResult<PdfExporter<'a, W>> {
|
||||
let (fonts, font_remap) = Self::subset_fonts(layouts, font_loader)?;
|
||||
let offsets = Self::calculate_offsets(layouts.len(), fonts.len());
|
||||
|
||||
Ok(ExportProcess {
|
||||
Ok(PdfExporter {
|
||||
writer: PdfWriter::new(target),
|
||||
layouts,
|
||||
offsets,
|
||||
@ -101,8 +91,8 @@ impl<'d, W: Write> ExportProcess<'d, W> {
|
||||
/// one used in the PDF. The new ones index into the returned vector of
|
||||
/// owned fonts.
|
||||
fn subset_fonts(
|
||||
layouts: &'d MultiLayout,
|
||||
font_loader: &SharedFontLoader
|
||||
layouts: &'a MultiLayout,
|
||||
font_loader: &GlobalFontLoader,
|
||||
) -> PdfResult<(Vec<OwnedFont>, HashMap<FontIndex, usize>)> {
|
||||
let mut fonts = Vec::new();
|
||||
let mut font_chars: HashMap<FontIndex, HashSet<char>> = HashMap::new();
|
||||
@ -144,18 +134,22 @@ impl<'d, W: Write> ExportProcess<'d, W> {
|
||||
let mut font_loader = font_loader.borrow_mut();
|
||||
|
||||
// All tables not listed here are dropped.
|
||||
const SUBSET_TABLES: [&str; 13] = [
|
||||
"name", "OS/2", "post", "head", "hhea", "hmtx", "maxp",
|
||||
"cmap", "cvt ", "fpgm", "prep", "loca", "glyf",
|
||||
];
|
||||
let tables: Vec<_> = [
|
||||
b"name", b"OS/2", b"post", b"head", b"hhea", b"hmtx", b"maxp",
|
||||
b"cmap", b"cvt ", b"fpgm", b"prep", b"loca", b"glyf",
|
||||
].iter().map(|&s| Tag(*s)).collect();
|
||||
|
||||
// Do the subsetting.
|
||||
for index in 0 .. num_fonts {
|
||||
let old_index = new_to_old[&index];
|
||||
let font = font_loader.get_with_index(old_index);
|
||||
let subsetted = font.subsetted(font_chars[&old_index].iter().cloned(), &SUBSET_TABLES)
|
||||
.map(|bytes| OwnedFont::from_bytes(bytes))
|
||||
.unwrap_or_else(|_| font.to_owned())?;
|
||||
|
||||
let chars = font_chars[&old_index].iter().cloned();
|
||||
let subsetted = match font.subsetted(chars, tables.iter().copied()) {
|
||||
Ok(data) => Font::from_bytes(data)?,
|
||||
Err(_) => font.clone(),
|
||||
};
|
||||
|
||||
fonts.push(subsetted);
|
||||
}
|
||||
|
||||
@ -302,7 +296,7 @@ impl<'d, W: Write> ExportProcess<'d, W> {
|
||||
id,
|
||||
Type0Font::new(
|
||||
base_font.clone(),
|
||||
CMapEncoding::Predefined("Identity-H".to_owned()),
|
||||
CMapEncoding::Predefined("Identity-H".to_string()),
|
||||
id + 1,
|
||||
)
|
||||
.to_unicode(id + 3),
|
||||
@ -409,7 +403,7 @@ fn ids((start, end): (Ref, Ref)) -> impl Iterator<Item = Ref> {
|
||||
/// The error type for _PDF_ exporting.
|
||||
pub enum PdfExportError {
|
||||
/// An error occured while subsetting the font for the _PDF_.
|
||||
Font(FontError),
|
||||
Font(LoadError),
|
||||
/// An I/O Error on the underlying writable.
|
||||
Io(io::Error),
|
||||
}
|
||||
@ -418,13 +412,13 @@ error_type! {
|
||||
self: PdfExportError,
|
||||
res: PdfResult,
|
||||
show: f => match self {
|
||||
PdfExportError::Font(err) => write!(f, "font error: {}", err),
|
||||
PdfExportError::Io(err) => write!(f, "io error: {}", err),
|
||||
PdfExportError::Font(err) => err.fmt(f),
|
||||
PdfExportError::Io(err) => err.fmt(f),
|
||||
},
|
||||
source: match self {
|
||||
PdfExportError::Font(err) => Some(err),
|
||||
PdfExportError::Io(err) => Some(err),
|
||||
},
|
||||
from: (err: io::Error, PdfExportError::Io(err)),
|
||||
from: (err: FontError, PdfExportError::Font(err)),
|
||||
from: (err: LoadError, PdfExportError::Font(err)),
|
||||
}
|
||||
|
@ -145,15 +145,14 @@ macro_rules! function {
|
||||
|
||||
(@layout($name:ident) layout($this:ident, $ctx:ident, $errors:ident) $code:block) => {
|
||||
impl $crate::syntax::Model for $name {
|
||||
fn layout<'a, 'b, 'c, 't>(
|
||||
fn layout<'a, 'b, 't>(
|
||||
#[allow(unused)] &'a $this,
|
||||
#[allow(unused)] mut $ctx: $crate::layout::LayoutContext<'b, 'c>,
|
||||
#[allow(unused)] mut $ctx: $crate::layout::LayoutContext<'b>,
|
||||
) -> $crate::layout::DynFuture<'t, $crate::layout::Layouted<
|
||||
$crate::layout::Commands<'a>>
|
||||
> where
|
||||
'a: 't,
|
||||
'b: 't,
|
||||
'c: 't,
|
||||
Self: 't,
|
||||
{
|
||||
Box::pin(async move {
|
||||
|
@ -5,8 +5,9 @@
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use smallvec::smallvec;
|
||||
use toddle::query::SharedFontLoader;
|
||||
use toddle::query::{SharedFontLoader, FontProvider};
|
||||
|
||||
use crate::GlobalFontLoader;
|
||||
use crate::error::Errors;
|
||||
use crate::style::{LayoutStyle, PageStyle, TextStyle};
|
||||
use crate::size::{Size, Size2D};
|
||||
@ -18,8 +19,8 @@ use super::*;
|
||||
|
||||
|
||||
/// Performs the model layouting.
|
||||
pub struct ModelLayouter<'a, 'p> {
|
||||
ctx: LayoutContext<'a, 'p>,
|
||||
pub struct ModelLayouter<'a> {
|
||||
ctx: LayoutContext<'a>,
|
||||
layouter: LineLayouter,
|
||||
style: LayoutStyle,
|
||||
errors: Errors,
|
||||
@ -27,10 +28,10 @@ pub struct ModelLayouter<'a, 'p> {
|
||||
|
||||
/// The context for layouting.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LayoutContext<'a, 'p> {
|
||||
pub struct LayoutContext<'a> {
|
||||
/// The font loader to retrieve fonts from when typesetting text
|
||||
/// using [`layout_text`].
|
||||
pub loader: &'a SharedFontLoader<'p>,
|
||||
pub loader: &'a GlobalFontLoader,
|
||||
/// The style for pages and text.
|
||||
pub style: &'a LayoutStyle,
|
||||
/// The base unpadded dimensions of this container (for relative sizing).
|
||||
@ -105,7 +106,7 @@ pub enum Command<'a> {
|
||||
}
|
||||
|
||||
/// Layout a syntax model into a list of boxes.
|
||||
pub async fn layout(model: &SyntaxModel, ctx: LayoutContext<'_, '_>) -> Layouted<MultiLayout> {
|
||||
pub async fn layout(model: &SyntaxModel, ctx: LayoutContext<'_>) -> Layouted<MultiLayout> {
|
||||
let mut layouter = ModelLayouter::new(ctx);
|
||||
layouter.layout_syntax_model(model).await;
|
||||
layouter.finish()
|
||||
@ -116,9 +117,9 @@ pub async fn layout(model: &SyntaxModel, ctx: LayoutContext<'_, '_>) -> Layouted
|
||||
/// work internally.
|
||||
pub type DynFuture<'a, T> = Pin<Box<dyn Future<Output=T> + 'a>>;
|
||||
|
||||
impl<'a, 'p> ModelLayouter<'a, 'p> {
|
||||
impl<'a> ModelLayouter<'a> {
|
||||
/// Create a new model layouter.
|
||||
pub fn new(ctx: LayoutContext<'a, 'p>) -> ModelLayouter<'a, 'p> {
|
||||
pub fn new(ctx: LayoutContext<'a>) -> ModelLayouter<'a> {
|
||||
ModelLayouter {
|
||||
layouter: LineLayouter::new(LineContext {
|
||||
spaces: ctx.spaces.clone(),
|
||||
@ -182,6 +183,7 @@ impl<'a, 'p> ModelLayouter<'a, 'p> {
|
||||
Some("monospace") => { list.remove(0); },
|
||||
_ => list.insert(0, "monospace".to_string()),
|
||||
}
|
||||
self.style.text.fallback.flatten();
|
||||
}
|
||||
|
||||
Node::Model(model) => {
|
||||
|
@ -4,17 +4,18 @@
|
||||
//! When the primary layouting axis horizontally inversed, the word is spelled
|
||||
//! backwards. Vertical word layout is not yet supported.
|
||||
|
||||
use toddle::query::{SharedFontLoader, FontQuery, FontIndex};
|
||||
use toddle::query::{FontQuery, FontIndex};
|
||||
use toddle::tables::{CharMap, Header, HorizontalMetrics};
|
||||
|
||||
use crate::GlobalFontLoader;
|
||||
use crate::size::{Size, Size2D};
|
||||
use crate::style::TextStyle;
|
||||
use super::*;
|
||||
|
||||
|
||||
/// Performs the text layouting.
|
||||
struct TextLayouter<'a, 'p> {
|
||||
ctx: TextContext<'a, 'p>,
|
||||
struct TextLayouter<'a> {
|
||||
ctx: TextContext<'a>,
|
||||
text: &'a str,
|
||||
actions: LayoutActions,
|
||||
buffer: String,
|
||||
@ -24,10 +25,10 @@ struct TextLayouter<'a, 'p> {
|
||||
|
||||
/// The context for text layouting.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TextContext<'a, 'p> {
|
||||
pub struct TextContext<'a> {
|
||||
/// The font loader to retrieve fonts from when typesetting text
|
||||
/// using [`layout_text`].
|
||||
pub loader: &'a SharedFontLoader<'p>,
|
||||
pub loader: &'a GlobalFontLoader,
|
||||
/// The style for text: Font selection with classes, weights and variants,
|
||||
/// font sizes, spacing and so on.
|
||||
pub style: &'a TextStyle,
|
||||
@ -39,13 +40,13 @@ pub struct TextContext<'a, 'p> {
|
||||
}
|
||||
|
||||
/// Layouts text into a box.
|
||||
pub async fn layout_text(text: &str, ctx: TextContext<'_, '_>) -> Layout {
|
||||
pub async fn layout_text(text: &str, ctx: TextContext<'_>) -> Layout {
|
||||
TextLayouter::new(text, ctx).layout().await
|
||||
}
|
||||
|
||||
impl<'a, 'p> TextLayouter<'a, 'p> {
|
||||
impl<'a> TextLayouter<'a> {
|
||||
/// Create a new text layouter.
|
||||
fn new(text: &'a str, ctx: TextContext<'a, 'p>) -> TextLayouter<'a, 'p> {
|
||||
fn new(text: &'a str, ctx: TextContext<'a>) -> TextLayouter<'a> {
|
||||
TextLayouter {
|
||||
ctx,
|
||||
text,
|
||||
|
61
src/lib.rs
61
src/lib.rs
@ -21,8 +21,14 @@
|
||||
pub use toddle;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::io::Cursor;
|
||||
use async_trait::async_trait;
|
||||
use smallvec::smallvec;
|
||||
use toddle::query::{FontLoader, FontProvider, SharedFontLoader};
|
||||
|
||||
use toddle::{Font, OwnedData};
|
||||
use toddle::query::{FontLoader, FontProvider, SharedFontLoader, FontDescriptor};
|
||||
|
||||
use crate::layout::{Layouted, MultiLayout};
|
||||
use crate::style::{LayoutStyle, PageStyle, TextStyle};
|
||||
@ -45,20 +51,29 @@ pub mod syntax;
|
||||
/// Transforms source code into typesetted layouts.
|
||||
///
|
||||
/// A typesetter can be configured through various methods.
|
||||
pub struct Typesetter<'p> {
|
||||
pub struct Typesetter {
|
||||
/// The font loader shared by all typesetting processes.
|
||||
loader: SharedFontLoader<'p>,
|
||||
loader: GlobalFontLoader,
|
||||
/// The base layouting style.
|
||||
style: LayoutStyle,
|
||||
/// The standard library scope.
|
||||
scope: Scope,
|
||||
}
|
||||
|
||||
impl<'p> Typesetter<'p> {
|
||||
/// The font loader type used in the [`Typesetter`].
|
||||
///
|
||||
/// This font loader is ref-cell protected and backed by a dynamic font
|
||||
/// provider.
|
||||
pub type GlobalFontLoader = SharedFontLoader<GlobalProvider>;
|
||||
|
||||
/// The provider type of font loaders used in the [`Typesetter`].
|
||||
pub type GlobalProvider = Box<dyn FontProvider<Data=OwnedData, Error=Box<dyn Error>>>;
|
||||
|
||||
impl Typesetter {
|
||||
/// Create a new typesetter.
|
||||
pub fn new() -> Typesetter<'p> {
|
||||
pub fn new(provider: (GlobalProvider, Vec<FontDescriptor>)) -> Typesetter {
|
||||
Typesetter {
|
||||
loader: RefCell::new(FontLoader::new()),
|
||||
loader: RefCell::new(FontLoader::new(provider)),
|
||||
style: LayoutStyle::default(),
|
||||
scope: Scope::with_std(),
|
||||
}
|
||||
@ -74,14 +89,8 @@ impl<'p> Typesetter<'p> {
|
||||
self.style.text = style;
|
||||
}
|
||||
|
||||
/// Add a font provider to the context of this typesetter.
|
||||
pub fn add_font_provider<P: 'p>(&mut self, provider: P)
|
||||
where P: FontProvider {
|
||||
self.loader.get_mut().add_provider(provider);
|
||||
}
|
||||
|
||||
/// A reference to the backing font loader.
|
||||
pub fn loader(&self) -> &SharedFontLoader<'p> {
|
||||
pub fn loader(&self) -> &GlobalFontLoader {
|
||||
&self.loader
|
||||
}
|
||||
|
||||
@ -121,3 +130,29 @@ impl<'p> Typesetter<'p> {
|
||||
self.layout(&tree).await.output
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a font provider and transforms its errors into boxed trait objects.
|
||||
/// This enables font providers that do not return boxed errors to be used with
|
||||
/// the typesetter.
|
||||
pub struct DynErrorProvider<P> {
|
||||
provider: P,
|
||||
}
|
||||
|
||||
impl<P> DynErrorProvider<P>
|
||||
where P: FontProvider, P::Error: Error + 'static {
|
||||
/// Create a new dynamic error provider from any provider.
|
||||
pub fn new(provider: P) -> DynErrorProvider<P> {
|
||||
DynErrorProvider { provider }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<P> FontProvider for DynErrorProvider<P>
|
||||
where P: FontProvider, P::Error: Error + 'static {
|
||||
type Data = P::Data;
|
||||
type Error = Box<dyn Error>;
|
||||
|
||||
async fn load(&self, index: usize, variant: usize) -> Result<Font<P::Data>, Self::Error> {
|
||||
Ok(self.provider.load(index, variant).await?)
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ function! {
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
styled(&self.body, ctx, Some(&self.list),
|
||||
|s, l| s.fallback.list = l.clone())
|
||||
|s, list| {
|
||||
s.fallback.list = list.clone();
|
||||
s.fallback.flatten();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! The _Typst_ standard library.
|
||||
|
||||
use toddle::query::FontProvider;
|
||||
use crate::syntax::Scope;
|
||||
use crate::func::prelude::*;
|
||||
|
||||
@ -68,7 +69,7 @@ function! {
|
||||
/// Layout an optional body with a change of the text style.
|
||||
fn styled<'a, T, F>(
|
||||
body: &'a Option<SyntaxModel>,
|
||||
ctx: LayoutContext,
|
||||
ctx: LayoutContext<'_>,
|
||||
data: Option<T>,
|
||||
f: F,
|
||||
) -> Commands<'a> where F: FnOnce(&mut TextStyle, T) {
|
||||
|
40
src/style.rs
40
src/style.rs
@ -1,6 +1,7 @@
|
||||
//! Styles for text and pages.
|
||||
|
||||
use toddle::query::{FontFallbackTree, FontVariant, FontStyle, FontWeight};
|
||||
use toddle::fallback;
|
||||
use toddle::query::{FallbackTree, FontVariant, FontStyle, FontWeight};
|
||||
use crate::size::{Size, Size2D, SizeBox, ValueBox, PSize};
|
||||
|
||||
|
||||
@ -17,7 +18,7 @@ pub struct LayoutStyle {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TextStyle {
|
||||
/// A tree of font names and generic family names.
|
||||
pub fallback: FontFallbackTree,
|
||||
pub fallback: FallbackTree,
|
||||
/// The selected font variant.
|
||||
pub variant: FontVariant,
|
||||
/// Whether the bolder toggle is active or inactive. This determines
|
||||
@ -57,38 +58,19 @@ impl TextStyle {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! fallback {
|
||||
(
|
||||
list: ($($f:expr),*),
|
||||
classes: { $($c:expr => ($($cf:expr),*),)* },
|
||||
base: ($($b:expr),*),
|
||||
) => ({
|
||||
let mut fallback = FontFallbackTree::new(
|
||||
vec![$($f.to_string()),*],
|
||||
vec![$($b.to_string()),*],
|
||||
);
|
||||
$(
|
||||
fallback.set_class_list($c.to_string(), vec![$($cf.to_string()),*])
|
||||
.expect("TextStyle::default: unexpected error \
|
||||
when setting class list");
|
||||
)*
|
||||
fallback
|
||||
});
|
||||
}
|
||||
|
||||
impl Default for TextStyle {
|
||||
fn default() -> TextStyle {
|
||||
TextStyle {
|
||||
fallback: fallback! {
|
||||
list: ("sans-serif"),
|
||||
list: ["sans-serif"],
|
||||
classes: {
|
||||
"serif" => ("source serif pro", "noto serif"),
|
||||
"sans-serif" => ("source sans pro", "noto sans"),
|
||||
"monospace" => ("source code pro", "noto sans mono"),
|
||||
"math" => ("latin modern math", "serif"),
|
||||
"serif" => ["source serif pro", "noto serif"],
|
||||
"sans-serif" => ["source sans pro", "noto sans"],
|
||||
"monospace" => ["source code pro", "noto sans mono"],
|
||||
"math" => ["latin modern math", "serif"],
|
||||
},
|
||||
base: ("source sans pro", "noto sans",
|
||||
"noto emoji", "latin modern math"),
|
||||
base: ["source sans pro", "noto sans",
|
||||
"noto emoji", "latin modern math"],
|
||||
},
|
||||
variant: FontVariant {
|
||||
style: FontStyle::Normal,
|
||||
@ -157,7 +139,7 @@ pub struct Paper {
|
||||
|
||||
impl Paper {
|
||||
/// The paper with the given name.
|
||||
pub fn from_str(name: &str) -> Option<Paper> {
|
||||
pub fn from_name(name: &str) -> Option<Paper> {
|
||||
parse_paper(name)
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ impl Value for FontStyle {
|
||||
type Output = Self;
|
||||
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self::Output, Error> {
|
||||
FontStyle::from_str(Ident::parse(expr)?.as_str())
|
||||
FontStyle::from_name(Ident::parse(expr)?.as_str())
|
||||
.ok_or_else(|| err!("invalid font style"))
|
||||
}
|
||||
}
|
||||
@ -166,7 +166,7 @@ impl Value for FontWeight {
|
||||
}
|
||||
}
|
||||
Expr::Ident(id) => {
|
||||
FontWeight::from_str(id.as_str())
|
||||
FontWeight::from_name(id.as_str())
|
||||
.ok_or_else(|| err!("invalid font weight"))
|
||||
.map(|weight| (weight, false))
|
||||
}
|
||||
@ -180,7 +180,7 @@ impl Value for Paper {
|
||||
type Output = Self;
|
||||
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self::Output, Error> {
|
||||
Paper::from_str(Ident::parse(expr)?.as_str())
|
||||
Paper::from_name(Ident::parse(expr)?.as_str())
|
||||
.ok_or_else(|| err!("invalid paper type"))
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,10 @@ pub_use_mod!(tokens);
|
||||
pub trait Model: Debug + ModelBounds {
|
||||
/// Layout the model into a sequence of commands processed by a
|
||||
/// [`ModelLayouter`](crate::layout::ModelLayouter).
|
||||
async fn layout<'a>(&'a self, ctx: LayoutContext<'_, '_>) -> Layouted<Commands<'a>>;
|
||||
async fn layout<'a>(
|
||||
&'a self,
|
||||
ctx: LayoutContext<'_>,
|
||||
) -> Layouted<Commands<'a>>;
|
||||
}
|
||||
|
||||
/// A tree representation of source code.
|
||||
@ -47,7 +50,10 @@ impl SyntaxModel {
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl Model for SyntaxModel {
|
||||
async fn layout<'a>(&'a self, _: LayoutContext<'_, '_>) -> Layouted<Commands<'a>> {
|
||||
async fn layout<'a>(
|
||||
&'a self,
|
||||
_: LayoutContext<'_>,
|
||||
) -> Layouted<Commands<'a>> {
|
||||
Layouted {
|
||||
output: vec![Command::LayoutSyntaxModel(self)],
|
||||
errors: vec![],
|
||||
|
@ -81,7 +81,7 @@ pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Parsed<SyntaxMode
|
||||
Token::Star => Node::ToggleBolder,
|
||||
Token::Underscore => Node::ToggleItalic,
|
||||
Token::Backtick => Node::ToggleMonospace,
|
||||
Token::Text(text) => Node::Text(text.to_owned()),
|
||||
Token::Text(text) => Node::Text(text.to_string()),
|
||||
|
||||
Token::LineComment(_) | Token::BlockComment(_) => continue,
|
||||
|
||||
|
@ -43,7 +43,7 @@ impl Scope {
|
||||
pub fn add_with_meta<F>(&mut self, name: &str, metadata: <F as ParseFunc>::Meta)
|
||||
where F: ParseFunc + Model + 'static {
|
||||
self.parsers.insert(
|
||||
name.to_owned(),
|
||||
name.to_string(),
|
||||
parser::<F>(metadata),
|
||||
);
|
||||
}
|
||||
|
@ -8,12 +8,12 @@ use std::process::Command;
|
||||
|
||||
use futures_executor::block_on;
|
||||
|
||||
use typstc::Typesetter;
|
||||
use typstc::{Typesetter, DynErrorProvider};
|
||||
use typstc::layout::{MultiLayout, Serialize};
|
||||
use typstc::size::{Size, Size2D, ValueBox};
|
||||
use typstc::style::{PageStyle, PaperClass};
|
||||
use typstc::toddle::query::FileSystemFontProvider;
|
||||
use typstc::export::pdf::PdfExporter;
|
||||
use typstc::export::pdf;
|
||||
use typstc::toddle::query::fs::EagerFsProvider;
|
||||
|
||||
|
||||
type DynResult<T> = Result<T, Box<dyn Error>>;
|
||||
@ -66,17 +66,17 @@ fn main() -> DynResult<()> {
|
||||
fn test(name: &str, src: &str) -> DynResult<()> {
|
||||
println!("Testing: {}.", name);
|
||||
|
||||
let mut typesetter = Typesetter::new();
|
||||
let (fs, entries) = EagerFsProvider::from_index("../fonts", "index.json")?;
|
||||
let paths = fs.paths();
|
||||
let provider = DynErrorProvider::new(fs);
|
||||
let mut typesetter = Typesetter::new((Box::new(provider), entries));
|
||||
|
||||
typesetter.set_page_style(PageStyle {
|
||||
class: PaperClass::Custom,
|
||||
dimensions: Size2D::with_all(Size::pt(250.0)),
|
||||
margins: ValueBox::with_all(None),
|
||||
});
|
||||
|
||||
let provider = FileSystemFontProvider::from_index("../fonts/index.json")?;
|
||||
let font_paths = provider.paths();
|
||||
typesetter.add_font_provider(provider);
|
||||
|
||||
let layouts = compile(&typesetter, src);
|
||||
|
||||
// Compute the font's paths.
|
||||
@ -84,10 +84,8 @@ fn test(name: &str, src: &str) -> DynResult<()> {
|
||||
let loader = typesetter.loader().borrow();
|
||||
for layout in &layouts {
|
||||
for index in layout.find_used_fonts() {
|
||||
fonts.entry(index).or_insert_with(|| {
|
||||
let p = loader.get_provider_and_index(index.id).1;
|
||||
&font_paths[p][index.variant]
|
||||
});
|
||||
fonts.entry(index)
|
||||
.or_insert_with(|| &paths[index.id][index.variant]);
|
||||
}
|
||||
}
|
||||
drop(loader);
|
||||
@ -113,8 +111,7 @@ fn test(name: &str, src: &str) -> DynResult<()> {
|
||||
// Write the PDF file.
|
||||
let path = format!("tests/cache/pdf/{}.pdf", name);
|
||||
let file = BufWriter::new(File::create(path)?);
|
||||
let exporter = PdfExporter::new();
|
||||
exporter.export(&layouts, typesetter.loader(), file)?;
|
||||
pdf::export(&layouts, typesetter.loader(), file)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user