summaryrefslogtreecommitdiff
path: root/src/doc.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-03-11 17:24:00 +0100
committerLaurenz <laurmaedje@gmail.com>2019-03-11 17:24:00 +0100
commit67281c4f469716c7f2341676f2ad656d8c544ea3 (patch)
tree4a5bd6602306369db2b9e99b7cbb405f72b816d5 /src/doc.rs
parent5942c3ba2ab1cd71f86749a91bc04e45da175f96 (diff)
Redesign document representation 🧱
Diffstat (limited to 'src/doc.rs')
-rw-r--r--src/doc.rs217
1 files changed, 61 insertions, 156 deletions
diff --git a/src/doc.rs b/src/doc.rs
index d0733dfa..890da26a 100644
--- a/src/doc.rs
+++ b/src/doc.rs
@@ -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 }
}
}