Format everything with rustfmt! 💚

This commit is contained in:
Laurenz 2020-08-30 22:18:55 +02:00
parent 0d44cf5321
commit 181f756a9e
30 changed files with 326 additions and 331 deletions

View File

@ -15,14 +15,10 @@ const FONT_DIR: &str = "fonts";
const COMA: &str = include_str!("../tests/coma.typ"); const COMA: &str = include_str!("../tests/coma.typ");
fn parsing_benchmark(c: &mut Criterion) { fn parsing_benchmark(c: &mut Criterion) {
c.bench_function("parse-coma-28-lines", |b| { c.bench_function("parse-coma-28-lines", |b| b.iter(|| parse(COMA)));
b.iter(|| parse(COMA))
});
let long = COMA.repeat(100); let long = COMA.repeat(100);
c.bench_function("parse-coma-2800-lines", |b| { c.bench_function("parse-coma-2800-lines", |b| b.iter(|| parse(&long)));
b.iter(|| parse(&long))
});
} }
fn typesetting_benchmark(c: &mut Criterion) { fn typesetting_benchmark(c: &mut Criterion) {

View File

@ -30,8 +30,7 @@ fn main() {
panic!("source and destination path are the same"); panic!("source and destination path are the same");
} }
let src = read_to_string(src_path) let src = read_to_string(src_path).expect("failed to read from source file");
.expect("failed to read from source file");
let mut index = FsIndex::new(); let mut index = FsIndex::new();
index.search_dir("fonts"); index.search_dir("fonts");
@ -55,16 +54,16 @@ fn main() {
"{}: {}:{}:{} - {}:{}: {}", "{}: {}:{}:{} - {}:{}: {}",
format!("{:?}", diagnostic.v.level).to_lowercase(), format!("{:?}", diagnostic.v.level).to_lowercase(),
src_path.display(), src_path.display(),
span.start.line + 1, span.start.column + 1, span.start.line + 1,
span.end.line + 1, span.end.column + 1, span.start.column + 1,
span.end.line + 1,
span.end.column + 1,
diagnostic.v.message, diagnostic.v.message,
); );
} }
let file = File::create(&dest_path) let file = File::create(&dest_path).expect("failed to create output file");
.expect("failed to create output file");
let writer = BufWriter::new(file); let writer = BufWriter::new(file);
pdf::export(&layouts, &loader, writer) pdf::export(&layouts, &loader, writer).expect("failed to export pdf");
.expect("failed to export pdf");
} }

View File

@ -59,13 +59,12 @@ impl FromStr for RgbaColor {
let mut values: [u8; 4] = [255; 4]; let mut values: [u8; 4] = [255; 4];
for elem in if alpha { 0..4 } else { 0..3 } { for elem in if alpha { 0 .. 4 } else { 0 .. 3 } {
let item_len = if long { 2 } else { 1 }; let item_len = if long { 2 } else { 1 };
let pos = elem * item_len; let pos = elem * item_len;
let item = &hex_str[pos..(pos+item_len)]; let item = &hex_str[pos .. (pos + item_len)];
values[elem] = u8::from_str_radix(item, 16) values[elem] = u8::from_str_radix(item, 16).map_err(|_| ParseColorError)?;
.map_err(|_| ParseColorError)?;
if short { if short {
// Duplicate number for shorthand notation, i.e. `a` -> `aa` // Duplicate number for shorthand notation, i.e. `a` -> `aa`
@ -81,12 +80,14 @@ impl Debug for RgbaColor {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if f.alternate() { if f.alternate() {
write!( write!(
f, "rgba({:02}, {:02}, {:02}, {:02})", f,
"rgba({:02}, {:02}, {:02}, {:02})",
self.r, self.g, self.b, self.a, self.r, self.g, self.b, self.a,
)?; )?;
} else { } else {
write!( write!(
f, "#{:02x}{:02x}{:02x}{:02x}", f,
"#{:02x}{:02x}{:02x}{:02x}",
self.r, self.g, self.b, self.a, self.r, self.g, self.b, self.a,
)?; )?;
} }
@ -116,10 +117,7 @@ mod tests {
#[test] #[test]
fn parse_color_strings() { fn parse_color_strings() {
fn test(hex: &str, r: u8, g: u8, b: u8, a: u8) { fn test(hex: &str, r: u8, g: u8, b: u8, a: u8) {
assert_eq!( assert_eq!(RgbaColor::from_str(hex), Ok(RgbaColor::new(r, g, b, a)));
RgbaColor::from_str(hex),
Ok(RgbaColor::new(r, g, b, a)),
);
} }
test("f61243ff", 0xf6, 0x12, 0x43, 0xff); test("f61243ff", 0xf6, 0x12, 0x43, 0xff);

View File

@ -14,9 +14,7 @@ impl Scope {
// Create a new empty scope with a fallback function that is invoked when no // Create a new empty scope with a fallback function that is invoked when no
// match is found. // match is found.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self { functions: HashMap::new() }
functions: HashMap::new(),
}
} }
/// Associate the given name with the function. /// Associate the given name with the function.

View File

@ -117,7 +117,8 @@ impl<V> Table<V> {
/// Iterator over all borrowed keys and values. /// Iterator over all borrowed keys and values.
pub fn iter(&self) -> impl Iterator<Item = (BorrowedKey, &V)> { pub fn iter(&self) -> impl Iterator<Item = (BorrowedKey, &V)> {
self.nums().map(|(&k, v)| (BorrowedKey::Num(k), v)) self.nums()
.map(|(&k, v)| (BorrowedKey::Num(k), v))
.chain(self.strs().map(|(k, v)| (BorrowedKey::Str(k), v))) .chain(self.strs().map(|(k, v)| (BorrowedKey::Str(k), v)))
} }
@ -138,13 +139,17 @@ impl<V> Table<V> {
/// Move into an owned iterator over owned keys and values. /// Move into an owned iterator over owned keys and values.
pub fn into_iter(self) -> impl Iterator<Item = (OwnedKey, V)> { pub fn into_iter(self) -> impl Iterator<Item = (OwnedKey, V)> {
self.nums.into_iter().map(|(k, v)| (OwnedKey::Num(k), v)) self.nums
.into_iter()
.map(|(k, v)| (OwnedKey::Num(k), v))
.chain(self.strs.into_iter().map(|(k, v)| (OwnedKey::Str(k), v))) .chain(self.strs.into_iter().map(|(k, v)| (OwnedKey::Str(k), v)))
} }
/// Move into an owned iterator over all values in the table. /// Move into an owned iterator over all values in the table.
pub fn into_values(self) -> impl Iterator<Item = V> { pub fn into_values(self) -> impl Iterator<Item = V> {
self.nums.into_iter().map(|(_, v)| v) self.nums
.into_iter()
.map(|(_, v)| v)
.chain(self.strs.into_iter().map(|(_, v)| v)) .chain(self.strs.into_iter().map(|(_, v)| v))
} }

View File

@ -6,15 +6,15 @@ use std::rc::Rc;
use fontdock::{FontStyle, FontWeight, FontWidth}; use fontdock::{FontStyle, FontWeight, FontWidth};
use super::table::{SpannedEntry, Table};
use crate::color::RgbaColor; use crate::color::RgbaColor;
use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign}; use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign};
use crate::length::{Length, ScaleLength}; use crate::length::{Length, ScaleLength};
use crate::paper::Paper; use crate::paper::Paper;
use crate::syntax::span::{Span, Spanned}; use crate::syntax::span::{Span, Spanned};
use crate::syntax::tree::{SyntaxTree, SyntaxNode}; use crate::syntax::tree::{SyntaxNode, SyntaxTree};
use crate::syntax::Ident; use crate::syntax::Ident;
use crate::{DynFuture, Feedback, Pass}; use crate::{DynFuture, Feedback, Pass};
use super::table::{SpannedEntry, Table};
/// A computational value. /// A computational value.
#[derive(Clone)] #[derive(Clone)]
@ -78,9 +78,10 @@ impl Spanned<Value> {
for entry in table.into_values() { for entry in table.into_values() {
if let Some(last_end) = end { if let Some(last_end) = end {
let span = Span::new(last_end, entry.key.start); let span = Span::new(last_end, entry.key.start);
commands.push(Command::LayoutSyntaxTree(vec![ commands.push(Command::LayoutSyntaxTree(vec![Spanned::new(
Spanned::new(SyntaxNode::Spacing, span) SyntaxNode::Spacing,
])); span,
)]));
} }
end = Some(entry.val.span.end); end = Some(entry.val.span.end);
@ -90,14 +91,10 @@ impl Spanned<Value> {
} }
// Format with debug. // Format with debug.
val => vec![ val => vec![Command::LayoutSyntaxTree(vec![Spanned::new(
Command::LayoutSyntaxTree(vec![
Spanned::new(
SyntaxNode::Text(format!("{:?}", val)), SyntaxNode::Text(format!("{:?}", val)),
self.span, self.span,
) )])],
])
],
} }
} }
} }
@ -149,9 +146,8 @@ impl PartialEq for Value {
/// layouting engine to do what the function pleases. /// layouting engine to do what the function pleases.
/// ///
/// The dynamic function object is wrapped in an `Rc` to keep `Value` clonable. /// The dynamic function object is wrapped in an `Rc` to keep `Value` clonable.
pub type FuncValue = Rc< pub type FuncValue =
dyn Fn(Span, TableValue, LayoutContext<'_>) -> DynFuture<Pass<Value>> Rc<dyn Fn(Span, TableValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>>;
>;
/// A table of values. /// A table of values.
/// ///
@ -500,7 +496,10 @@ mod tests {
table.expect::<String>("", Span::ZERO, &mut f), table.expect::<String>("", Span::ZERO, &mut f),
Some("hi".to_string()) Some("hi".to_string())
); );
assert_eq!(f.diagnostics, [error!(Span::ZERO, "expected string, found bool")]); assert_eq!(f.diagnostics, [error!(
Span::ZERO,
"expected string, found bool"
)]);
assert_eq!(table.len(), 1); assert_eq!(table.len(), 1);
} }
@ -512,7 +511,10 @@ mod tests {
table.insert("hi", entry(Value::Bool(true))); table.insert("hi", entry(Value::Bool(true)));
assert_eq!(table.take::<bool>(), Some(false)); assert_eq!(table.take::<bool>(), Some(false));
assert_eq!(table.take_key::<f64>("hi", &mut f), None); assert_eq!(table.take_key::<f64>("hi", &mut f), None);
assert_eq!(f.diagnostics, [error!(Span::ZERO, "expected number, found bool")]); assert_eq!(f.diagnostics, [error!(
Span::ZERO,
"expected number, found bool"
)]);
assert!(table.is_empty()); assert!(table.is_empty());
} }
@ -522,10 +524,10 @@ mod tests {
table.insert(1, entry(Value::Bool(false))); table.insert(1, entry(Value::Bool(false)));
table.insert(3, entry(Value::Number(0.0))); table.insert(3, entry(Value::Number(0.0)));
table.insert(7, entry(Value::Bool(true))); table.insert(7, entry(Value::Bool(true)));
assert_eq!( assert_eq!(table.take_all_num::<bool>().collect::<Vec<_>>(), [
table.take_all_num::<bool>().collect::<Vec<_>>(), (1, false),
[(1, false), (7, true)], (7, true)
); ],);
assert_eq!(table.len(), 1); assert_eq!(table.len(), 1);
assert_eq!(table[3].val.v, Value::Number(0.0)); assert_eq!(table[3].val.v, Value::Number(0.0));
} }

View File

@ -7,8 +7,8 @@ use fontdock::FaceId;
use tide::content::Content; use tide::content::Content;
use tide::doc::{Catalog, Page, PageTree, Resource, Text}; use tide::doc::{Catalog, Page, PageTree, Resource, Text};
use tide::font::{ use tide::font::{
CIDFont, CIDFontType, CIDSystemInfo, CMap, CMapEncoding, FontDescriptor, CIDFont, CIDFontType, CIDSystemInfo, CMap, CMapEncoding, FontDescriptor, FontFlags,
FontFlags, FontStream, GlyphUnit, Type0Font, WidthRecord, FontStream, GlyphUnit, Type0Font, WidthRecord,
}; };
use tide::{PdfWriter, Rect, Ref, Trailer, Version}; use tide::{PdfWriter, Rect, Ref, Trailer, Version};
use ttf_parser::{name_id, GlyphId}; use ttf_parser::{name_id, GlyphId};
@ -89,20 +89,18 @@ impl<'a, W: Write> PdfExporter<'a, W> {
fn write_preface(&mut self) -> io::Result<()> { fn write_preface(&mut self) -> io::Result<()> {
// The document catalog. // 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. // The font resources.
let start = self.offsets.fonts.0; let start = self.offsets.fonts.0;
let fonts = (0..self.to_pdf.len() as u32).map(|i| { let fonts = (0 .. self.to_pdf.len() as u32)
Resource::Font(i + 1, start + (NUM_OBJECTS_PER_FONT * i)) .map(|i| Resource::Font(i + 1, start + (NUM_OBJECTS_PER_FONT * i)));
});
// The root page tree. // The root page tree.
self.writer.write_obj( self.writer.write_obj(
self.offsets.page_tree, self.offsets.page_tree,
PageTree::new() PageTree::new().kids(ids(self.offsets.pages)).resources(fonts),
.kids(ids(self.offsets.pages))
.resources(fonts),
)?; )?;
// The page objects (non-root nodes in the page tree). // The page objects (non-root nodes in the page tree).
@ -119,9 +117,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
self.writer.write_obj( self.writer.write_obj(
page_id, page_id,
Page::new(self.offsets.page_tree) Page::new(self.offsets.page_tree).media_box(rect).content(content_id),
.media_box(rect)
.content(content_id),
)?; )?;
} }
@ -151,7 +147,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
size = shaped.size; size = shaped.size;
text.tf( text.tf(
self.to_pdf[&shaped.face] as u32 + 1, self.to_pdf[&shaped.face] as u32 + 1,
Length::raw(size).as_pt() as f32 Length::raw(size).as_pt() as f32,
); );
} }
@ -178,8 +174,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
let name = face let name = face
.names() .names()
.find(|entry| { .find(|entry| {
entry.name_id() == name_id::POST_SCRIPT_NAME entry.name_id() == name_id::POST_SCRIPT_NAME && entry.is_unicode()
&& entry.is_unicode()
}) })
.map(|entry| entry.to_string()) .map(|entry| entry.to_string())
.flatten() .flatten()
@ -190,9 +185,8 @@ impl<'a, W: Write> PdfExporter<'a, W> {
let units_per_em = face.units_per_em().unwrap_or(1000) as f64; let units_per_em = face.units_per_em().unwrap_or(1000) as f64;
let ratio = 1.0 / units_per_em; let ratio = 1.0 / units_per_em;
let to_glyph_unit = |font_unit: f64| { let to_glyph_unit =
(1000.0 * ratio * font_unit).round() as GlyphUnit |font_unit: f64| (1000.0 * ratio * font_unit).round() as GlyphUnit;
};
let global_bbox = face.global_bounding_box(); let global_bbox = face.global_bounding_box();
let bbox = Rect::new( let bbox = Rect::new(
@ -218,7 +212,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
flags.insert(FontFlags::SMALL_CAP); flags.insert(FontFlags::SMALL_CAP);
let num_glyphs = face.number_of_glyphs(); let num_glyphs = face.number_of_glyphs();
let widths: Vec<_> = (0..num_glyphs) let widths: Vec<_> = (0 .. num_glyphs)
.map(|g| face.glyph_hor_advance(GlyphId(g)).unwrap_or(0)) .map(|g| face.glyph_hor_advance(GlyphId(g)).unwrap_or(0))
.map(|w| to_glyph_unit(w as f64)) .map(|w| to_glyph_unit(w as f64))
.collect(); .collect();
@ -258,23 +252,21 @@ impl<'a, W: Write> PdfExporter<'a, W> {
)?; )?;
// Write the font descriptor (contains metrics about the font). // Write the font descriptor (contains metrics about the font).
self.writer.write_obj(id + 2, self.writer.write_obj(
id + 2,
FontDescriptor::new(base_font, flags, italic_angle) FontDescriptor::new(base_font, flags, italic_angle)
.font_bbox(bbox) .font_bbox(bbox)
.ascent(to_glyph_unit(ascender as f64)) .ascent(to_glyph_unit(ascender as f64))
.descent(to_glyph_unit(descender as f64)) .descent(to_glyph_unit(descender as f64))
.cap_height(to_glyph_unit(cap_height as f64)) .cap_height(to_glyph_unit(cap_height as f64))
.stem_v(stem_v as GlyphUnit) .stem_v(stem_v as GlyphUnit)
.font_file_2(id + 4) .font_file_2(id + 4),
)?; )?;
// Write the CMap, which maps glyph ids back to unicode codepoints // Write the CMap, which maps glyph ids back to unicode codepoints
// to enable copying out of the PDF. // to enable copying out of the PDF.
self.writer.write_obj(id + 3, &CMap::new( self.writer
"Custom", .write_obj(id + 3, &CMap::new("Custom", system_info, mapping))?;
system_info,
mapping,
))?;
// Write the face's bytes. // Write the face's bytes.
self.writer.write_obj(id + 4, &FontStream::new(face.data()))?; self.writer.write_obj(id + 4, &FontStream::new(face.data()))?;
@ -328,5 +320,5 @@ fn calculate_offsets(layout_count: usize, font_count: usize) -> Offsets {
} }
fn ids((start, end): (Ref, Ref)) -> impl Iterator<Item = Ref> { fn ids((start, end): (Ref, Ref)) -> impl Iterator<Item = Ref> {
start..=end start ..= end
} }

View File

@ -30,9 +30,8 @@ impl FaceFromVec for OwnedFace {
fn from_vec(vec: Vec<u8>, i: u32) -> Option<Self> { fn from_vec(vec: Vec<u8>, i: u32) -> Option<Self> {
// The vec's location is stable in memory since we don't touch it and // The vec's location is stable in memory since we don't touch it and
// it can't be touched from outside this type. // it can't be touched from outside this type.
let slice: &'static [u8] = unsafe { let slice: &'static [u8] =
std::slice::from_raw_parts(vec.as_ptr(), vec.len()) unsafe { std::slice::from_raw_parts(vec.as_ptr(), vec.len()) };
};
Some(Self { Some(Self {
data: vec, data: vec,

View File

@ -21,12 +21,18 @@ impl<T: Clone> Value2<T> {
} }
/// Create a new 2D-value with `x` set to a value and `y` to default. /// Create a new 2D-value with `x` set to a value and `y` to default.
pub fn with_x(x: T) -> Self where T: Default { pub fn with_x(x: T) -> Self
where
T: Default,
{
Self { x, y: T::default() } Self { x, y: T::default() }
} }
/// Create a new 2D-value with `y` set to a value and `x` to default. /// Create a new 2D-value with `y` set to a value and `x` to default.
pub fn with_y(y: T) -> Self where T: Default { pub fn with_y(y: T) -> Self
where
T: Default,
{
Self { x: T::default(), y } Self { x: T::default(), y }
} }
@ -53,22 +59,38 @@ impl<T: Clone> Value2<T> {
/// Return the primary value of this specialized 2D-value. /// Return the primary value of this specialized 2D-value.
pub fn primary(self, axes: LayoutAxes) -> T { pub fn primary(self, axes: LayoutAxes) -> T {
if axes.primary.axis() == Horizontal { self.x } else { self.y } if axes.primary.axis() == Horizontal {
self.x
} else {
self.y
}
} }
/// Borrow the primary value of this specialized 2D-value mutably. /// Borrow the primary value of this specialized 2D-value mutably.
pub fn primary_mut(&mut self, axes: LayoutAxes) -> &mut T { pub fn primary_mut(&mut self, axes: LayoutAxes) -> &mut T {
if axes.primary.axis() == Horizontal { &mut self.x } else { &mut self.y } if axes.primary.axis() == Horizontal {
&mut self.x
} else {
&mut self.y
}
} }
/// Return the secondary value of this specialized 2D-value. /// Return the secondary value of this specialized 2D-value.
pub fn secondary(self, axes: LayoutAxes) -> T { pub fn secondary(self, axes: LayoutAxes) -> T {
if axes.primary.axis() == Horizontal { self.y } else { self.x } if axes.primary.axis() == Horizontal {
self.y
} else {
self.x
}
} }
/// Borrow the secondary value of this specialized 2D-value mutably. /// Borrow the secondary value of this specialized 2D-value mutably.
pub fn secondary_mut(&mut self, axes: LayoutAxes) -> &mut T { pub fn secondary_mut(&mut self, axes: LayoutAxes) -> &mut T {
if axes.primary.axis() == Horizontal { &mut self.y } else { &mut self.x } if axes.primary.axis() == Horizontal {
&mut self.y
} else {
&mut self.x
}
} }
/// Returns the generalized version of a `Size2D` dependent on the layouting /// Returns the generalized version of a `Size2D` dependent on the layouting
@ -98,10 +120,7 @@ impl<T: Clone> Value2<T> {
impl<T: Debug> Debug for Value2<T> { impl<T: Debug> Debug for Value2<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_list() f.debug_list().entry(&self.x).entry(&self.y).finish()
.entry(&self.x)
.entry(&self.y)
.finish()
} }
} }
@ -159,10 +178,7 @@ impl Neg for Size {
type Output = Size; type Output = Size;
fn neg(self) -> Size { fn neg(self) -> Size {
Size { Size { x: -self.x, y: -self.y }
x: -self.x,
y: -self.y,
}
} }
} }

View File

@ -246,9 +246,7 @@ impl LineLayouter {
for (offset, layout) in layouts { for (offset, layout) in layouts {
let x = match self.ctx.axes.primary.is_positive() { let x = match self.ctx.axes.primary.is_positive() {
true => offset, true => offset,
false => self.run.size.x false => self.run.size.x - offset - layout.size.primary(self.ctx.axes),
- offset
- layout.size.primary(self.ctx.axes),
}; };
let pos = Size::with_x(x); let pos = Size::with_x(x);
@ -258,7 +256,7 @@ impl LineLayouter {
self.stack.add(BoxLayout { self.stack.add(BoxLayout {
size: self.run.size.specialized(self.ctx.axes), size: self.run.size.specialized(self.ctx.axes),
align: self.run.align.unwrap_or(LayoutAlign::new(Start, Start)), align: self.run.align.unwrap_or(LayoutAlign::new(Start, Start)),
elements elements,
}); });
self.run = LineRun::new(); self.run = LineRun::new();

View File

@ -10,7 +10,7 @@ mod tree;
/// Basic types used across the layouting engine. /// Basic types used across the layouting engine.
pub mod prelude { pub mod prelude {
pub use super::primitive::*; pub use super::primitive::*;
pub use super::{BoxLayout, layout, LayoutContext, LayoutSpace, MultiLayout}; pub use super::{layout, BoxLayout, LayoutContext, LayoutSpace, MultiLayout};
pub use Dir::*; pub use Dir::*;
pub use GenAlign::*; pub use GenAlign::*;
pub use GenAxis::*; pub use GenAxis::*;

View File

@ -140,7 +140,11 @@ pub enum SpecAxis {
impl SpecAxis { impl SpecAxis {
/// The generic version of this axis in the given system of axes. /// The generic version of this axis in the given system of axes.
pub fn to_generic(self, axes: LayoutAxes) -> GenAxis { pub fn to_generic(self, axes: LayoutAxes) -> GenAxis {
if self == axes.primary.axis() { Primary } else { Secondary } if self == axes.primary.axis() {
Primary
} else {
Secondary
}
} }
} }
@ -240,7 +244,11 @@ impl SpecAlign {
pub fn to_generic(self, axes: LayoutAxes) -> GenAlign { pub fn to_generic(self, axes: LayoutAxes) -> GenAlign {
let get = |spec: SpecAxis, align: GenAlign| { let get = |spec: SpecAxis, align: GenAlign| {
let axis = spec.to_generic(axes); let axis = spec.to_generic(axes);
if axes.get(axis).is_positive() { align } else { align.inv() } if axes.get(axis).is_positive() {
align
} else {
align.inv()
}
}; };
match self { match self {

View File

@ -19,8 +19,8 @@
//! The position of the first aligned box thus depends on the length of the //! The position of the first aligned box thus depends on the length of the
//! sentence in the second box. //! sentence in the second box.
use crate::geom::Value4;
use super::*; use super::*;
use crate::geom::Value4;
/// Performs the stack layouting. /// Performs the stack layouting.
pub struct StackLayouter { pub struct StackLayouter {
@ -130,14 +130,11 @@ impl StackLayouter {
let size = Size::with_y(spacing); let size = Size::with_y(spacing);
self.update_metrics(size); self.update_metrics(size);
self.space.layouts.push(( self.space.layouts.push((self.ctx.axes, BoxLayout {
self.ctx.axes,
BoxLayout {
size: size.specialized(self.ctx.axes), size: size.specialized(self.ctx.axes),
align: LayoutAlign::new(Start, Start), align: LayoutAlign::new(Start, Start),
elements: LayoutElements::new(), elements: LayoutElements::new(),
} }));
));
self.space.last_spacing = LastSpacing::Hard; self.space.last_spacing = LastSpacing::Hard;
} }
@ -179,8 +176,7 @@ impl StackLayouter {
fn update_rulers(&mut self, align: LayoutAlign) -> bool { fn update_rulers(&mut self, align: LayoutAlign) -> bool {
let allowed = self.is_fitting_alignment(align); let allowed = self.is_fitting_alignment(align);
if allowed { if allowed {
*self.space.rulers.get_mut(self.ctx.axes.secondary, Start) = *self.space.rulers.get_mut(self.ctx.axes.secondary, Start) = align.secondary;
align.secondary;
} }
allowed allowed
} }
@ -226,7 +222,7 @@ impl StackLayouter {
/// if no space is capable of that. /// if no space is capable of that.
pub fn skip_to_fitting_space(&mut self, size: Size) { pub fn skip_to_fitting_space(&mut self, size: Size) {
let start = self.next_space(); let start = self.next_space();
for (index, space) in self.ctx.spaces[start..].iter().enumerate() { for (index, space) in self.ctx.spaces[start ..].iter().enumerate() {
if space.usable().fits(size) { if space.usable().fits(size) {
self.finish_space(true); self.finish_space(true);
self.start_space(start + index, true); self.start_space(start + index, true);
@ -246,7 +242,7 @@ impl StackLayouter {
expansion: LayoutExpansion::new(false, false), expansion: LayoutExpansion::new(false, false),
}]; }];
for space in &self.ctx.spaces[self.next_space()..] { for space in &self.ctx.spaces[self.next_space() ..] {
spaces.push(space.inner()); spaces.push(space.inner());
} }
@ -288,8 +284,12 @@ impl StackLayouter {
// expand if necessary.) // expand if necessary.)
let usable = space.usable(); let usable = space.usable();
if space.expansion.horizontal { self.space.size.x = usable.x; } if space.expansion.horizontal {
if space.expansion.vertical { self.space.size.y = usable.y; } self.space.size.x = usable.x;
}
if space.expansion.vertical {
self.space.size.y = usable.y;
}
let size = self.space.size.padded(space.padding); let size = self.space.size.padded(space.padding);
@ -347,8 +347,7 @@ impl StackLayouter {
// We reduce the bounding box of this layout at it's end by the // We reduce the bounding box of this layout at it's end by the
// accumulated secondary extent of all layouts we have seen so far, // accumulated secondary extent of all layouts we have seen so far,
// which are the layouts after this one since we iterate reversed. // which are the layouts after this one since we iterate reversed.
*bound.get_mut(axes.secondary, End) -= *bound.get_mut(axes.secondary, End) -= axes.secondary.factor() * extent.y;
axes.secondary.factor() * extent.y;
// Then, we add this layout's secondary extent to the accumulator. // Then, we add this layout's secondary extent to the accumulator.
let size = layout.size.generalized(*axes); let size = layout.size.generalized(*axes);
@ -369,8 +368,7 @@ impl StackLayouter {
// The space in which this layout is aligned is given by the // The space in which this layout is aligned is given by the
// distances between the borders of it's bounding box. // distances between the borders of it's bounding box.
let usable = let usable = Size::new(bound.right - bound.left, bound.bottom - bound.top)
Size::new(bound.right - bound.left, bound.bottom - bound.top)
.generalized(axes); .generalized(axes);
let local = usable.anchor(align, axes) - size.anchor(align, axes); let local = usable.anchor(align, axes) - size.anchor(align, axes);
@ -379,11 +377,7 @@ impl StackLayouter {
elements.extend_offset(pos, layout.elements); elements.extend_offset(pos, layout.elements);
} }
self.layouts.push(BoxLayout { self.layouts.push(BoxLayout { size, align: self.ctx.align, elements });
size,
align: self.ctx.align,
elements,
});
// ------------------------------------------------------------------ // // ------------------------------------------------------------------ //
// Step 5: Start the next space. // Step 5: Start the next space.

View File

@ -7,11 +7,11 @@
use fontdock::{FaceId, FaceQuery, FontStyle}; use fontdock::{FaceId, FaceQuery, FontStyle};
use ttf_parser::GlyphId; use ttf_parser::GlyphId;
use super::elements::{LayoutElement, Shaped};
use super::*;
use crate::font::SharedFontLoader; use crate::font::SharedFontLoader;
use crate::geom::Size; use crate::geom::Size;
use crate::style::TextStyle; use crate::style::TextStyle;
use super::elements::{LayoutElement, Shaped};
use super::*;
/// Layouts text into a box. /// Layouts text into a box.
pub async fn layout_text(text: &str, ctx: TextContext<'_>) -> BoxLayout { pub async fn layout_text(text: &str, ctx: TextContext<'_>) -> BoxLayout {

View File

@ -1,19 +1,16 @@
//! Layouting of syntax trees. //! Layouting of syntax trees.
use crate::style::LayoutStyle;
use crate::syntax::decoration::Decoration;
use crate::syntax::span::{Span, Spanned};
use crate::syntax::tree::{CallExpr, SyntaxNode, SyntaxTree, Code};
use crate::{DynFuture, Feedback, Pass};
use super::line::{LineContext, LineLayouter}; use super::line::{LineContext, LineLayouter};
use super::text::{layout_text, TextContext}; use super::text::{layout_text, TextContext};
use super::*; use super::*;
use crate::style::LayoutStyle;
use crate::syntax::decoration::Decoration;
use crate::syntax::span::{Span, Spanned};
use crate::syntax::tree::{CallExpr, Code, SyntaxNode, SyntaxTree};
use crate::{DynFuture, Feedback, Pass};
/// Layout a syntax tree into a collection of boxes. /// Layout a syntax tree into a collection of boxes.
pub async fn layout_tree( pub async fn layout_tree(tree: &SyntaxTree, ctx: LayoutContext<'_>) -> Pass<MultiLayout> {
tree: &SyntaxTree,
ctx: LayoutContext<'_>,
) -> Pass<MultiLayout> {
let mut layouter = TreeLayouter::new(ctx); let mut layouter = TreeLayouter::new(ctx);
layouter.layout_tree(tree).await; layouter.layout_tree(tree).await;
layouter.finish() layouter.finish()
@ -75,8 +72,12 @@ impl<'a> TreeLayouter<'a> {
} }
SyntaxNode::Text(text) => { SyntaxNode::Text(text) => {
if self.style.text.italic { decorate(self, Decoration::Italic); } if self.style.text.italic {
if self.style.text.bolder { decorate(self, Decoration::Bold); } decorate(self, Decoration::Italic);
}
if self.style.text.bolder {
decorate(self, Decoration::Bold);
}
self.layout_text(text).await; self.layout_text(text).await;
} }
@ -90,10 +91,8 @@ impl<'a> TreeLayouter<'a> {
} }
fn layout_space(&mut self) { fn layout_space(&mut self) {
self.layouter.add_primary_spacing( self.layouter
self.style.text.word_spacing(), .add_primary_spacing(self.style.text.word_spacing(), SpacingKind::WORD);
SpacingKind::WORD,
);
} }
fn layout_parbreak(&mut self) { fn layout_parbreak(&mut self) {
@ -105,24 +104,20 @@ impl<'a> TreeLayouter<'a> {
async fn layout_text(&mut self, text: &str) { async fn layout_text(&mut self, text: &str) {
self.layouter.add( self.layouter.add(
layout_text( layout_text(text, TextContext {
text,
TextContext {
loader: &self.ctx.loader, loader: &self.ctx.loader,
style: &self.style.text, style: &self.style.text,
dir: self.ctx.axes.primary, dir: self.ctx.axes.primary,
align: self.ctx.align, align: self.ctx.align,
} })
).await .await,
); );
} }
async fn layout_raw(&mut self, lines: &[String]) { async fn layout_raw(&mut self, lines: &[String]) {
// TODO: Make this more efficient. // TODO: Make this more efficient.
let fallback = self.style.text.fallback.clone(); let fallback = self.style.text.fallback.clone();
self.style.text.fallback self.style.text.fallback.list_mut().insert(0, "monospace".to_string());
.list_mut()
.insert(0, "monospace".to_string());
self.style.text.fallback.flatten(); self.style.text.fallback.flatten();
let mut first = true; let mut first = true;
@ -176,7 +171,7 @@ impl<'a> TreeLayouter<'a> {
AddSpacing(space, kind, axis) => match axis { AddSpacing(space, kind, axis) => match axis {
Primary => self.layouter.add_primary_spacing(space, kind), Primary => self.layouter.add_primary_spacing(space, kind),
Secondary => self.layouter.add_secondary_spacing(space, kind), Secondary => self.layouter.add_secondary_spacing(space, kind),
} },
BreakLine => self.layouter.finish_line(), BreakLine => self.layouter.finish_line(),
BreakPage => { BreakPage => {
@ -203,13 +198,14 @@ impl<'a> TreeLayouter<'a> {
// new page style and update it within the layouter. // new page style and update it within the layouter.
let margins = style.margins(); let margins = style.margins();
self.ctx.base = style.size.unpadded(margins); self.ctx.base = style.size.unpadded(margins);
self.layouter.set_spaces(vec![ self.layouter.set_spaces(
LayoutSpace { vec![LayoutSpace {
size: style.size, size: style.size,
padding: margins, padding: margins,
expansion: LayoutExpansion::new(true, true), expansion: LayoutExpansion::new(true, true),
} }],
], true); true,
);
} else { } else {
error!( error!(
@self.feedback, span, @self.feedback, span,

View File

@ -150,7 +150,7 @@ impl FromStr for Length {
// have valid ASCII chars as subbytes. // have valid ASCII chars as subbytes.
let split = len - 2; let split = len - 2;
let bytes = src.as_bytes(); let bytes = src.as_bytes();
let unit = match &bytes[split..] { let unit = match &bytes[split ..] {
b"pt" => Unit::Pt, b"pt" => Unit::Pt,
b"mm" => Unit::Mm, b"mm" => Unit::Mm,
b"cm" => Unit::Cm, b"cm" => Unit::Cm,
@ -158,7 +158,7 @@ impl FromStr for Length {
_ => return Err(ParseLengthError), _ => return Err(ParseLengthError),
}; };
src[..split] src[.. split]
.parse::<f64>() .parse::<f64>()
.map(|val| Self::new(val, unit)) .map(|val| Self::new(val, unit))
.map_err(|_| ParseLengthError) .map_err(|_| ParseLengthError)

View File

@ -95,9 +95,7 @@ impl Typesetter {
use crate::layout::prelude::*; use crate::layout::prelude::*;
let margins = self.style.page.margins(); let margins = self.style.page.margins();
layout( layout(&tree, LayoutContext {
&tree,
LayoutContext {
loader: &self.loader, loader: &self.loader,
scope: &self.std, scope: &self.std,
style: &self.style, style: &self.style,
@ -111,8 +109,8 @@ impl Typesetter {
axes: LayoutAxes::new(LTR, TTB), axes: LayoutAxes::new(LTR, TTB),
align: LayoutAlign::new(Start, Start), align: LayoutAlign::new(Start, Start),
root: true, root: true,
}, })
).await .await
} }
/// Process source code directly into a collection of layouts. /// Process source code directly into a collection of layouts.
@ -177,10 +175,7 @@ pub struct Feedback {
impl Feedback { impl Feedback {
/// Create a new feedback instance without errors and decos. /// Create a new feedback instance without errors and decos.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self { diagnostics: vec![], decorations: vec![] }
diagnostics: vec![],
decorations: vec![],
}
} }
/// Merged two feedbacks into one. /// Merged two feedbacks into one.

View File

@ -1,12 +1,16 @@
use crate::length::ScaleLength;
use super::*; use super::*;
use crate::length::ScaleLength;
/// `box`: Layouts its contents into a box. /// `box`: Layouts its contents into a box.
/// ///
/// # Keyword arguments /// # Keyword arguments
/// - `width`: The width of the box (length of relative to parent's width). /// - `width`: The width of the box (length of relative to parent's width).
/// - `height`: The height of the box (length of relative to parent's height). /// - `height`: The height of the box (length of relative to parent's height).
pub async fn boxed(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> { pub async fn boxed(
_: Span,
mut args: TableValue,
mut ctx: LayoutContext<'_>,
) -> Pass<Value> {
let mut f = Feedback::new(); let mut f = Feedback::new();
let content = args.take::<SyntaxTree>().unwrap_or(SyntaxTree::new()); let content = args.take::<SyntaxTree>().unwrap_or(SyntaxTree::new());

View File

@ -1,5 +1,5 @@
use crate::color::RgbaColor;
use super::*; use super::*;
use crate::color::RgbaColor;
/// `rgb`: Create an RGB(A) color. /// `rgb`: Create an RGB(A) color.
pub async fn rgb(span: Span, mut args: TableValue, _: LayoutContext<'_>) -> Pass<Value> { pub async fn rgb(span: Span, mut args: TableValue, _: LayoutContext<'_>) -> Pass<Value> {
@ -11,20 +11,17 @@ pub async fn rgb(span: Span, mut args: TableValue, _: LayoutContext<'_>) -> Pass
let a = args.take::<Spanned<f64>>(); let a = args.take::<Spanned<f64>>();
let mut clamp = |component: Option<Spanned<f64>>, default| { let mut clamp = |component: Option<Spanned<f64>>, default| {
component.map(|c| { component
.map(|c| {
if c.v < 0.0 || c.v > 255.0 { if c.v < 0.0 || c.v > 255.0 {
error!(@f, c.span, "should be between 0 and 255") error!(@f, c.span, "should be between 0 and 255")
} }
c.v.min(255.0).max(0.0).round() as u8 c.v.min(255.0).max(0.0).round() as u8
}).unwrap_or(default) })
.unwrap_or(default)
}; };
let color = RgbaColor::new( let color = RgbaColor::new(clamp(r, 0), clamp(g, 0), clamp(b, 0), clamp(a, 255));
clamp(r, 0),
clamp(g, 0),
clamp(b, 0),
clamp(a, 255),
);
args.unexpected(&mut f); args.unexpected(&mut f);
Pass::new(Value::Color(color), f) Pass::new(Value::Color(color), f)

View File

@ -1,7 +1,7 @@
use fontdock::{FontStyle, FontWeight, FontWidth}; use fontdock::{FontStyle, FontWeight, FontWidth};
use crate::length::ScaleLength;
use super::*; use super::*;
use crate::length::ScaleLength;
/// `font`: Configure the font. /// `font`: Configure the font.
/// ///
@ -35,7 +35,8 @@ pub async fn font(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass
} }
} }
let list: Vec<_> = args.take_all_num_vals::<StringLike>() let list: Vec<_> = args
.take_all_num_vals::<StringLike>()
.map(|s| s.to_lowercase()) .map(|s| s.to_lowercase())
.collect(); .collect();
@ -57,7 +58,8 @@ pub async fn font(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass
} }
for (class, mut table) in args.take_all_str::<TableValue>() { for (class, mut table) in args.take_all_str::<TableValue>() {
let fallback = table.take_all_num_vals::<StringLike>() let fallback = table
.take_all_num_vals::<StringLike>()
.map(|s| s.to_lowercase()) .map(|s| s.to_lowercase())
.collect(); .collect();

View File

@ -1,6 +1,6 @@
use super::*;
use crate::length::{Length, ScaleLength}; use crate::length::{Length, ScaleLength};
use crate::paper::{Paper, PaperClass}; use crate::paper::{Paper, PaperClass};
use super::*;
/// `page`: Configure pages. /// `page`: Configure pages.
/// ///

View File

@ -1,6 +1,6 @@
use super::*;
use crate::layout::SpacingKind; use crate::layout::SpacingKind;
use crate::length::ScaleLength; use crate::length::ScaleLength;
use super::*;
/// `h`: Add horizontal spacing. /// `h`: Add horizontal spacing.
/// ///

View File

@ -39,12 +39,14 @@ pub enum PaperClass {
impl PaperClass { impl PaperClass {
/// The default margins for this page class. /// The default margins for this page class.
pub fn default_margins(self) -> Value4<ScaleLength> { pub fn default_margins(self) -> Value4<ScaleLength> {
let values = |l, t, r, b| Value4::new( let values = |l, t, r, b| {
Value4::new(
ScaleLength::Scaled(l), ScaleLength::Scaled(l),
ScaleLength::Scaled(t), ScaleLength::Scaled(t),
ScaleLength::Scaled(r), ScaleLength::Scaled(r),
ScaleLength::Scaled(b), ScaleLength::Scaled(b),
); )
};
match self { match self {
Self::Custom => values(0.1190, 0.0842, 0.1190, 0.0842), Self::Custom => values(0.1190, 0.0842, 0.1190, 0.0842),

View File

@ -1,12 +1,12 @@
//! A prelude for building custom functions. //! A prelude for building custom functions.
pub use super::*;
pub use crate::compute::value::*; pub use crate::compute::value::*;
pub use crate::layout::prelude::*; pub use crate::layout::prelude::*;
pub use crate::layout::Commands;
pub use crate::layout::Command::{self, *}; pub use crate::layout::Command::{self, *};
pub use crate::layout::Commands;
pub use crate::style::*; pub use crate::style::*;
pub use crate::syntax::parsing::parse; pub use crate::syntax::parsing::parse;
pub use crate::syntax::span::{Pos, Span, SpanVec, Spanned}; pub use crate::syntax::span::{Pos, Span, SpanVec, Spanned};
pub use crate::syntax::tree::*; pub use crate::syntax::tree::*;
pub use crate::{Pass, Feedback}; pub use crate::{Feedback, Pass};
pub use super::*;

View File

@ -1,8 +1,6 @@
//! Styles for text and pages. //! Styles for text and pages.
use fontdock::{ use fontdock::{fallback, FallbackTree, FontStyle, FontVariant, FontWeight, FontWidth};
fallback, FallbackTree, FontStyle, FontVariant, FontWeight, FontWidth,
};
use crate::geom::{Margins, Size, Value4}; use crate::geom::{Margins, Size, Value4};
use crate::length::{Length, ScaleLength}; use crate::length::{Length, ScaleLength};

View File

@ -37,9 +37,9 @@ impl Debug for Ident {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::fmt::Debug;
use crate::prelude::*;
use super::span; use super::span;
use crate::prelude::*;
use std::fmt::Debug;
/// Assert that expected and found are equal, printing both and panicking /// Assert that expected and found are equal, printing both and panicking
/// and the source of their test case if they aren't. /// and the source of their test case if they aren't.

View File

@ -2,16 +2,14 @@
use std::str::FromStr; use std::str::FromStr;
use crate::{Feedback, Pass};
use crate::color::RgbaColor;
use crate::compute::table::SpannedEntry;
use super::decoration::Decoration; use super::decoration::Decoration;
use super::span::{Pos, Span, Spanned}; use super::span::{Pos, Span, Spanned};
use super::tokens::{is_newline_char, Token, TokenMode, Tokens}; use super::tokens::{is_newline_char, Token, TokenMode, Tokens};
use super::tree::{ use super::tree::{CallExpr, Code, Expr, SyntaxNode, SyntaxTree, TableExpr};
CallExpr, Expr, SyntaxNode, SyntaxTree, TableExpr, Code,
};
use super::Ident; use super::Ident;
use crate::color::RgbaColor;
use crate::compute::table::SpannedEntry;
use crate::{Feedback, Pass};
/// Parse a string of source code. /// Parse a string of source code.
pub fn parse(src: &str) -> Pass<SyntaxTree> { pub fn parse(src: &str) -> Pass<SyntaxTree> {
@ -106,9 +104,7 @@ impl Parser<'_> {
self.with_span(SyntaxNode::Code(Code { lang, lines, block })) self.with_span(SyntaxNode::Code(Code { lang, lines, block }))
} }
Token::Text(text) => { Token::Text(text) => self.with_span(SyntaxNode::Text(text.to_string())),
self.with_span(SyntaxNode::Text(text.to_string()))
}
Token::UnicodeEscape { sequence, terminated } => { Token::UnicodeEscape { sequence, terminated } => {
if !terminated { if !terminated {
@ -222,7 +218,10 @@ impl Parser<'_> {
let mut table = TableExpr::new(); let mut table = TableExpr::new();
let mut comma_and_keyless = true; let mut comma_and_keyless = true;
while { self.skip_white(); !self.eof() } { while {
self.skip_white();
!self.eof()
} {
let (key, val) = if let Some(ident) = self.parse_ident() { let (key, val) = if let Some(ident) = self.parse_ident() {
self.skip_white(); self.skip_white();
@ -243,7 +242,7 @@ impl Parser<'_> {
(None, call.map(Expr::Call)) (None, call.map(Expr::Call))
} }
_ => (None, ident.map(Expr::Ident)) _ => (None, ident.map(Expr::Ident)),
} }
} else if let Some(value) = self.parse_expr() { } else if let Some(value) = self.parse_expr() {
(None, value) (None, value)
@ -256,13 +255,17 @@ impl Parser<'_> {
if let Some(key) = key { if let Some(key) = key {
comma_and_keyless = false; comma_and_keyless = false;
table.insert(key.v.0, SpannedEntry::new(key.span, val)); table.insert(key.v.0, SpannedEntry::new(key.span, val));
self.feedback.decorations self.feedback
.decorations
.push(Spanned::new(Decoration::TableKey, key.span)); .push(Spanned::new(Decoration::TableKey, key.span));
} else { } else {
table.push(SpannedEntry::val(val)); table.push(SpannedEntry::val(val));
} }
if { self.skip_white(); self.eof() } { if {
self.skip_white();
self.eof()
} {
break; break;
} }
@ -389,9 +392,7 @@ impl Parser<'_> {
let span = self.end_group(); let span = self.end_group();
let expr = if coercable { let expr = if coercable {
table.into_values() table.into_values().next().expect("table is coercable").val.v
.next()
.expect("table is coercable").val.v
} else { } else {
Expr::Table(table) Expr::Table(table)
}; };
@ -479,8 +480,7 @@ impl<'s> Parser<'s> {
fn end_group(&mut self) -> Span { fn end_group(&mut self) -> Span {
let peeked = self.peek(); let peeked = self.peek();
let (start, end_token) = self.delimiters.pop() let (start, end_token) = self.delimiters.pop().expect("group was not started");
.expect("group was not started");
if end_token != Token::Chain && peeked != None { if end_token != Token::Chain && peeked != None {
self.delimiters.push((start, end_token)); self.delimiters.push((start, end_token));
@ -529,11 +529,7 @@ impl<'s> Parser<'s> {
} }
fn check_eat(&mut self, token: Token<'_>) -> Option<Spanned<Token<'s>>> { fn check_eat(&mut self, token: Token<'_>) -> Option<Spanned<Token<'s>>> {
if self.check(token) { if self.check(token) { self.eat() } else { None }
self.eat()
} else {
None
}
} }
/// Checks if the next token is of some kind /// Checks if the next token is of some kind
@ -590,8 +586,7 @@ impl Group {
fn is_delimiter(token: Token<'_>) -> bool { fn is_delimiter(token: Token<'_>) -> bool {
matches!( matches!(
token, token,
Token::RightParen | Token::RightBracket Token::RightParen | Token::RightBracket | Token::RightBrace | Token::Chain
| Token::RightBrace | Token::Chain
) )
} }
@ -655,7 +650,10 @@ fn unescape_string(string: &str) -> String {
} }
Some('n') => out.push('\n'), Some('n') => out.push('\n'),
Some('t') => out.push('\t'), Some('t') => out.push('\t'),
Some(c) => { out.push('\\'); out.push(c); } Some(c) => {
out.push('\\');
out.push(c);
}
None => out.push('\\'), None => out.push('\\'),
} }
} else { } else {
@ -785,22 +783,20 @@ fn split_lines(text: &str) -> Vec<String> {
#[cfg(test)] #[cfg(test)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
mod tests { mod tests {
use crate::syntax::tests::*;
use crate::length::Length;
use super::*; use super::*;
use crate::length::Length;
use crate::syntax::tests::*;
use Decoration::*; use Decoration::*;
// ----------------------- Construct Syntax Nodes ----------------------- // // ----------------------- Construct Syntax Nodes ----------------------- //
use SyntaxNode::{ use SyntaxNode::{
Spacing as S, Linebreak as L, Parbreak as P, Spacing as S, ToggleBolder as B, ToggleItalic as I,
Linebreak as L,
Parbreak as P,
ToggleItalic as I,
ToggleBolder as B,
}; };
fn T(text: &str) -> SyntaxNode { SyntaxNode::Text(text.to_string()) } fn T(text: &str) -> SyntaxNode {
SyntaxNode::Text(text.to_string())
}
macro_rules! R { macro_rules! R {
($($line:expr),* $(,)?) => { ($($line:expr),* $(,)?) => {
@ -833,10 +829,14 @@ mod tests {
// ------------------------ Construct Expressions ----------------------- // // ------------------------ Construct Expressions ----------------------- //
use Expr::{Bool, Number as Num, Length as Len, Color}; use Expr::{Bool, Color, Length as Len, Number as Num};
fn Id(ident: &str) -> Expr { Expr::Ident(Ident(ident.to_string())) } fn Id(ident: &str) -> Expr {
fn Str(string: &str) -> Expr { Expr::Str(string.to_string()) } Expr::Ident(Ident(ident.to_string()))
}
fn Str(string: &str) -> Expr {
Expr::Str(string.to_string())
}
macro_rules! Table { macro_rules! Table {
(@table=$table:expr,) => {}; (@table=$table:expr,) => {};

View File

@ -4,8 +4,8 @@ use std::iter::Peekable;
use std::str::Chars; use std::str::Chars;
use unicode_xid::UnicodeXID; use unicode_xid::UnicodeXID;
use crate::length::Length;
use super::span::{Pos, Span, Spanned}; use super::span::{Pos, Span, Spanned};
use crate::length::Length;
use Token::*; use Token::*;
use TokenMode::*; use TokenMode::*;
@ -224,7 +224,10 @@ impl<'s> Iterator for Tokens<'s> {
// Comments. // Comments.
'/' if self.peek() == Some('/') => self.read_line_comment(), '/' if self.peek() == Some('/') => self.read_line_comment(),
'/' if self.peek() == Some('*') => self.read_block_comment(), '/' if self.peek() == Some('*') => self.read_block_comment(),
'*' if self.peek() == Some('/') => { self.eat(); Invalid("*/") } '*' if self.peek() == Some('/') => {
self.eat();
Invalid("*/")
}
// Whitespace. // Whitespace.
c if c.is_whitespace() => self.read_whitespace(start), c if c.is_whitespace() => self.read_whitespace(start),
@ -241,8 +244,7 @@ impl<'s> Iterator for Tokens<'s> {
':' if self.mode == Header => Colon, ':' if self.mode == Header => Colon,
',' if self.mode == Header => Comma, ',' if self.mode == Header => Comma,
'=' if self.mode == Header => Equals, '=' if self.mode == Header => Equals,
'>' if self.mode == Header && self.peek() == Some('>') => '>' if self.mode == Header && self.peek() == Some('>') => self.read_chain(),
self.read_chain(),
// Expression operators. // Expression operators.
'+' if self.mode == Header => Plus, '+' if self.mode == Header => Plus,
@ -309,7 +311,11 @@ impl<'s> Tokens<'s> {
} }
fn read_block_comment(&mut self) -> Token<'s> { fn read_block_comment(&mut self) -> Token<'s> {
enum Last { Slash, Star, Other } enum Last {
Slash,
Star,
Other,
}
let mut depth = 0; let mut depth = 0;
let mut last = Last::Other; let mut last = Last::Other;
@ -322,12 +328,12 @@ impl<'s> Tokens<'s> {
'/' => match last { '/' => match last {
Last::Star if depth == 0 => return true, Last::Star if depth == 0 => return true,
Last::Star => depth -= 1, Last::Star => depth -= 1,
_ => last = Last::Slash _ => last = Last::Slash,
} },
'*' => match last { '*' => match last {
Last::Slash => depth += 1, Last::Slash => depth += 1,
_ => last = Last::Star, _ => last = Last::Star,
} },
_ => last = Last::Other, _ => last = Last::Other,
} }
@ -409,8 +415,8 @@ impl<'s> Tokens<'s> {
Code { Code {
lang, lang,
raw: &self.src[start..end], raw: &self.src[start .. end],
terminated terminated,
} }
} else { } else {
Raw { raw, terminated } Raw { raw, terminated }
@ -443,9 +449,8 @@ impl<'s> Tokens<'s> {
self.eat(); self.eat();
if self.peek() == Some('{') { if self.peek() == Some('{') {
self.eat(); self.eat();
let (sequence, _) = self.read_string_until(false, 0, 0, |c| { let (sequence, _) =
!c.is_ascii_hexdigit() self.read_string_until(false, 0, 0, |c| !c.is_ascii_hexdigit());
});
let terminated = self.peek() == Some('}'); let terminated = self.peek() == Some('}');
if terminated { if terminated {
@ -460,7 +465,7 @@ impl<'s> Tokens<'s> {
Some(c) if is_escapable(c) => { Some(c) if is_escapable(c) => {
let index = self.index(); let index = self.index();
self.eat(); self.eat();
Text(&self.src[index..index + c.len_utf8()]) Text(&self.src[index .. index + c.len_utf8()])
} }
Some(c) if c.is_whitespace() => Backslash, Some(c) if c.is_whitespace() => Backslash,
Some(_) => Text("\\"), Some(_) => Text("\\"),
@ -522,7 +527,7 @@ impl<'s> Tokens<'s> {
end = ((end as isize) + offset_end) as usize; end = ((end as isize) + offset_end) as usize;
} }
(&self.src[start..end], matched) (&self.src[start .. end], matched)
} }
fn eat(&mut self) -> Option<char> { fn eat(&mut self) -> Option<char> {
@ -546,7 +551,7 @@ impl<'s> Tokens<'s> {
fn parse_percentage(text: &str) -> Option<f64> { fn parse_percentage(text: &str) -> Option<f64> {
if text.ends_with('%') { if text.ends_with('%') {
text[..text.len() - 1].parse::<f64>().ok() text[.. text.len() - 1].parse::<f64>().ok()
} else { } else {
None None
} }
@ -556,7 +561,7 @@ fn parse_percentage(text: &str) -> Option<f64> {
pub fn is_newline_char(character: char) -> bool { pub fn is_newline_char(character: char) -> bool {
match character { match character {
// Line Feed, Vertical Tab, Form Feed, Carriage Return. // Line Feed, Vertical Tab, Form Feed, Carriage Return.
'\x0A'..='\x0D' => true, '\x0A' ..= '\x0D' => true,
// Next Line, Line Separator, Paragraph Separator. // Next Line, Line Separator, Paragraph Separator.
'\u{0085}' | '\u{2028}' | '\u{2029}' => true, '\u{0085}' | '\u{2028}' | '\u{2029}' => true,
_ => false, _ => false,
@ -588,35 +593,33 @@ pub fn is_identifier(string: &str) -> bool {
#[cfg(test)] #[cfg(test)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
mod tests { mod tests {
use super::super::span::Spanned;
use super::*;
use crate::length::Length; use crate::length::Length;
use crate::syntax::tests::*; use crate::syntax::tests::*;
use super::*;
use super::super::span::Spanned;
use Token::{ use Token::{
Space as S, BlockComment as BC, Bool, Chain, Hex, Hyphen as Min, Ident as Id,
LineComment as LC, BlockComment as BC, LeftBrace as LB, LeftBracket as L, LeftParen as LP, Length as Len,
LeftBracket as L, RightBracket as R, LineComment as LC, Number as Num, Plus, RightBrace as RB, RightBracket as R,
LeftParen as LP, RightParen as RP, RightParen as RP, Slash, Space as S, Star, Text as T,
LeftBrace as LB, RightBrace as RB,
Chain,
Ident as Id,
Bool,
Number as Num,
Length as Len,
Hex,
Plus,
Hyphen as Min,
Slash,
Star,
Text as T,
}; };
fn Str(string: &str, terminated: bool) -> Token { Token::Str { string, terminated } } fn Str(string: &str, terminated: bool) -> Token {
fn Raw(raw: &str, terminated: bool) -> Token { Token::Raw { raw, terminated } } Token::Str { string, terminated }
fn Code<'a>(lang: Option<&'a str>, raw: &'a str, terminated: bool) -> Token<'a> { }
Token::Code { lang: lang.map(Spanned::zero), raw, terminated } fn Raw(raw: &str, terminated: bool) -> Token {
Token::Raw { raw, terminated }
}
fn Code<'a>(lang: Option<&'a str>, raw: &'a str, terminated: bool) -> Token<'a> {
Token::Code {
lang: lang.map(Spanned::zero),
raw,
terminated,
}
}
fn UE(sequence: &str, terminated: bool) -> Token {
Token::UnicodeEscape { sequence, terminated }
} }
fn UE(sequence: &str, terminated: bool) -> Token { Token::UnicodeEscape { sequence, terminated } }
macro_rules! t { ($($tts:tt)*) => {test!(@spans=false, $($tts)*)} } macro_rules! t { ($($tts:tt)*) => {test!(@spans=false, $($tts)*)} }
macro_rules! ts { ($($tts:tt)*) => {test!(@spans=true, $($tts)*)} } macro_rules! ts { ($($tts:tt)*) => {test!(@spans=true, $($tts)*)} }

View File

@ -2,15 +2,15 @@
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use super::decoration::Decoration;
use super::span::{SpanVec, Spanned};
use super::Ident;
use crate::color::RgbaColor; use crate::color::RgbaColor;
use crate::compute::table::{SpannedEntry, Table}; use crate::compute::table::{SpannedEntry, Table};
use crate::compute::value::{TableValue, Value}; use crate::compute::value::{TableValue, Value};
use crate::layout::LayoutContext; use crate::layout::LayoutContext;
use crate::length::Length; use crate::length::Length;
use crate::{DynFuture, Feedback}; use crate::{DynFuture, Feedback};
use super::decoration::Decoration;
use super::span::{Spanned, SpanVec};
use super::Ident;
/// A collection of nodes which form a tree together with the nodes' children. /// A collection of nodes which form a tree together with the nodes' children.
pub type SyntaxTree = SpanVec<SyntaxNode>; pub type SyntaxTree = SpanVec<SyntaxNode>;
@ -96,11 +96,7 @@ impl Expr {
} }
/// Evaluate the expression to a value. /// Evaluate the expression to a value.
pub async fn eval( pub async fn eval(&self, ctx: &LayoutContext<'_>, f: &mut Feedback) -> Value {
&self,
ctx: &LayoutContext<'_>,
f: &mut Feedback,
) -> Value {
use Expr::*; use Expr::*;
match self { match self {
Ident(i) => Value::Ident(i.clone()), Ident(i) => Value::Ident(i.clone()),

View File

@ -98,8 +98,10 @@ fn test(
" {:?}: {}:{}:{} - {}:{}: {}", " {:?}: {}:{}:{} - {}:{}: {}",
diagnostic.v.level, diagnostic.v.level,
path.display(), path.display(),
span.start.line + 1, span.start.column + 1, span.start.line + 1,
span.end.line + 1, span.end.column + 1, span.start.column + 1,
span.end.line + 1,
span.end.column + 1,
diagnostic.v.message, diagnostic.v.message,
); );
} }
@ -137,28 +139,23 @@ impl TestFilter {
if self.perfect { if self.perfect {
self.filter.iter().any(|p| name == p) self.filter.iter().any(|p| name == p)
} else { } else {
self.filter.is_empty() self.filter.is_empty() || self.filter.iter().any(|p| name.contains(p))
|| self.filter.iter().any(|p| name.contains(p))
} }
} }
} }
fn render( fn render(layouts: &MultiLayout, loader: &SharedFontLoader, scale: f64) -> DrawTarget {
layouts: &MultiLayout,
loader: &SharedFontLoader,
scale: f64,
) -> DrawTarget {
let pad = scale * 10.0; let pad = scale * 10.0;
let width = 2.0 * pad + layouts.iter() let width = 2.0 * pad
+ layouts
.iter()
.map(|l| scale * l.size.x) .map(|l| scale * l.size.x)
.max_by(|a, b| a.partial_cmp(&b).unwrap()) .max_by(|a, b| a.partial_cmp(&b).unwrap())
.unwrap() .unwrap()
.round(); .round();
let height = pad + layouts.iter() let height =
.map(|l| scale * l.size.y + pad) pad + layouts.iter().map(|l| scale * l.size.y + pad).sum::<f64>().round();
.sum::<f64>()
.round();
let mut surface = DrawTarget::new(width as i32, height as i32); let mut surface = DrawTarget::new(width as i32, height as i32);
surface.clear(BLACK); surface.clear(BLACK);