diff options
| author | Laurenz <laurmaedje@gmail.com> | 2019-03-11 17:24:00 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2019-03-11 17:24:00 +0100 |
| commit | 67281c4f469716c7f2341676f2ad656d8c544ea3 (patch) | |
| tree | 4a5bd6602306369db2b9e99b7cbb405f72b816d5 /src/doc.rs | |
| parent | 5942c3ba2ab1cd71f86749a91bc04e45da175f96 (diff) | |
Redesign document representation 🧱
Diffstat (limited to 'src/doc.rs')
| -rw-r--r-- | src/doc.rs | 217 |
1 files changed, 61 insertions, 156 deletions
@@ -1,34 +1,60 @@ -//! Generation of abstract documents from syntax trees. +//! Abstract representation of a typesetted document. -#![allow(dead_code)] +use std::ops; +use crate::font::Font; -use std::fmt; -use crate::parsing::{SyntaxTree, Node}; - -/// Abstract representation of a complete typesetted document. -/// -/// This abstract thing can then be serialized into a specific format like _PDF_. #[derive(Debug, Clone, PartialEq)] pub struct Document { - /// The pages of the document. pub pages: Vec<Page>, - /// The font the document is written in. - pub font: String, + pub fonts: Vec<Font>, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Style { + // Paper + pub paper_size: [Size; 2], + pub margins: [Size; 4], + + // Font handling + pub font_families: Vec<String>, + pub font_size: f32, +} + +impl Default for Style { + fn default() -> Style { + Style { + // A4 paper with 1.5 cm margins in all directions + paper_size: [Size::from_mm(210.0), Size::from_mm(297.0)], + margins: [Size::from_cm(2.5); 4], + + // Default font family + font_families: (&[ + "NotoSans", "NotoSansMath" + ]).iter().map(ToString::to_string).collect(), + font_size: 12.0, + } + } } -/// A page of a document. #[derive(Debug, Clone, PartialEq)] pub struct Page { - /// The width and height of the page. - pub size: [Size; 2], - /// The contents of the page. - pub contents: Vec<Text>, + pub width: Size, + pub height: Size, + pub text: Vec<Text>, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Text { + pub commands: Vec<TextCommand>, } -/// Plain text. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Text(pub String); +#[derive(Debug, Clone, PartialEq)] +pub enum TextCommand { + Text(String), + Move(Size, Size), + SetFont(usize, f32), +} /// A general distance type that can convert between units. #[derive(Debug, Copy, Clone, PartialEq)] @@ -40,170 +66,49 @@ pub struct Size { impl Size { /// Create a size from a number of points. #[inline] - pub fn from_points(points: f32) -> Size { - Size { points } - } + pub fn from_points(points: f32) -> Size { Size { points } } /// Create a size from a number of inches. #[inline] - pub fn from_inches(inches: f32) -> Size { - Size { points: 72.0 * inches } - } + pub fn from_inches(inches: f32) -> Size { Size { points: 72.0 * inches } } /// Create a size from a number of millimeters. #[inline] - pub fn from_mm(mm: f32) -> Size { - Size { points: 2.83465 * mm } - } + pub fn from_mm(mm: f32) -> Size { Size { points: 2.83465 * mm } } /// Create a size from a number of centimeters. #[inline] - pub fn from_cm(cm: f32) -> Size { - Size { points: 28.3465 * cm } - } + pub fn from_cm(cm: f32) -> Size { Size { points: 28.3465 * cm } } /// Create a size from a number of points. #[inline] - pub fn to_points(&self) -> f32 { - self.points - } + pub fn to_points(&self) -> f32 { self.points } /// Create a size from a number of inches. #[inline] - pub fn to_inches(&self) -> f32 { - self.points * 0.0138889 - } + pub fn to_inches(&self) -> f32 { self.points * 0.0138889 } /// Create a size from a number of millimeters. #[inline] - pub fn to_mm(&self) -> f32 { - self.points * 0.352778 - } + pub fn to_mm(&self) -> f32 { self.points * 0.352778 } /// Create a size from a number of centimeters. #[inline] - pub fn to_cm(&self) -> f32 { - self.points * 0.0352778 - } -} - - -/// A type that can be generated into a document. -pub trait Generate { - /// Generate a document from self. - fn generate(self) -> GenResult<Document>; -} - -impl Generate for SyntaxTree<'_> { - fn generate(self) -> GenResult<Document> { - Generator::new(self).generate() - } -} - -/// Result type used for parsing. -type GenResult<T> = std::result::Result<T, GenerationError>; - -/// A failure when generating. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct GenerationError { - /// A message describing the error. - message: String, -} - -impl fmt::Display for GenerationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "generation error: {}", self.message) - } + pub fn to_cm(&self) -> f32 { self.points * 0.0352778 } } +impl ops::Add for Size { + type Output = Size; -/// Transforms an abstract syntax tree into a document. -#[derive(Debug, Clone)] -struct Generator<'s> { - tree: SyntaxTree<'s>, -} - -impl<'s> Generator<'s> { - /// Create a new generator from a syntax tree. - fn new(tree: SyntaxTree<'s>) -> Generator<'s> { - Generator { tree } - } - - /// Generate the abstract document. - fn generate(&mut self) -> GenResult<Document> { - let mut text = String::new(); - for node in &self.tree.nodes { - match node { - Node::Space if !text.is_empty() => text.push(' '), - Node::Space | Node::Newline => (), - Node::Word(word) => text.push_str(word), - - Node::ToggleItalics | Node::ToggleBold | Node::ToggleMath => unimplemented!(), - Node::Func(_) => unimplemented!(), - - } - } - - let page = Page { - size: [Size::from_mm(210.0), Size::from_mm(297.0)], - contents: vec![ Text(text) ], - }; - - Ok(Document { - pages: vec![page], - font: "NotoSans-Regular".to_owned(), - }) - } - - /// Gives a generation error with a message. - #[inline] - fn err<R, S: Into<String>>(&self, message: S) -> GenResult<R> { - Err(GenerationError { message: message.into() }) + fn add(self, other: Size) -> Size { + Size { points: self.points + other.points } } } +impl ops::Sub for Size { + type Output = Size; -#[cfg(test)] -mod generator_tests { - use super::*; - use crate::parsing::ParseTree; - - /// Test if the source gets generated into the document. - fn test(src: &str, doc: Document) { - assert_eq!(src.parse_tree().unwrap().generate(), Ok(doc)); - } - - /// Test if generation gives this error for the source code. - fn test_err(src: &str, err: GenerationError) { - assert_eq!(src.parse_tree().unwrap().generate(), Err(err)); - } - - #[test] - fn generator_simple() { - test("This is an example of a sentence.", Document { - pages: vec![ - Page { - size: [Size::from_mm(210.0), Size::from_mm(297.0)], - contents: vec![ - Text("This is an example of a sentence.".to_owned()), - ] - } - ], - font: "NotoSans-Regular".to_owned(), - }); - } - - #[test] - fn generate_emoji() { - use crate::write::WritePdf; - let doc = Document { - pages: vec![Page { - size: [Size::from_mm(210.0), Size::from_mm(297.0)], - contents: vec![Text("🌍".to_owned())] - }], - font: "NotoEmoji-Regular".to_owned(), - }; - let mut file = std::fs::File::create("../target/typeset-doc-emoji.pdf").unwrap(); - file.write_pdf(&doc).unwrap(); + fn sub(self, other: Size) -> Size { + Size { points: self.points - other.points } } } |
