diff --git a/src/bin/main.rs b/src/bin/main.rs index 5ae20f4a6..58b2c00ed 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,14 +1,13 @@ use std::env; use std::error::Error; use std::fs::File; -use std::io::{Read, BufWriter}; +use std::io::{BufWriter, Read}; use std::path::{Path, PathBuf}; use std::process; -use typst::Typesetter; use typst::export::pdf::PdfExporter; use typst::toddle::query::FileSystemFontProvider; - +use typst::Typesetter; fn main() { if let Err(err) = run() { @@ -26,11 +25,16 @@ fn run() -> Result<(), Box> { let source_path = Path::new(&args[1]); - // Compute the output filename from the input filename by replacing the extension. + // Compute the output filename from the input filename by replacing the + // extension. let dest_path = if args.len() <= 2 { - let stem = source_path.file_stem().ok_or_else(|| "missing destation file name")?; + let stem = source_path + .file_stem() + .ok_or_else(|| "missing destation file name")?; - let base = source_path.parent().ok_or_else(|| "missing destation folder")?; + let base = source_path + .parent() + .ok_or_else(|| "missing destation folder")?; base.join(format!("{}.pdf", stem.to_string_lossy())) } else { @@ -43,7 +47,9 @@ fn run() -> Result<(), Box> { let mut src = String::new(); let mut source_file = File::open(source_path).map_err(|_| "failed to open source file")?; - source_file.read_to_string(&mut src).map_err(|_| "failed to read from source file")?; + source_file + .read_to_string(&mut src) + .map_err(|_| "failed to read from source file")?; // Create a typesetter with a font provider that provides the default fonts. let mut typesetter = Typesetter::new(); diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 78e48e81d..b7ad21c77 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -3,21 +3,22 @@ use std::collections::{HashMap, HashSet}; use std::io::{self, Write}; -use tide::{PdfWriter, Ref, Rect, Version, Trailer}; use tide::content::Content; -use tide::doc::{Catalog, PageTree, Page, Resource, Text}; -use tide::font::{Type0Font, CIDFont, CIDFontType, CIDSystemInfo, FontDescriptor, FontFlags}; -use tide::font::{GlyphUnit, CMap, CMapEncoding, WidthRecord, FontStream}; +use tide::doc::{Catalog, Page, PageTree, Resource, Text}; +use tide::font::{CIDFont, CIDFontType, CIDSystemInfo, FontDescriptor, FontFlags, Type0Font}; +use tide::font::{CMap, CMapEncoding, FontStream, GlyphUnit, WidthRecord}; +use tide::{PdfWriter, Rect, Ref, Trailer, Version}; -use toddle::tables::{Header, Post, OS2, HorizontalMetrics, CharMap, Name, NameEntry, MacStyleFlags}; use toddle::font::OwnedFont; use toddle::query::SharedFontLoader; +use toddle::tables::{ + CharMap, Header, HorizontalMetrics, MacStyleFlags, Name, NameEntry, Post, OS2, +}; use toddle::Error as FontError; -use crate::layout::{MultiLayout, Layout, LayoutAction}; +use crate::layout::{Layout, LayoutAction, MultiLayout}; use crate::size::{Size, Size2D}; - /// Exports layouts into _PDFs_. #[derive(Debug)] pub struct PdfExporter {} @@ -29,10 +30,16 @@ impl PdfExporter { PdfExporter {} } - /// Export a finished layouts into a writer. Returns how many bytes were written. + /// Export a finished layouts into a writer. Returns how many bytes were + /// written. #[inline] - pub fn export(&self, layout: &MultiLayout, loader: &SharedFontLoader, target: W) - -> PdfResult { + pub fn export( + &self, + layout: &MultiLayout, + loader: &SharedFontLoader, + target: W, + ) -> PdfResult + { let mut engine = PdfEngine::new(layout, loader, target)?; engine.write() } @@ -59,8 +66,12 @@ struct Offsets { impl<'d, W: Write> PdfEngine<'d, W> { /// Create a new _PDF_ engine. - fn new(layout: &'d MultiLayout, loader: &SharedFontLoader, target: W) - -> PdfResult> { + fn new( + layout: &'d MultiLayout, + loader: &SharedFontLoader, + target: W, + ) -> PdfResult> + { // Create a subsetted PDF font for each font in the layout. let mut font_remap = HashMap::new(); let fonts = { @@ -71,24 +82,26 @@ impl<'d, W: Write> PdfEngine<'d, W> { for boxed in &layout.layouts { for action in &boxed.actions { match action { - LayoutAction::WriteText(string) => { - chars.entry(font) - .or_insert_with(HashSet::new) - .extend(string.chars()) - }, + LayoutAction::WriteText(string) => chars + .entry(font) + .or_insert_with(HashSet::new) + .extend(string.chars()), LayoutAction::SetFont(id, _) => { font = *id; let new_id = font_remap.len(); font_remap.entry(font).or_insert(new_id); - }, - _ => {}, + } + _ => {} } } } // Collect the fonts into a vector in the order of the values in the remapping. let mut loader = loader.borrow_mut(); - let mut order = font_remap.iter().map(|(&old, &new)| (old, new)).collect::>(); + let mut order = font_remap + .iter() + .map(|(&old, &new)| (old, new)) + .collect::>(); order.sort_by_key(|&(_, new)| new); let mut fonts = vec![]; @@ -96,8 +109,10 @@ impl<'d, W: Write> PdfEngine<'d, W> { let font = loader.get_with_index(index); let subsetted = font.subsetted( chars[&index].iter().cloned(), - &["name", "OS/2", "post", "head", "hhea", "hmtx", "maxp", - "cmap", "cvt ", "fpgm", "prep", "loca", "glyf"][..] + &[ + "name", "OS/2", "post", "head", "hhea", "hmtx", "maxp", "cmap", "cvt ", + "fpgm", "prep", "loca", "glyf", + ][..], )?; fonts.push(OwnedFont::from_bytes(subsetted)?); } @@ -111,7 +126,13 @@ impl<'d, W: Write> PdfEngine<'d, W> { let pages = (page_tree + 1, page_tree + layout.layouts.len() as Ref); let contents = (pages.1 + 1, pages.1 + layout.layouts.len() as Ref); let font_offsets = (contents.1 + 1, contents.1 + 5 * fonts.len() as Ref); - let offsets = Offsets { catalog, page_tree, pages, contents, fonts: font_offsets }; + let offsets = Offsets { + catalog, + page_tree, + pages, + contents, + fonts: font_offsets, + }; Ok(PdfEngine { writer: PdfWriter::new(target), @@ -129,32 +150,43 @@ impl<'d, W: Write> PdfEngine<'d, W> { self.write_pages()?; self.write_fonts()?; self.writer.write_xref_table()?; - self.writer.write_trailer(Trailer::new(self.offsets.catalog))?; + self.writer + .write_trailer(Trailer::new(self.offsets.catalog))?; Ok(self.writer.written()) } /// Write the document catalog and page tree. fn write_page_tree(&mut self) -> PdfResult<()> { // The document catalog - self.writer.write_obj(self.offsets.catalog, &Catalog::new(self.offsets.page_tree))?; + self.writer + .write_obj(self.offsets.catalog, &Catalog::new(self.offsets.page_tree))?; // The font resources let offset = self.offsets.fonts.0; - let fonts = (0 .. self.fonts.len()) - .map(|i| Resource::Font((i + 1) as u32, offset + 5 * i as u32)); + let fonts = + (0..self.fonts.len()).map(|i| Resource::Font((i + 1) as u32, offset + 5 * i as u32)); // The root page tree - self.writer.write_obj(self.offsets.page_tree, PageTree::new() - .kids(ids(self.offsets.pages)) - .resources(fonts) + self.writer.write_obj( + self.offsets.page_tree, + PageTree::new() + .kids(ids(self.offsets.pages)) + .resources(fonts), )?; // The page objects for (id, page) in ids(self.offsets.pages).zip(&self.layout.layouts) { - let rect = Rect::new(0.0, 0.0, page.dimensions.x.to_pt(), page.dimensions.y.to_pt()); - self.writer.write_obj(id, Page::new(self.offsets.page_tree) - .media_box(rect) - .contents(ids(self.offsets.contents)) + let rect = Rect::new( + 0.0, + 0.0, + page.dimensions.x.to_pt(), + page.dimensions.y.to_pt(), + ); + self.writer.write_obj( + id, + Page::new(self.offsets.page_tree) + .media_box(rect) + .contents(ids(self.offsets.contents)), )?; } @@ -202,8 +234,8 @@ impl<'d, W: Write> PdfEngine<'d, W> { // Write the text. text.tj(self.fonts[active_font.0].encode_text(&string)?); - }, - LayoutAction::DebugBox(_, _) => {}, + } + LayoutAction::DebugBox(_, _) => {} } } @@ -217,18 +249,21 @@ impl<'d, W: Write> PdfEngine<'d, W> { let mut id = self.offsets.fonts.0; for font in &mut self.fonts { - let name = font.read_table::()? + let name = font + .read_table::()? .get_decoded(NameEntry::PostScriptName) .unwrap_or_else(|| "unknown".to_string()); let base_font = format!("ABCDEF+{}", name); // Write the base font object referencing the CID font. - self.writer.write_obj(id, + self.writer.write_obj( + id, Type0Font::new( base_font.clone(), CMapEncoding::Predefined("Identity-H".to_owned()), - id + 1 - ).to_unicode(id + 3) + id + 1, + ) + .to_unicode(id + 3), )?; // Extract information from the head table. @@ -252,19 +287,22 @@ impl<'d, W: Write> PdfEngine<'d, W> { // Transform the width into PDF units. let widths: Vec<_> = font .read_table::()? - .metrics.iter() + .metrics + .iter() .map(|m| font_unit_to_glyph_unit(m.advance_width as f32)) .collect(); // Write the CID font referencing the font descriptor. let system_info = CIDSystemInfo::new("Adobe", "Identity", 0); - self.writer.write_obj(id + 1, + self.writer.write_obj( + id + 1, CIDFont::new( CIDFontType::Type2, base_font.clone(), system_info.clone(), id + 2, - ).widths(vec![WidthRecord::start(0, widths)]) + ) + .widths(vec![WidthRecord::start(0, widths)]), )?; // Extract information from the post table. @@ -284,24 +322,31 @@ impl<'d, W: Write> PdfEngine<'d, W> { let os2 = font.read_table::()?; // Write the font descriptor (contains the global information about the font). - self.writer.write_obj(id + 2, + self.writer.write_obj( + id + 2, FontDescriptor::new(base_font, flags, italic_angle) .font_bbox(bounding_box) .ascent(font_unit_to_glyph_unit(os2.s_typo_ascender as f32)) .descent(font_unit_to_glyph_unit(os2.s_typo_descender as f32)) - .cap_height(font_unit_to_glyph_unit(os2.s_cap_height.unwrap_or(os2.s_typo_ascender) as f32)) + .cap_height(font_unit_to_glyph_unit( + os2.s_cap_height.unwrap_or(os2.s_typo_ascender) as f32, + )) .stem_v((10.0 + 0.244 * (os2.us_weight_class as f32 - 50.0)) as GlyphUnit) - .font_file_2(id + 4) + .font_file_2(id + 4), )?; // Write the CMap, which maps glyphs to unicode codepoints. - let mapping = font.read_table::()? - .mapping.iter() + let mapping = font + .read_table::()? + .mapping + .iter() .map(|(&c, &cid)| (cid, c)); - self.writer.write_obj(id + 3, &CMap::new("Custom", system_info, mapping))?; + self.writer + .write_obj(id + 3, &CMap::new("Custom", system_info, mapping))?; // Finally write the subsetted font program. - self.writer.write_obj(id + 4, &FontStream::new(font.data().get_ref()))?; + self.writer + .write_obj(id + 4, &FontStream::new(font.data().get_ref()))?; id += 5; } @@ -311,8 +356,8 @@ impl<'d, W: Write> PdfEngine<'d, W> { } /// Create an iterator from a reference pair. -fn ids((start, end): (Ref, Ref)) -> impl Iterator { - start ..= end +fn ids((start, end): (Ref, Ref)) -> impl Iterator { + start..=end } /// The error type for _PDF_ creation. diff --git a/src/func.rs b/src/func.rs index cbe7a31ac..1f1b928d2 100644 --- a/src/func.rs +++ b/src/func.rs @@ -6,27 +6,27 @@ use std::fmt::{self, Debug, Formatter}; use toddle::query::FontClass; -use crate::layout::{Layout, MultiLayout , LayoutContext, LayoutResult}; +use crate::layout::{Layout, LayoutContext, LayoutResult, MultiLayout}; use crate::parsing::{ParseContext, ParseResult}; -use crate::syntax::{SyntaxTree, FuncHeader}; - +use crate::syntax::{FuncHeader, SyntaxTree}; /// Typesetting function types. /// -/// These types have to be able to parse tokens into themselves and store the relevant information -/// from the parsing to do their role in typesetting later. +/// These types have to be able to parse tokens into themselves and store the +/// relevant information from the parsing to do their role in typesetting later. /// -/// The trait `FunctionBounds` is automatically implemented for types which can be used as -/// functions, that is they fulfill the bounds `Debug + PartialEq + 'static`. +/// The trait `FunctionBounds` is automatically implemented for types which can +/// be used as functions, that is they fulfill the bounds `Debug + PartialEq + +/// 'static`. pub trait Function: FunctionBounds { /// Parse the header and body into this function given a context. - fn parse(header: &FuncHeader, body: Option<&str>, ctx: ParseContext) - -> ParseResult where Self: Sized; + fn parse(header: &FuncHeader, body: Option<&str>, ctx: ParseContext) -> ParseResult + where Self: Sized; /// Layout this function given a context. /// - /// Returns optionally the resulting layout and a new context if changes to the context should - /// be made. + /// Returns optionally the resulting layout and a new context if changes to + /// the context should be made. fn layout(&self, ctx: LayoutContext) -> LayoutResult; } @@ -39,15 +39,13 @@ impl PartialEq for dyn Function { /// A sequence of commands requested for execution by a function. #[derive(Debug)] pub struct FuncCommands<'a> { - pub commands: Vec> + pub commands: Vec>, } impl<'a> FuncCommands<'a> { /// Create an empty command list. pub fn new() -> FuncCommands<'a> { - FuncCommands { - commands: vec![], - } + FuncCommands { commands: vec![] } } /// Add a command to the sequence. @@ -79,10 +77,11 @@ pub enum Command<'a> { ToggleStyleClass(FontClass), } -/// A helper trait that describes requirements for types that can implement [`Function`]. +/// A helper trait that describes requirements for types that can implement +/// [`Function`]. /// -/// Automatically implemented for all types which fulfill to the bounds `Debug + PartialEq + -/// 'static`. There should be no need to implement this manually. +/// Automatically implemented for all types which fulfill to the bounds `Debug + +/// PartialEq + 'static`. There should be no need to implement this manually. pub trait FunctionBounds: Debug { /// Cast self into `Any`. fn help_cast_as_any(&self) -> &dyn Any; @@ -91,7 +90,9 @@ pub trait FunctionBounds: Debug { fn help_eq(&self, other: &dyn Function) -> bool; } -impl FunctionBounds for T where T: Debug + PartialEq + 'static { +impl FunctionBounds for T +where T: Debug + PartialEq + 'static +{ fn help_cast_as_any(&self) -> &dyn Any { self } @@ -111,13 +112,14 @@ pub struct Scope { } /// A function which parses a function invocation into a function type. -type ParseFunc = dyn Fn(&FuncHeader, Option<&str>, ParseContext) - -> ParseResult>; +type ParseFunc = dyn Fn(&FuncHeader, Option<&str>, ParseContext) -> ParseResult>; impl Scope { /// Create a new empty scope. pub fn new() -> Scope { - Scope { parsers: HashMap::new() } + Scope { + parsers: HashMap::new(), + } } /// Create a new scope with the standard functions contained. @@ -129,9 +131,7 @@ impl Scope { pub fn add(&mut self, name: &str) { self.parsers.insert( name.to_owned(), - Box::new(|h, b, c| { - F::parse(h, b, c).map(|func| Box::new(func) as Box) - }) + Box::new(|h, b, c| F::parse(h, b, c).map(|func| Box::new(func) as Box)), ); } diff --git a/src/layout/actions.rs b/src/layout/actions.rs index 069c3f7c9..3eb4fb7fd 100644 --- a/src/layout/actions.rs +++ b/src/layout/actions.rs @@ -3,11 +3,10 @@ use std::fmt::{self, Display, Formatter}; use std::io::{self, Write}; -use crate::size::Size2D; use super::Layout; +use crate::size::Size2D; use LayoutAction::*; - /// A layouting action. #[derive(Clone)] pub enum LayoutAction { @@ -30,8 +29,14 @@ impl LayoutAction { MoveAbsolute(s) => write!(f, "m {:.4} {:.4}", s.x.to_pt(), s.y.to_pt()), SetFont(i, s) => write!(f, "f {} {}", i, s), WriteText(s) => write!(f, "w {}", s), - DebugBox(p, s) => write!(f, "b {} {} {} {}", - p.x.to_pt(), p.y.to_pt(), s.x.to_pt(), s.y.to_pt()) + DebugBox(p, s) => write!( + f, + "b {} {} {} {}", + p.x.to_pt(), + p.y.to_pt(), + s.x.to_pt(), + s.y.to_pt() + ), } } } @@ -81,7 +86,7 @@ impl LayoutActionList { SetFont(index, size) if (index, size) != self.active_font => { self.next_font = Some((index, size)); - }, + } _ => { if let Some(target) = self.next_pos.take() { @@ -92,19 +97,21 @@ impl LayoutActionList { } self.actions.push(action); - }, + } } } /// Add a series of actions. - pub fn extend(&mut self, actions: I) where I: IntoIterator { + pub fn extend(&mut self, actions: I) + where I: IntoIterator { for action in actions.into_iter() { self.add(action); } } /// Add all actions from a box layout at a position. A move to the position - /// is generated and all moves inside the box layout are translated as necessary. + /// is generated and all moves inside the box layout are translated as + /// necessary. pub fn add_box(&mut self, position: Size2D, layout: Layout) { if let Some(target) = self.next_pos.take() { self.actions.push(MoveAbsolute(target)); @@ -114,7 +121,8 @@ impl LayoutActionList { self.origin = position; if layout.debug_render { - self.actions.push(LayoutAction::DebugBox(position, layout.dimensions)); + self.actions + .push(LayoutAction::DebugBox(position, layout.dimensions)); } self.extend(layout.actions); diff --git a/src/layout/flex.rs b/src/layout/flex.rs index 704281d3b..ab1f066e3 100644 --- a/src/layout/flex.rs +++ b/src/layout/flex.rs @@ -1,6 +1,5 @@ use super::*; - /// Finishes a flex layout by justifying the positions of the individual boxes. #[derive(Debug)] pub struct FlexLayouter { @@ -32,7 +31,8 @@ enum FlexUnit { /// A content unit to be arranged flexibly. Boxed(Layout), /// A unit which acts as glue between two [`FlexUnit::Boxed`] units and - /// is only present if there was no flow break in between the two surrounding boxes. + /// is only present if there was no flow break in between the two + /// surrounding boxes. Glue(Layout), } @@ -107,7 +107,9 @@ impl FlexLayouter { /// Layout the box. fn boxed(&mut self, boxed: Layout) -> LayoutResult<()> { - let last_glue_x = self.last_glue.as_ref() + let last_glue_x = self + .last_glue + .as_ref() .map(|g| g.dimensions.x) .unwrap_or(Size::zero()); @@ -157,7 +159,7 @@ impl FlexLayouter { // Right align everything by shifting it right by the // amount of space left to the right of the line. cursor + remaining_space - }, + } }; self.actions.add_box(position, layout); @@ -173,7 +175,8 @@ impl FlexLayouter { self.dimensions.y += self.line_metrics.y; - // Reset the cursor the left and move down by the line and the inter-line spacing. + // Reset the cursor the left and move down by the line and the inter-line + // spacing. self.cursor.x = self.ctx.space.padding.left; self.cursor.y += self.line_metrics.y + self.ctx.flex_spacing; diff --git a/src/layout/mod.rs b/src/layout/mod.rs index c8d101414..14aa64172 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -4,24 +4,23 @@ use std::borrow::Cow; use std::io::{self, Write}; use std::mem; -use toddle::query::{SharedFontLoader, FontClass}; +use toddle::query::{FontClass, SharedFontLoader}; use toddle::Error as FontError; use crate::func::Command; use crate::size::{Size, Size2D, SizeBox}; -use crate::syntax::{SyntaxTree, Node, FuncCall}; use crate::style::TextStyle; +use crate::syntax::{FuncCall, Node, SyntaxTree}; -mod text; -mod stacked; -mod flex; mod actions; +mod flex; +mod stacked; +mod text; pub use actions::{LayoutAction, LayoutActionList}; +pub use flex::{FlexContext, FlexLayouter}; +pub use stacked::{StackContext, StackLayouter}; pub use text::{layout_text, TextContext}; -pub use flex::{FlexLayouter, FlexContext}; -pub use stacked::{StackLayouter, StackContext}; - /// A box layout has a fixed width and height and composes of actions. #[derive(Debug, Clone)] @@ -37,7 +36,12 @@ pub struct Layout { impl Layout { /// Serialize this layout into an output buffer. pub fn serialize(&self, f: &mut W) -> io::Result<()> { - writeln!(f, "{:.4} {:.4}", self.dimensions.x.to_pt(), self.dimensions.y.to_pt())?; + writeln!( + f, + "{:.4} {:.4}", + self.dimensions.x.to_pt(), + self.dimensions.y.to_pt() + )?; for action in &self.actions { action.serialize(f)?; writeln!(f)?; @@ -55,9 +59,7 @@ pub struct MultiLayout { impl MultiLayout { /// Create an empty multibox layout. pub fn new() -> MultiLayout { - MultiLayout { - layouts: vec![], - } + MultiLayout { layouts: vec![] } } /// Extract a single sublayout and panic if this layout does not have @@ -158,7 +160,7 @@ impl<'a, 'p> Layouter<'a, 'p> { }, flex_spacing: (ctx.style.line_spacing - 1.0) * Size::pt(ctx.style.font_size), }), - style: Cow::Borrowed(ctx.style) + style: Cow::Borrowed(ctx.style), } } @@ -175,7 +177,7 @@ impl<'a, 'p> Layouter<'a, 'p> { if !self.flex_layouter.is_empty() { self.layout_text(" ", true)?; } - }, + } // Finish the current flex layout and add it to the box layouter. Node::Newline => { @@ -186,7 +188,7 @@ impl<'a, 'p> Layouter<'a, 'p> { let size = Size::pt(self.style.font_size) * (self.style.line_spacing * self.style.paragraph_spacing - 1.0); self.stack_layouter.add_space(size)?; - }, + } // Toggle the text styles. Node::ToggleItalics => self.style.to_mut().toggle_class(FontClass::Italic), @@ -208,16 +210,19 @@ impl<'a, 'p> Layouter<'a, 'p> { } Ok(MultiLayout { - layouts: vec![self.stack_layouter.finish()] + layouts: vec![self.stack_layouter.finish()], }) } /// Layout a piece of text into a box. fn layout_text(&mut self, text: &str, glue: bool) -> LayoutResult<()> { - let boxed = layout_text(text, TextContext { - loader: &self.ctx.loader, - style: &self.style, - })?; + let boxed = layout_text( + text, + TextContext { + loader: &self.ctx.loader, + style: &self.style, + }, + )?; if glue { self.flex_layouter.add_glue(boxed); diff --git a/src/layout/stacked.rs b/src/layout/stacked.rs index 312681ace..5ca32970b 100644 --- a/src/layout/stacked.rs +++ b/src/layout/stacked.rs @@ -1,6 +1,5 @@ use super::*; - /// Layouts boxes block-style. #[derive(Debug)] pub struct StackLayouter { @@ -29,10 +28,13 @@ impl StackLayouter { Alignment::Right => Size2D::with_x(space.usable().x), }, usable: space.usable(), - cursor: Size2D::new(match ctx.space.alignment { - Alignment::Left => space.padding.left, - Alignment::Right => space.dimensions.x - space.padding.right, - }, space.padding.top), + cursor: Size2D::new( + match ctx.space.alignment { + Alignment::Left => space.padding.left, + Alignment::Right => space.dimensions.x - space.padding.right, + }, + space.padding.top, + ), } } diff --git a/src/layout/text.rs b/src/layout/text.rs index cf2580294..27b65d562 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -1,9 +1,8 @@ use toddle::query::{FontQuery, SharedFontLoader}; -use toddle::tables::{Header, CharMap, HorizontalMetrics}; +use toddle::tables::{CharMap, Header, HorizontalMetrics}; -use crate::size::{Size, Size2D}; use super::*; - +use crate::size::{Size, Size2D}; /// The context for text layouting. #[derive(Copy, Clone)] @@ -53,7 +52,8 @@ pub fn layout_text(text: &str, ctx: TextContext) -> LayoutResult { let font_unit_to_size = |x| Size::pt(font_unit_ratio * x); // Add the char width to the total box width. - let glyph = font.read_table::()? + let glyph = font + .read_table::()? .get(character) .expect("layout text: font should have char"); @@ -61,7 +61,7 @@ pub fn layout_text(text: &str, ctx: TextContext) -> LayoutResult { font.read_table::()? .get(glyph) .expect("layout text: font should have glyph") - .advance_width as f32 + .advance_width as f32, ); let char_width = glyph_width * ctx.style.font_size; diff --git a/src/lib.rs b/src/lib.rs index 00ed9e298..fe9d32a60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,26 +1,28 @@ //! The compiler for the _Typst_ typesetting language. //! //! # Steps -//! - **Parsing:** The parsing step first transforms a plain string into an [iterator of -//! tokens](crate::parsing::Tokens). Then parser constructs a syntax tree from the token stream. -//! The structures describing the tree can be found in the [syntax]. Dynamic functions parse -//! their own bodies themselves. -//! - **Layouting:** The next step is to transform the syntax tree into a portable representation of -//! the typesetted document. Types for these can be found in the [layout] module. -//! - **Exporting:** The finished document can then be exported into supported formats. Submodules -//! for the supported formats are located in the [export] module. Currently the only supported -//! format is _PDF_. +//! - **Parsing:** The parsing step first transforms a plain string into an +//! [iterator of tokens](crate::parsing::Tokens). Then parser constructs a +//! syntax tree from the token stream. The structures describing the tree can +//! be found in the [syntax]. Dynamic functions parse their own bodies +//! themselves. +//! - **Layouting:** The next step is to transform the syntax tree into a +//! portable representation of the typesetted document. Types for these can be +//! found in the [layout] module. +//! - **Exporting:** The finished document can then be exported into supported +//! formats. Submodules for the supported formats are located in the [export] +//! module. Currently the only supported format is _PDF_. pub extern crate toddle; use std::cell::RefCell; -use toddle::query::{FontLoader, SharedFontLoader, FontProvider}; +use toddle::query::{FontLoader, FontProvider, SharedFontLoader}; use crate::func::Scope; -use crate::parsing::{parse, ParseContext, ParseResult, ParseError}; use crate::layout::{layout_tree, LayoutContext, MultiLayout}; -use crate::layout::{LayoutSpace, Alignment, LayoutError, LayoutResult}; +use crate::layout::{Alignment, LayoutError, LayoutResult, LayoutSpace}; +use crate::parsing::{parse, ParseContext, ParseError, ParseResult}; use crate::style::{PageStyle, TextStyle}; use crate::syntax::SyntaxTree; @@ -29,12 +31,11 @@ mod macros; pub mod export; pub mod func; pub mod layout; +pub mod library; pub mod parsing; pub mod size; pub mod style; pub mod syntax; -pub mod library; - /// Transforms source code into typesetted documents. /// @@ -73,7 +74,8 @@ impl<'p> Typesetter<'p> { /// Add a font provider to the context of this typesetter. #[inline] - pub fn add_font_provider(&mut self, provider: P) where P: FontProvider { + pub fn add_font_provider(&mut self, provider: P) + where P: FontProvider { self.loader.get_mut().add_provider(provider); } @@ -98,12 +100,15 @@ impl<'p> Typesetter<'p> { shrink_to_fit: false, }; - let pages = layout_tree(&tree, LayoutContext { - loader: &self.loader, - style: &self.text_style, - space, - extra_space: Some(space), - })?; + let pages = layout_tree( + &tree, + LayoutContext { + loader: &self.loader, + style: &self.text_style, + space, + extra_space: Some(space), + }, + )?; Ok(pages) } @@ -116,7 +121,6 @@ impl<'p> Typesetter<'p> { } } - /// The general error type for typesetting. pub enum TypesetError { /// An error that occured while parsing. diff --git a/src/library/align.rs b/src/library/align.rs index 322a9efae..4dc5f53c6 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -1,7 +1,6 @@ use super::prelude::*; use crate::layout::Alignment; - /// Allows to align content in different ways. #[derive(Debug, PartialEq)] pub struct AlignFunc { @@ -10,9 +9,8 @@ pub struct AlignFunc { } impl Function for AlignFunc { - fn parse(header: &FuncHeader, body: Option<&str>, ctx: ParseContext) - -> ParseResult where Self: Sized { - + fn parse(header: &FuncHeader, body: Option<&str>, ctx: ParseContext) -> ParseResult + where Self: Sized { if header.args.len() != 1 || !header.kwargs.is_empty() { return err("expected exactly one positional argument specifying the alignment"); } @@ -24,7 +22,10 @@ impl Function for AlignFunc { s => return err(format!("invalid alignment specifier: '{}'", s)), } } else { - return err(format!("expected alignment specifier, found: '{}'", header.args[0])); + return err(format!( + "expected alignment specifier, found: '{}'", + header.args[0] + )); }; let body = if let Some(body) = body { diff --git a/src/library/mod.rs b/src/library/mod.rs index 848ba8476..f3156b4a0 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -7,11 +7,11 @@ mod styles; /// Useful imports for creating your own functions. pub mod prelude { - pub use crate::syntax::{SyntaxTree, FuncHeader, Expression}; - pub use crate::parsing::{parse, ParseContext, ParseResult, ParseError}; - pub use crate::layout::{layout_tree, LayoutContext, MultiLayout, Layout}; - pub use crate::layout::{LayoutResult, LayoutError}; - pub use crate::func::{Function, Command, FuncCommands}; + pub use crate::func::{Command, FuncCommands, Function}; + pub use crate::layout::{layout_tree, Layout, LayoutContext, MultiLayout}; + pub use crate::layout::{LayoutError, LayoutResult}; + pub use crate::parsing::{parse, ParseContext, ParseError, ParseResult}; + pub use crate::syntax::{Expression, FuncHeader, SyntaxTree}; pub fn err, T>(message: S) -> ParseResult { Err(ParseError::new(message)) @@ -19,8 +19,7 @@ pub mod prelude { } pub use align::AlignFunc; -pub use styles::{ItalicFunc, BoldFunc, MonospaceFunc}; - +pub use styles::{BoldFunc, ItalicFunc, MonospaceFunc}; /// Create a scope with all standard functions. pub fn std() -> Scope { diff --git a/src/library/styles.rs b/src/library/styles.rs index c588ac5e4..666c8975d 100644 --- a/src/library/styles.rs +++ b/src/library/styles.rs @@ -2,7 +2,6 @@ use toddle::query::FontClass; use super::prelude::*; - macro_rules! style_func { ( $(#[$outer:meta])* diff --git a/src/parsing/mod.rs b/src/parsing/mod.rs index fa71270e0..0f5ca0f8a 100644 --- a/src/parsing/mod.rs +++ b/src/parsing/mod.rs @@ -5,14 +5,13 @@ use std::collections::HashMap; use unicode_xid::UnicodeXID; use crate::func::{Function, Scope}; -use crate::syntax::*; use crate::size::Size; +use crate::syntax::*; mod tokens; pub use tokens::{tokenize, Tokens}; - /// Parses source code into a syntax tree given a context. #[inline] pub fn parse(src: &str, ctx: ParseContext) -> ParseResult { @@ -105,10 +104,7 @@ impl<'s> Parser<'s> { let body = self.parse_func_body(&header)?; // Finally this function is parsed to the end. - self.append(Node::Func(FuncCall { - header, - body, - })); + self.append(Node::Func(FuncCall { header, body })); Ok(self.switch(ParserState::Body)) } @@ -124,7 +120,7 @@ impl<'s> Parser<'s> { } else { Err(ParseError::new(format!("invalid identifier: '{}'", word))) } - }, + } _ => Err(ParseError::new("expected identifier")), }?; @@ -138,13 +134,17 @@ impl<'s> Parser<'s> { // Check for arguments match self.tokens.next() { - Some(Token::RightBracket) => {}, + Some(Token::RightBracket) => {} Some(Token::Colon) => { let (args, kwargs) = self.parse_func_args()?; header.args = args; header.kwargs = kwargs; - }, - _ => return Err(ParseError::new("expected function arguments or closing bracket")), + } + _ => { + return Err(ParseError::new( + "expected function arguments or closing bracket", + )) + } } // Store the header information of the function invocation. @@ -164,16 +164,16 @@ impl<'s> Parser<'s> { Some(Token::Text(_)) | Some(Token::Quoted(_)) if !comma => { args.push(self.parse_expression()?); comma = true; - }, + } Some(Token::Comma) if comma => { self.advance(); comma = false - }, + } Some(Token::RightBracket) => { self.advance(); - break - }, + break; + } _ if comma => return Err(ParseError::new("expected comma or closing bracket")), _ => return Err(ParseError::new("expected closing bracket")), @@ -197,7 +197,7 @@ impl<'s> Parser<'s> { } else { Expression::Ident(text.to_owned()) } - }, + } _ => return Err(ParseError::new("expected expression")), }) } @@ -211,19 +211,25 @@ impl<'s> Parser<'s> { } // Now we want to parse this function dynamically. - let parser = self.ctx.scope.get_parser(&header.name) + let parser = self + .ctx + .scope + .get_parser(&header.name) .ok_or_else(|| ParseError::new(format!("unknown function: '{}'", &header.name)))?; // Do the parsing dependent on whether the function has a body. Ok(if has_body { // Find out the string which makes the body of this function. - let (start, end) = self.tokens.current_index().and_then(|index| { - find_closing_bracket(&self.src[index..]) - .map(|end| (index, index + end)) - }).ok_or_else(|| ParseError::new("expected closing bracket"))?; + let (start, end) = self + .tokens + .current_index() + .and_then(|index| { + find_closing_bracket(&self.src[index..]).map(|end| (index, index + end)) + }) + .ok_or_else(|| ParseError::new("expected closing bracket"))?; // Parse the body. - let body_string = &self.src[start .. end]; + let body_string = &self.src[start..end]; let body = parser(&header, Some(body_string), self.ctx)?; // Skip to the end of the function in the token stream. @@ -246,12 +252,12 @@ impl<'s> Parser<'s> { Token::Newline => { self.append_consumed(Node::Newline); self.switch(ParserState::WroteNewline); - }, + } Token::Space => self.append_space_consumed(), _ => { self.append_space(); self.switch(ParserState::Body); - }, + } }, ParserState::WroteNewline => match token { Token::Newline | Token::Space => self.append_space_consumed(), @@ -263,17 +269,17 @@ impl<'s> Parser<'s> { Token::Newline => { self.advance(); self.switch(ParserState::FirstNewline); - }, + } // Comments Token::LineComment(_) | Token::BlockComment(_) => self.advance(), Token::StarSlash => { return Err(ParseError::new("unexpected end of block comment")); - }, + } // Anything else skips out of the function. _ => break, - } + }, } } @@ -284,8 +290,9 @@ impl<'s> Parser<'s> { fn skip_white(&mut self) { while let Some(token) = self.tokens.peek() { match token { - Token::Space | Token::Newline - | Token::LineComment(_) | Token::BlockComment(_) => self.advance(), + Token::Space | Token::Newline | Token::LineComment(_) | Token::BlockComment(_) => { + self.advance() + } _ => break, } } @@ -335,19 +342,19 @@ fn find_closing_bracket(src: &str) -> Option { '\\' => { escaped = !escaped; continue; - }, + } ']' if !escaped && parens == 0 => return Some(index), '[' if !escaped => parens += 1, ']' if !escaped => parens -= 1, - _ => {}, + _ => {} } escaped = false; } None } -/// A peekable iterator for tokens which allows access to the original iterator inside this module -/// (which is needed by the parser). +/// A peekable iterator for tokens which allows access to the original iterator +/// inside this module (which is needed by the parser). #[derive(Debug, Clone)] struct PeekableTokens<'s> { tokens: Tokens<'s>, @@ -411,7 +418,6 @@ fn is_identifier(string: &str) -> bool { true } - /// The error type for parsing. pub struct ParseError(String); @@ -430,17 +436,16 @@ error_type! { show: f => f.write_str(&err.0), } - #[cfg(test)] mod tests { use super::*; - use crate::func::{Function, FuncCommands, Scope}; + use crate::func::{FuncCommands, Function, Scope}; use crate::layout::{LayoutContext, LayoutResult}; - use Node::{Space as S, Newline as N, Func as F}; use funcs::*; + use Node::{Func as F, Newline as N, Space as S}; - /// Two test functions, one which parses it's body as another syntax tree and another one which - /// does not expect a body. + /// Two test functions, one which parses it's body as another syntax tree + /// and another one which does not expect a body. mod funcs { use super::*; @@ -449,8 +454,8 @@ mod tests { pub struct TreeFn(pub SyntaxTree); impl Function for TreeFn { - fn parse(_: &FuncHeader, body: Option<&str>, ctx: ParseContext) - -> ParseResult where Self: Sized { + fn parse(_: &FuncHeader, body: Option<&str>, ctx: ParseContext) -> ParseResult + where Self: Sized { if let Some(src) = body { parse(src, ctx).map(|tree| TreeFn(tree)) } else { @@ -468,8 +473,8 @@ mod tests { pub struct BodylessFn; impl Function for BodylessFn { - fn parse(_: &FuncHeader, body: Option<&str>, _: ParseContext) - -> ParseResult where Self: Sized { + fn parse(_: &FuncHeader, body: Option<&str>, _: ParseContext) -> ParseResult + where Self: Sized { if body.is_none() { Ok(BodylessFn) } else { @@ -485,7 +490,9 @@ mod tests { /// Test if the source code parses into the syntax tree. fn test(src: &str, tree: SyntaxTree) { - let ctx = ParseContext { scope: &Scope::new() }; + let ctx = ParseContext { + scope: &Scope::new(), + }; assert_eq!(parse(src, ctx).unwrap(), tree); } @@ -497,7 +504,9 @@ mod tests { /// Test if the source parses into the error. fn test_err(src: &str, err: &str) { - let ctx = ParseContext { scope: &Scope::new() }; + let ctx = ParseContext { + scope: &Scope::new(), + }; assert_eq!(parse(src, ctx).unwrap_err().to_string(), err); } @@ -509,9 +518,12 @@ mod tests { /// Create a text node. #[allow(non_snake_case)] - fn T(s: &str) -> Node { Node::Text(s.to_owned()) } + fn T(s: &str) -> Node { + Node::Text(s.to_owned()) + } - /// Shortcut macro to create a syntax tree. Is `vec`-like and the elements are the nodes. + /// Shortcut macro to create a syntax tree. Is `vec`-like and the elements + /// are the nodes. macro_rules! tree { ($($x:expr),*) => ( SyntaxTree { nodes: vec![$($x),*] } diff --git a/src/parsing/tokens.rs b/src/parsing/tokens.rs index 869e3821d..295b13d86 100644 --- a/src/parsing/tokens.rs +++ b/src/parsing/tokens.rs @@ -4,7 +4,6 @@ use smallvec::SmallVec; use crate::syntax::*; - /// Builds an iterator over the tokens of the source code. #[inline] pub fn tokenize(src: &str) -> Tokens { @@ -15,7 +14,7 @@ pub fn tokenize(src: &str) -> Tokens { #[derive(Debug, Clone)] pub struct Tokens<'s> { src: &'s str, - pub(in super) chars: PeekableChars<'s>, + pub(super) chars: PeekableChars<'s>, state: TokensState, stack: SmallVec<[TokensState; 1]>, } @@ -56,7 +55,7 @@ impl<'s> Tokens<'s> { /// Go back to the top-of-stack state. fn unswitch(&mut self) { - self.state = self.stack.pop().unwrap_or(TokensState::Body); + self.state = self.stack.pop().unwrap_or(TokensState::Body); } /// Advance and return the given token. @@ -67,7 +66,7 @@ impl<'s> Tokens<'s> { /// Returns a word containing the string bounded by the given indices. fn text(&self, start: usize, end: usize) -> Token<'s> { - Token::Text(&self.src[start .. end]) + Token::Text(&self.src[start..end]) } } @@ -78,7 +77,8 @@ impl<'s> Iterator for Tokens<'s> { fn next(&mut self) -> Option> { use TokensState as TU; - // Go to the body state if the function has a body or return to the top-of-stack state. + // Go to the body state if the function has a body or return to the top-of-stack + // state. if self.state == TU::MaybeBody { if self.chars.peek()?.1 == '[' { self.state = TU::Body; @@ -97,7 +97,7 @@ impl<'s> Iterator for Tokens<'s> { '[' => { self.switch(TU::Function); Token::LeftBracket - }, + } ']' => { if self.state == TU::Function { self.state = TU::MaybeBody; @@ -105,7 +105,7 @@ impl<'s> Iterator for Tokens<'s> { self.unswitch(); } Token::RightBracket - }, + } // Line comment '/' if afterwards == Some('/') => { @@ -121,8 +121,8 @@ impl<'s> Iterator for Tokens<'s> { } let end = end.0 + end.1.len_utf8(); - Token::LineComment(&self.src[start .. end]) - }, + Token::LineComment(&self.src[start..end]) + } // Block comment '/' if afterwards == Some('*') => { @@ -133,17 +133,26 @@ impl<'s> Iterator for Tokens<'s> { while let Some((index, c)) = self.chars.next() { let after = self.chars.peek().map(|p| p.1); match (c, after) { - ('*', Some('/')) if nested == 0 => { self.advance(); break }, - ('/', Some('*')) => { self.advance(); nested += 1 }, - ('*', Some('/')) => { self.advance(); nested -= 1 }, - _ => {}, + ('*', Some('/')) if nested == 0 => { + self.advance(); + break; + } + ('/', Some('*')) => { + self.advance(); + nested += 1 + } + ('*', Some('/')) => { + self.advance(); + nested -= 1 + } + _ => {} } end = (index, c); } let end = end.0 + end.1.len_utf8(); - Token::BlockComment(&self.src[start .. end]) - }, + Token::BlockComment(&self.src[start..end]) + } // Unexpected end of block comment '*' if afterwards == Some('/') => self.consumed(Token::StarSlash), @@ -189,7 +198,7 @@ impl<'s> Iterator for Tokens<'s> { } let end_pos = end.0 + end.1.len_utf8(); - Token::Quoted(&self.src[next_pos + 1 .. end_pos]) + Token::Quoted(&self.src[next_pos + 1..end_pos]) } // Escaping @@ -207,7 +216,7 @@ impl<'s> Iterator for Tokens<'s> { } Token::Text("\\") - }, + } // Normal text _ => { @@ -241,7 +250,7 @@ impl<'s> Iterator for Tokens<'s> { let end_pos = end.0 + end.1.len_utf8(); self.text(next_pos, end_pos) - }, + } }) } } @@ -328,20 +337,20 @@ impl Iterator for PeekableChars<'_> { Some(value) => { self.peek1 = self.peek2.take(); value - }, + } None => self.next_inner(), } } } - #[cfg(test)] mod tests { use super::*; - use Token::{Space as S, Newline as N, LeftBracket as L, RightBracket as R, - Colon as C, Equals as E, Quoted as Q, Underscore as TU, Star as TS, - Backtick as TB, Text as T, LineComment as LC, BlockComment as BC, - StarSlash as SS}; + use Token::{ + Backtick as TB, BlockComment as BC, Colon as C, Equals as E, LeftBracket as L, + LineComment as LC, Newline as N, Quoted as Q, RightBracket as R, Space as S, Star as TS, + StarSlash as SS, Text as T, Underscore as TU, + }; /// Test if the source code tokenizes to the tokens. fn test(src: &str, tokens: Vec) { diff --git a/src/size.rs b/src/size.rs index f2e44e47f..e837a6398 100644 --- a/src/size.rs +++ b/src/size.rs @@ -6,7 +6,6 @@ use std::iter::Sum; use std::ops::*; use std::str::FromStr; - /// A general spacing type. #[derive(Copy, Clone, PartialEq, Default)] pub struct Size { @@ -39,57 +38,89 @@ pub struct SizeBox { impl Size { /// Create a zeroed size. #[inline] - pub fn zero() -> Size { Size::default() } + pub fn zero() -> Size { + Size::default() + } /// Create a size from an amount of points. #[inline] - pub fn pt(points: f32) -> Size { Size { points } } + pub fn pt(points: f32) -> Size { + Size { points } + } /// Create a size from an amount of millimeters. #[inline] - pub fn mm(mm: f32) -> Size { Size { points: 2.83465 * mm } } + pub fn mm(mm: f32) -> Size { + Size { + points: 2.83465 * mm, + } + } /// Create a size from an amount of centimeters. #[inline] - pub fn cm(cm: f32) -> Size { Size { points: 28.3465 * cm } } + pub fn cm(cm: f32) -> Size { + Size { + points: 28.3465 * cm, + } + } /// Create a size from an amount of inches. #[inline] - pub fn inches(inches: f32) -> Size { Size { points: 72.0 * inches } } + pub fn inches(inches: f32) -> Size { + Size { + points: 72.0 * inches, + } + } /// Convert this size into points. #[inline] - pub fn to_pt(&self) -> f32 { self.points } + pub fn to_pt(&self) -> f32 { + self.points + } /// Convert this size into millimeters. #[inline] - pub fn to_mm(&self) -> f32 { self.points * 0.352778 } + pub fn to_mm(&self) -> f32 { + self.points * 0.352778 + } /// Convert this size into centimeters. #[inline] - pub fn to_cm(&self) -> f32 { self.points * 0.0352778 } + pub fn to_cm(&self) -> f32 { + self.points * 0.0352778 + } /// Convert this size into inches. #[inline] - pub fn to_inches(&self) -> f32 { self.points * 0.0138889 } + pub fn to_inches(&self) -> f32 { + self.points * 0.0138889 + } } impl Size2D { /// Create a new vector from two sizes. #[inline] - pub fn new(x: Size, y: Size) -> Size2D { Size2D { x, y } } + pub fn new(x: Size, y: Size) -> Size2D { + Size2D { x, y } + } /// Create a vector with all set to zero. #[inline] - pub fn zero() -> Size2D { Size2D::default() } + pub fn zero() -> Size2D { + Size2D::default() + } /// Create a new vector with `y` set to zero and `x` to a value. #[inline] - pub fn with_x(x: Size) -> Size2D { Size2D { x, y: Size::zero() } } + pub fn with_x(x: Size) -> Size2D { + Size2D { x, y: Size::zero() } + } /// Create a new vector with `x` set to zero and `y` to a value. #[inline] - pub fn with_y(y: Size) -> Size2D { Size2D { x: Size::zero(), y } } + pub fn with_y(y: Size) -> Size2D { + Size2D { x: Size::zero(), y } + } /// Return a [`Size2D`] padded by the paddings of the given box. #[inline] @@ -105,7 +136,12 @@ impl SizeBox { /// Create a new box from four sizes. #[inline] pub fn new(left: Size, top: Size, right: Size, bottom: Size) -> SizeBox { - SizeBox { left, top, right, bottom } + SizeBox { + left, + top, + right, + bottom, + } } /// Create a box with all set to zero. @@ -117,12 +153,20 @@ impl SizeBox { /// The maximum of two sizes. pub fn max(a: Size, b: Size) -> Size { - if a >= b { a } else { b } + if a >= b { + a + } else { + b + } } /// The minimum of two sizes. pub fn min(a: Size, b: Size) -> Size { - if a <= b { a } else { b } + if a <= b { + a + } else { + b + } } //------------------------------------------------------------------------------------------------// @@ -146,10 +190,11 @@ impl FromStr for Size { return Err(ParseSizeError); } - let value = src[.. src.len() - 2].parse::() + let value = src[..src.len() - 2] + .parse::() .map_err(|_| ParseSizeError)?; - Ok(match &src[src.len() - 2 ..] { + Ok(match &src[src.len() - 2..] { "pt" => Size::pt(value), "mm" => Size::mm(value), "cm" => Size::cm(value), @@ -171,13 +216,16 @@ impl Neg for Size { #[inline] fn neg(self) -> Size { - Size { points: -self.points } + Size { + points: -self.points, + } } } impl Sum for Size { #[inline] - fn sum(iter: I) -> Size where I: Iterator { + fn sum(iter: I) -> Size + where I: Iterator { iter.fold(Size::zero(), Add::add) } } @@ -189,7 +237,9 @@ macro_rules! impl_reflexive { #[inline] fn $func(self, other: Size) -> Size { - Size { points: $trait::$func(self.points, other.points) } + Size { + points: $trait::$func(self.points, other.points), + } } } @@ -209,7 +259,9 @@ macro_rules! impl_num_back { #[inline] fn $func(self, other: $ty) -> Size { - Size { points: $trait::$func(self.points, other as f32) } + Size { + points: $trait::$func(self.points, other as f32), + } } } @@ -231,7 +283,9 @@ macro_rules! impl_num_both { #[inline] fn $func(self, other: Size) -> Size { - Size { points: $trait::$func(self as f32, other.points) } + Size { + points: $trait::$func(self as f32, other.points), + } } } }; @@ -257,7 +311,10 @@ impl Neg for Size2D { #[inline] fn neg(self) -> Size2D { - Size2D { x: -self.x, y: -self.y } + Size2D { + x: -self.x, + y: -self.y, + } } } @@ -336,8 +393,11 @@ impl_num_back2d!(Div, div, DivAssign, div_assign, i32); impl Display for SizeBox { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "[left: {}, top: {}, right: {}, bottom: {}]", - self.left, self.top, self.right, self.bottom) + write!( + f, + "[left: {}, top: {}, right: {}, bottom: {}]", + self.left, self.top, self.right, self.bottom + ) } } diff --git a/src/style.rs b/src/style.rs index b9c377905..3bc1e33f2 100644 --- a/src/style.rs +++ b/src/style.rs @@ -4,14 +4,13 @@ use toddle::query::FontClass; use crate::size::{Size, Size2D, SizeBox}; - /// Default styles for text. #[derive(Debug, Clone)] pub struct TextStyle { /// The classes the font we want has to be part of. pub classes: Vec, - /// A sequence of classes. We need the font to be part of at least one of these - /// and preferably the leftmost possible. + /// A sequence of classes. We need the font to be part of at least one of + /// these and preferably the leftmost possible. pub fallback: Vec, /// The font size. pub font_size: f32, @@ -26,13 +25,14 @@ impl TextStyle { /// /// If the class was one of _italic_ or _bold_, then: /// - If it was not present, the _regular_ class will be removed. - /// - If it was present, the _regular_ class will be added in case the - /// other style class is not present. + /// - If it was present, the _regular_ class will be added in case the other + /// style class is not present. pub fn toggle_class(&mut self, class: FontClass) { if self.classes.contains(&class) { self.classes.retain(|x| x != &class); if (class == FontClass::Italic && !self.classes.contains(&FontClass::Bold)) - || (class == FontClass::Bold && !self.classes.contains(&FontClass::Italic)) { + || (class == FontClass::Bold && !self.classes.contains(&FontClass::Italic)) + { self.classes.push(FontClass::Regular); } } else { diff --git a/src/syntax.rs b/src/syntax.rs index b21406420..9c7e4908b 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -6,24 +6,26 @@ use std::fmt::{self, Display, Formatter}; use crate::func::Function; use crate::size::Size; - /// A logical unit of the incoming text stream. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Token<'s> { /// One or more whitespace (non-newline) codepoints. Space, - /// A line feed (`\n`, `\r\n` and some more as defined by the Unicode standard). + /// A line feed (`\n`, `\r\n` and some more as defined by the Unicode + /// standard). Newline, /// A left bracket: `[`. LeftBracket, /// A right bracket: `]`. RightBracket, - /// A colon (`:`) indicating the beginning of function arguments (Function header only). + /// A colon (`:`) indicating the beginning of function arguments (Function + /// header only). /// - /// If a colon occurs outside of a function header, it will be tokenized as a - /// [Word](Token::Word). + /// If a colon occurs outside of a function header, it will be tokenized as + /// a [Word](Token::Word). Colon, - /// An equals (`=`) sign assigning a function argument a value (Function header only). + /// An equals (`=`) sign assigning a function argument a value (Function + /// header only). Equals, /// A comma (`,`) separating two function arguments (Function header only). Comma, @@ -39,8 +41,9 @@ pub enum Token<'s> { LineComment(&'s str), /// A block comment. BlockComment(&'s str), - /// A star followed by a slash unexpectedly ending a block comment (the comment was not started - /// before, otherwise a [BlockComment](Token::BlockComment) would be returned). + /// A star followed by a slash unexpectedly ending a block comment (the + /// comment was not started before, otherwise a + /// [BlockComment](Token::BlockComment) would be returned). StarSlash, /// Everything else is just text. Text(&'s str), @@ -98,7 +101,7 @@ impl PartialEq for FuncCall { pub struct FuncHeader { pub name: String, pub args: Vec, - pub kwargs: HashMap + pub kwargs: HashMap, } /// A value expression. diff --git a/tests/layouting.rs b/tests/layouting.rs index 0174b097c..cb7b75ef8 100644 --- a/tests/layouting.rs +++ b/tests/layouting.rs @@ -1,15 +1,14 @@ use std::fs::{self, File}; -use std::io::{Write, Read, BufWriter}; +use std::io::{BufWriter, Read, Write}; use std::process::Command; -use typst::Typesetter; +use typst::export::pdf::PdfExporter; use typst::layout::LayoutAction; use typst::toddle::query::FileSystemFontProvider; -use typst::export::pdf::PdfExporter; +use typst::Typesetter; const CACHE_DIR: &str = "test-cache"; - fn main() { let mut perfect_match = false; let mut filter = Vec::new(); @@ -31,9 +30,7 @@ fn main() { for entry in fs::read_dir("tests/layouts/").unwrap() { let path = entry.unwrap().path(); - let name = path - .file_stem().unwrap() - .to_str().unwrap(); + let name = path.file_stem().unwrap().to_str().unwrap(); let matches = if perfect_match { filter.iter().any(|pattern| name == pattern)