diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 2e7938ed2..80341decb 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -30,6 +30,8 @@ pub struct Engine<'t> { current_text: String, current_line_width: Size, current_max_vertical_move: Size, + bold: bool, + italic: bool, } impl<'t> Engine<'t> { @@ -44,6 +46,8 @@ impl<'t> Engine<'t> { current_text: String::new(), current_line_width: Size::zero(), current_max_vertical_move: Size::zero(), + italic: false, + bold: false, } } @@ -57,8 +61,12 @@ impl<'t> Engine<'t> { match node { Node::Word(word) => self.write_word(word)?, Node::Space => self.write_space()?, - Node::Newline => (), - Node::ToggleItalics | Node::ToggleBold | Node::ToggleMath => unimplemented!(), + Node::Newline => {}, + + Node::ToggleItalics => self.italic = !self.italic, + Node::ToggleBold => self.bold = !self.bold, + + Node::ToggleMath => unimplemented!(), Node::Func(_) => unimplemented!(), } } @@ -177,8 +185,8 @@ impl<'t> Engine<'t> { fn get_font_for(&self, character: char) -> TypeResult<(usize, Ref)> { self.font_loader.get(FontQuery { families: &self.ctx.style.font_families, - italic: false, - bold: false, + italic: self.italic, + bold: self.bold, character, }).ok_or_else(|| TypesetError::MissingFont) } diff --git a/src/font.rs b/src/font.rs index 53d31a41d..f9039a718 100644 --- a/src/font.rs +++ b/src/font.rs @@ -13,7 +13,7 @@ use std::collections::HashMap; use std::fs::File; use std::path::PathBuf; -use std::io::{self, Cursor, Read, Seek, SeekFrom}; +use std::io::{self, Cursor, Read, Seek, SeekFrom, BufReader}; use byteorder::{BE, ReadBytesExt, WriteBytesExt}; use opentype::{Error as OpentypeError, OpenTypeReader, Outlines, TableRecord, Tag}; use opentype::tables::{Header, Name, CharMap, MaximumProfile, HorizontalMetrics, Post, OS2}; @@ -339,7 +339,7 @@ impl FontProvider for FileSystemFontProvider { let index = self.infos.iter().position(|i| i == info)?; let path = &self.paths[index]; let file = File::open(self.base.join(path)).ok()?; - Some(Box::new(file) as Box) + Some(Box::new(BufReader::new(file)) as Box) } #[inline] diff --git a/src/lib.rs b/src/lib.rs index f8c0c59be..d9d250b96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ //! use typeset::export::pdf::PdfExporter; //! //! // Simple example source code. -//! let src = "Hello World from Typeset! 🌍"; +//! let src = "Hello World from __Typeset__! 🌍"; //! //! // Create a compiler with a font provider that provides three fonts //! // (the default sans-serif fonts and a fallback for the emoji). @@ -38,7 +38,7 @@ //! # /* //! let file = File::create("hello-typeset.pdf").unwrap(); //! # */ -//! # let file = File::create("../target/typeset-hello.pdf").unwrap(); +//! # let file = File::create("../target/typeset-doc-hello.pdf").unwrap(); //! let exporter = PdfExporter::new(); //! exporter.export(&document, file).unwrap(); //! ``` @@ -167,16 +167,16 @@ mod test { let document = compiler.typeset(src).unwrap(); // Write to file - let path = format!("../target/typeset-pdf-{}.pdf", name); + let path = format!("../target/typeset-unit-{}.pdf", name); let file = BufWriter::new(File::create(path).unwrap()); let exporter = PdfExporter::new(); exporter.export(&document, file).unwrap(); } #[test] - fn small() { + fn simple() { test("parentheses", "Text with ) and ( or (enclosed) works."); - test("multiline"," + test("multiline-lorem"," Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet @@ -184,21 +184,22 @@ mod test { "); } - #[test] - fn unicode() { - test("unicode", "∑mbe∂∂ed font with Unicode!"); - } - #[test] fn composite_glyph() { test("composite-glyph", "Composite character‼"); } #[test] - fn mixed_emoji() { + fn unicode() { + test("unicode", "∑mbe∂∂ed font with Unicode!"); test("mixed-emoji", "Hello World 🌍!") } + #[test] + fn styled() { + test("styled", "**Hello World**. That's __great__!"); + } + #[test] fn long_wikipedia() { test("wikipedia", r#" diff --git a/src/parsing.rs b/src/parsing.rs index 4341ed4af..085e7d1b6 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -249,7 +249,12 @@ impl<'s, T> Parser<'s, T> where T: Iterator> { PS::Body => match token { // Whitespace Token::Space => self.append(Node::Space), - Token::Newline => self.append(Node::Newline), + Token::Newline => { + self.append(Node::Newline); + if self.tokens.peek() != Some(&Token::Space) { + self.append(Node::Space); + } + }, // Words Token::Word(word) => self.append(Node::Word(word)), @@ -382,6 +387,17 @@ mod token_tests { test("\n", vec![N]); } + /// This test looks if LF- and CRLF-style newlines get both identified correctly + #[test] + fn tokenize_whitespace_newlines() { + test(" \t", vec![S]); + test("First line\r\nSecond line\nThird line\n", + vec![W("First"), S, W("line"), N, W("Second"), S, W("line"), N, + W("Third"), S, W("line"), N]); + test("Hello \n ", vec![W("Hello"), S, N, S]); + test("Dense\nTimes", vec![W("Dense"), N, W("Times")]); + } + /// Tests if escaping with backslash works as it should. #[test] fn tokenize_escape() { @@ -454,21 +470,12 @@ mod token_tests { vec![L, W("document"), R, L, W("Hello"), S, W("🌍"), W("!"), R]); test("[f]⺐.", vec![L, W("f"), R, W("⺐"), W(".")]); } - - /// This test looks if LF- and CRLF-style newlines get both identified correctly. - #[test] - fn tokenize_whitespace_newlines() { - test(" \t", vec![S]); - test("First line\r\nSecond line\nThird line\n", - vec![W("First"), S, W("line"), N, W("Second"), S, W("line"), N, - W("Third"), S, W("line"), N]); - } } #[cfg(test)] mod parse_tests { use super::*; - use Node::{Space as S, Word as W, Func as F}; + use Node::{Space as S, Word as W, Newline as N, Func as F}; /// Test if the source code parses into the syntax tree. fn test(src: &str, tree: SyntaxTree) { @@ -496,6 +503,15 @@ mod parse_tests { test("Hello World!", tree! { W("Hello"), S, W("World"), W("!")}); } + /// Test whether newlines generate the correct whitespace. + #[test] + fn parse_newlines_whitespace() { + test("Hello \n World", tree! { W("Hello"), S, N, S, W("World") }); + test("Hello\nWorld", tree! { W("Hello"), N, S, W("World") }); + test("Hello\n World", tree! { W("Hello"), N, S, W("World") }); + test("Hello \nWorld", tree! { W("Hello"), S, N, S, W("World") }); + } + /// Parse things dealing with functions. #[test] fn parse_functions() {