mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Format everything with rustfmt! 💚
This commit is contained in:
parent
0d44cf5321
commit
181f756a9e
@ -15,14 +15,10 @@ const FONT_DIR: &str = "fonts";
|
||||
const COMA: &str = include_str!("../tests/coma.typ");
|
||||
|
||||
fn parsing_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("parse-coma-28-lines", |b| {
|
||||
b.iter(|| parse(COMA))
|
||||
});
|
||||
c.bench_function("parse-coma-28-lines", |b| b.iter(|| parse(COMA)));
|
||||
|
||||
let long = COMA.repeat(100);
|
||||
c.bench_function("parse-coma-2800-lines", |b| {
|
||||
b.iter(|| parse(&long))
|
||||
});
|
||||
c.bench_function("parse-coma-2800-lines", |b| b.iter(|| parse(&long)));
|
||||
}
|
||||
|
||||
fn typesetting_benchmark(c: &mut Criterion) {
|
||||
|
15
main/main.rs
15
main/main.rs
@ -30,8 +30,7 @@ fn main() {
|
||||
panic!("source and destination path are the same");
|
||||
}
|
||||
|
||||
let src = read_to_string(src_path)
|
||||
.expect("failed to read from source file");
|
||||
let src = read_to_string(src_path).expect("failed to read from source file");
|
||||
|
||||
let mut index = FsIndex::new();
|
||||
index.search_dir("fonts");
|
||||
@ -55,16 +54,16 @@ fn main() {
|
||||
"{}: {}:{}:{} - {}:{}: {}",
|
||||
format!("{:?}", diagnostic.v.level).to_lowercase(),
|
||||
src_path.display(),
|
||||
span.start.line + 1, span.start.column + 1,
|
||||
span.end.line + 1, span.end.column + 1,
|
||||
span.start.line + 1,
|
||||
span.start.column + 1,
|
||||
span.end.line + 1,
|
||||
span.end.column + 1,
|
||||
diagnostic.v.message,
|
||||
);
|
||||
}
|
||||
|
||||
let file = File::create(&dest_path)
|
||||
.expect("failed to create output file");
|
||||
let file = File::create(&dest_path).expect("failed to create output file");
|
||||
|
||||
let writer = BufWriter::new(file);
|
||||
pdf::export(&layouts, &loader, writer)
|
||||
.expect("failed to export pdf");
|
||||
pdf::export(&layouts, &loader, writer).expect("failed to export pdf");
|
||||
}
|
||||
|
20
src/color.rs
20
src/color.rs
@ -49,7 +49,7 @@ impl FromStr for RgbaColor {
|
||||
}
|
||||
|
||||
let len = hex_str.len();
|
||||
let long = len == 6 || len == 8;
|
||||
let long = len == 6 || len == 8;
|
||||
let short = len == 3 || len == 4;
|
||||
let alpha = len == 4 || len == 8;
|
||||
|
||||
@ -59,13 +59,12 @@ impl FromStr for RgbaColor {
|
||||
|
||||
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 pos = elem * item_len;
|
||||
|
||||
let item = &hex_str[pos..(pos+item_len)];
|
||||
values[elem] = u8::from_str_radix(item, 16)
|
||||
.map_err(|_| ParseColorError)?;
|
||||
let item = &hex_str[pos .. (pos + item_len)];
|
||||
values[elem] = u8::from_str_radix(item, 16).map_err(|_| ParseColorError)?;
|
||||
|
||||
if short {
|
||||
// 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 {
|
||||
if f.alternate() {
|
||||
write!(
|
||||
f, "rgba({:02}, {:02}, {:02}, {:02})",
|
||||
f,
|
||||
"rgba({:02}, {:02}, {:02}, {:02})",
|
||||
self.r, self.g, self.b, self.a,
|
||||
)?;
|
||||
} else {
|
||||
write!(
|
||||
f, "#{:02x}{:02x}{:02x}{:02x}",
|
||||
f,
|
||||
"#{:02x}{:02x}{:02x}{:02x}",
|
||||
self.r, self.g, self.b, self.a,
|
||||
)?;
|
||||
}
|
||||
@ -116,10 +117,7 @@ mod tests {
|
||||
#[test]
|
||||
fn parse_color_strings() {
|
||||
fn test(hex: &str, r: u8, g: u8, b: u8, a: u8) {
|
||||
assert_eq!(
|
||||
RgbaColor::from_str(hex),
|
||||
Ok(RgbaColor::new(r, g, b, a)),
|
||||
);
|
||||
assert_eq!(RgbaColor::from_str(hex), Ok(RgbaColor::new(r, g, b, a)));
|
||||
}
|
||||
|
||||
test("f61243ff", 0xf6, 0x12, 0x43, 0xff);
|
||||
|
@ -14,9 +14,7 @@ impl Scope {
|
||||
// Create a new empty scope with a fallback function that is invoked when no
|
||||
// match is found.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
functions: HashMap::new(),
|
||||
}
|
||||
Self { functions: HashMap::new() }
|
||||
}
|
||||
|
||||
/// Associate the given name with the function.
|
||||
|
@ -117,7 +117,8 @@ impl<V> Table<V> {
|
||||
|
||||
/// Iterator over all borrowed keys and values.
|
||||
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)))
|
||||
}
|
||||
|
||||
@ -138,13 +139,17 @@ impl<V> Table<V> {
|
||||
|
||||
/// Move into an owned iterator over owned keys and values.
|
||||
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)))
|
||||
}
|
||||
|
||||
/// Move into an owned iterator over all values in the table.
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -6,15 +6,15 @@ use std::rc::Rc;
|
||||
|
||||
use fontdock::{FontStyle, FontWeight, FontWidth};
|
||||
|
||||
use super::table::{SpannedEntry, Table};
|
||||
use crate::color::RgbaColor;
|
||||
use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign};
|
||||
use crate::length::{Length, ScaleLength};
|
||||
use crate::paper::Paper;
|
||||
use crate::syntax::span::{Span, Spanned};
|
||||
use crate::syntax::tree::{SyntaxTree, SyntaxNode};
|
||||
use crate::syntax::tree::{SyntaxNode, SyntaxTree};
|
||||
use crate::syntax::Ident;
|
||||
use crate::{DynFuture, Feedback, Pass};
|
||||
use super::table::{SpannedEntry, Table};
|
||||
|
||||
/// A computational value.
|
||||
#[derive(Clone)]
|
||||
@ -78,9 +78,10 @@ impl Spanned<Value> {
|
||||
for entry in table.into_values() {
|
||||
if let Some(last_end) = end {
|
||||
let span = Span::new(last_end, entry.key.start);
|
||||
commands.push(Command::LayoutSyntaxTree(vec![
|
||||
Spanned::new(SyntaxNode::Spacing, span)
|
||||
]));
|
||||
commands.push(Command::LayoutSyntaxTree(vec![Spanned::new(
|
||||
SyntaxNode::Spacing,
|
||||
span,
|
||||
)]));
|
||||
}
|
||||
|
||||
end = Some(entry.val.span.end);
|
||||
@ -90,14 +91,10 @@ impl Spanned<Value> {
|
||||
}
|
||||
|
||||
// Format with debug.
|
||||
val => vec![
|
||||
Command::LayoutSyntaxTree(vec![
|
||||
Spanned::new(
|
||||
SyntaxNode::Text(format!("{:?}", val)),
|
||||
self.span,
|
||||
)
|
||||
])
|
||||
],
|
||||
val => vec![Command::LayoutSyntaxTree(vec![Spanned::new(
|
||||
SyntaxNode::Text(format!("{:?}", val)),
|
||||
self.span,
|
||||
)])],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,9 +146,8 @@ impl PartialEq for Value {
|
||||
/// layouting engine to do what the function pleases.
|
||||
///
|
||||
/// The dynamic function object is wrapped in an `Rc` to keep `Value` clonable.
|
||||
pub type FuncValue = Rc<
|
||||
dyn Fn(Span, TableValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>
|
||||
>;
|
||||
pub type FuncValue =
|
||||
Rc<dyn Fn(Span, TableValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>>;
|
||||
|
||||
/// A table of values.
|
||||
///
|
||||
@ -500,7 +496,10 @@ mod tests {
|
||||
table.expect::<String>("", Span::ZERO, &mut f),
|
||||
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);
|
||||
}
|
||||
|
||||
@ -512,7 +511,10 @@ mod tests {
|
||||
table.insert("hi", entry(Value::Bool(true)));
|
||||
assert_eq!(table.take::<bool>(), Some(false));
|
||||
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());
|
||||
}
|
||||
|
||||
@ -522,10 +524,10 @@ mod tests {
|
||||
table.insert(1, entry(Value::Bool(false)));
|
||||
table.insert(3, entry(Value::Number(0.0)));
|
||||
table.insert(7, entry(Value::Bool(true)));
|
||||
assert_eq!(
|
||||
table.take_all_num::<bool>().collect::<Vec<_>>(),
|
||||
[(1, false), (7, true)],
|
||||
);
|
||||
assert_eq!(table.take_all_num::<bool>().collect::<Vec<_>>(), [
|
||||
(1, false),
|
||||
(7, true)
|
||||
],);
|
||||
assert_eq!(table.len(), 1);
|
||||
assert_eq!(table[3].val.v, Value::Number(0.0));
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ use fontdock::FaceId;
|
||||
use tide::content::Content;
|
||||
use tide::doc::{Catalog, Page, PageTree, Resource, Text};
|
||||
use tide::font::{
|
||||
CIDFont, CIDFontType, CIDSystemInfo, CMap, CMapEncoding, FontDescriptor,
|
||||
FontFlags, FontStream, GlyphUnit, Type0Font, WidthRecord,
|
||||
CIDFont, CIDFontType, CIDSystemInfo, CMap, CMapEncoding, FontDescriptor, FontFlags,
|
||||
FontStream, GlyphUnit, Type0Font, WidthRecord,
|
||||
};
|
||||
use tide::{PdfWriter, Rect, Ref, Trailer, Version};
|
||||
use ttf_parser::{name_id, GlyphId};
|
||||
@ -89,20 +89,18 @@ impl<'a, W: Write> PdfExporter<'a, W> {
|
||||
|
||||
fn write_preface(&mut self) -> io::Result<()> {
|
||||
// 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 start = self.offsets.fonts.0;
|
||||
let fonts = (0..self.to_pdf.len() as u32).map(|i| {
|
||||
Resource::Font(i + 1, start + (NUM_OBJECTS_PER_FONT * i))
|
||||
});
|
||||
let fonts = (0 .. self.to_pdf.len() as u32)
|
||||
.map(|i| Resource::Font(i + 1, start + (NUM_OBJECTS_PER_FONT * i)));
|
||||
|
||||
// The root page tree.
|
||||
self.writer.write_obj(
|
||||
self.offsets.page_tree,
|
||||
PageTree::new()
|
||||
.kids(ids(self.offsets.pages))
|
||||
.resources(fonts),
|
||||
PageTree::new().kids(ids(self.offsets.pages)).resources(fonts),
|
||||
)?;
|
||||
|
||||
// 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(
|
||||
page_id,
|
||||
Page::new(self.offsets.page_tree)
|
||||
.media_box(rect)
|
||||
.content(content_id),
|
||||
Page::new(self.offsets.page_tree).media_box(rect).content(content_id),
|
||||
)?;
|
||||
}
|
||||
|
||||
@ -151,7 +147,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
|
||||
size = shaped.size;
|
||||
text.tf(
|
||||
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
|
||||
.names()
|
||||
.find(|entry| {
|
||||
entry.name_id() == name_id::POST_SCRIPT_NAME
|
||||
&& entry.is_unicode()
|
||||
entry.name_id() == name_id::POST_SCRIPT_NAME && entry.is_unicode()
|
||||
})
|
||||
.map(|entry| entry.to_string())
|
||||
.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 ratio = 1.0 / units_per_em;
|
||||
let to_glyph_unit = |font_unit: f64| {
|
||||
(1000.0 * ratio * font_unit).round() as GlyphUnit
|
||||
};
|
||||
let to_glyph_unit =
|
||||
|font_unit: f64| (1000.0 * ratio * font_unit).round() as GlyphUnit;
|
||||
|
||||
let global_bbox = face.global_bounding_box();
|
||||
let bbox = Rect::new(
|
||||
@ -218,7 +212,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
|
||||
flags.insert(FontFlags::SMALL_CAP);
|
||||
|
||||
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(|w| to_glyph_unit(w as f64))
|
||||
.collect();
|
||||
@ -258,23 +252,21 @@ impl<'a, W: Write> PdfExporter<'a, W> {
|
||||
)?;
|
||||
|
||||
// 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)
|
||||
.font_bbox(bbox)
|
||||
.ascent(to_glyph_unit(ascender as f64))
|
||||
.descent(to_glyph_unit(descender as f64))
|
||||
.cap_height(to_glyph_unit(cap_height as f64))
|
||||
.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
|
||||
// to enable copying out of the PDF.
|
||||
self.writer.write_obj(id + 3, &CMap::new(
|
||||
"Custom",
|
||||
system_info,
|
||||
mapping,
|
||||
))?;
|
||||
self.writer
|
||||
.write_obj(id + 3, &CMap::new("Custom", system_info, mapping))?;
|
||||
|
||||
// Write the face's bytes.
|
||||
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> {
|
||||
start..=end
|
||||
start ..= end
|
||||
}
|
||||
|
@ -30,9 +30,8 @@ impl FaceFromVec for OwnedFace {
|
||||
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
|
||||
// it can't be touched from outside this type.
|
||||
let slice: &'static [u8] = unsafe {
|
||||
std::slice::from_raw_parts(vec.as_ptr(), vec.len())
|
||||
};
|
||||
let slice: &'static [u8] =
|
||||
unsafe { std::slice::from_raw_parts(vec.as_ptr(), vec.len()) };
|
||||
|
||||
Some(Self {
|
||||
data: vec,
|
||||
|
44
src/geom.rs
44
src/geom.rs
@ -21,12 +21,18 @@ impl<T: Clone> Value2<T> {
|
||||
}
|
||||
|
||||
/// 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() }
|
||||
}
|
||||
|
||||
/// 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 }
|
||||
}
|
||||
|
||||
@ -53,22 +59,38 @@ impl<T: Clone> Value2<T> {
|
||||
|
||||
/// Return the primary value of this specialized 2D-value.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
@ -98,10 +120,7 @@ impl<T: Clone> Value2<T> {
|
||||
|
||||
impl<T: Debug> Debug for Value2<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
f.debug_list()
|
||||
.entry(&self.x)
|
||||
.entry(&self.y)
|
||||
.finish()
|
||||
f.debug_list().entry(&self.x).entry(&self.y).finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,10 +178,7 @@ impl Neg for Size {
|
||||
type Output = Size;
|
||||
|
||||
fn neg(self) -> Size {
|
||||
Size {
|
||||
x: -self.x,
|
||||
y: -self.y,
|
||||
}
|
||||
Size { x: -self.x, y: -self.y }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,9 +246,7 @@ impl LineLayouter {
|
||||
for (offset, layout) in layouts {
|
||||
let x = match self.ctx.axes.primary.is_positive() {
|
||||
true => offset,
|
||||
false => self.run.size.x
|
||||
- offset
|
||||
- layout.size.primary(self.ctx.axes),
|
||||
false => self.run.size.x - offset - layout.size.primary(self.ctx.axes),
|
||||
};
|
||||
|
||||
let pos = Size::with_x(x);
|
||||
@ -258,7 +256,7 @@ impl LineLayouter {
|
||||
self.stack.add(BoxLayout {
|
||||
size: self.run.size.specialized(self.ctx.axes),
|
||||
align: self.run.align.unwrap_or(LayoutAlign::new(Start, Start)),
|
||||
elements
|
||||
elements,
|
||||
});
|
||||
|
||||
self.run = LineRun::new();
|
||||
|
@ -10,7 +10,7 @@ mod tree;
|
||||
/// Basic types used across the layouting engine.
|
||||
pub mod prelude {
|
||||
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 GenAlign::*;
|
||||
pub use GenAxis::*;
|
||||
|
@ -140,7 +140,11 @@ pub enum SpecAxis {
|
||||
impl SpecAxis {
|
||||
/// The generic version of this axis in the given system of axes.
|
||||
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 {
|
||||
let get = |spec: SpecAxis, align: GenAlign| {
|
||||
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 {
|
||||
|
@ -19,8 +19,8 @@
|
||||
//! The position of the first aligned box thus depends on the length of the
|
||||
//! sentence in the second box.
|
||||
|
||||
use crate::geom::Value4;
|
||||
use super::*;
|
||||
use crate::geom::Value4;
|
||||
|
||||
/// Performs the stack layouting.
|
||||
pub struct StackLayouter {
|
||||
@ -130,14 +130,11 @@ impl StackLayouter {
|
||||
let size = Size::with_y(spacing);
|
||||
|
||||
self.update_metrics(size);
|
||||
self.space.layouts.push((
|
||||
self.ctx.axes,
|
||||
BoxLayout {
|
||||
size: size.specialized(self.ctx.axes),
|
||||
align: LayoutAlign::new(Start, Start),
|
||||
elements: LayoutElements::new(),
|
||||
}
|
||||
));
|
||||
self.space.layouts.push((self.ctx.axes, BoxLayout {
|
||||
size: size.specialized(self.ctx.axes),
|
||||
align: LayoutAlign::new(Start, Start),
|
||||
elements: LayoutElements::new(),
|
||||
}));
|
||||
|
||||
self.space.last_spacing = LastSpacing::Hard;
|
||||
}
|
||||
@ -179,8 +176,7 @@ impl StackLayouter {
|
||||
fn update_rulers(&mut self, align: LayoutAlign) -> bool {
|
||||
let allowed = self.is_fitting_alignment(align);
|
||||
if allowed {
|
||||
*self.space.rulers.get_mut(self.ctx.axes.secondary, Start) =
|
||||
align.secondary;
|
||||
*self.space.rulers.get_mut(self.ctx.axes.secondary, Start) = align.secondary;
|
||||
}
|
||||
allowed
|
||||
}
|
||||
@ -226,7 +222,7 @@ impl StackLayouter {
|
||||
/// if no space is capable of that.
|
||||
pub fn skip_to_fitting_space(&mut self, size: Size) {
|
||||
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) {
|
||||
self.finish_space(true);
|
||||
self.start_space(start + index, true);
|
||||
@ -246,7 +242,7 @@ impl StackLayouter {
|
||||
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());
|
||||
}
|
||||
|
||||
@ -288,8 +284,12 @@ impl StackLayouter {
|
||||
// expand if necessary.)
|
||||
|
||||
let usable = space.usable();
|
||||
if space.expansion.horizontal { self.space.size.x = usable.x; }
|
||||
if space.expansion.vertical { self.space.size.y = usable.y; }
|
||||
if space.expansion.horizontal {
|
||||
self.space.size.x = usable.x;
|
||||
}
|
||||
if space.expansion.vertical {
|
||||
self.space.size.y = usable.y;
|
||||
}
|
||||
|
||||
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
|
||||
// accumulated secondary extent of all layouts we have seen so far,
|
||||
// which are the layouts after this one since we iterate reversed.
|
||||
*bound.get_mut(axes.secondary, End) -=
|
||||
axes.secondary.factor() * extent.y;
|
||||
*bound.get_mut(axes.secondary, End) -= axes.secondary.factor() * extent.y;
|
||||
|
||||
// Then, we add this layout's secondary extent to the accumulator.
|
||||
let size = layout.size.generalized(*axes);
|
||||
@ -369,9 +368,8 @@ impl StackLayouter {
|
||||
|
||||
// The space in which this layout is aligned is given by the
|
||||
// distances between the borders of it's bounding box.
|
||||
let usable =
|
||||
Size::new(bound.right - bound.left, bound.bottom - bound.top)
|
||||
.generalized(axes);
|
||||
let usable = Size::new(bound.right - bound.left, bound.bottom - bound.top)
|
||||
.generalized(axes);
|
||||
|
||||
let local = usable.anchor(align, axes) - size.anchor(align, axes);
|
||||
let pos = Size::new(bound.left, bound.top) + local.specialized(axes);
|
||||
@ -379,11 +377,7 @@ impl StackLayouter {
|
||||
elements.extend_offset(pos, layout.elements);
|
||||
}
|
||||
|
||||
self.layouts.push(BoxLayout {
|
||||
size,
|
||||
align: self.ctx.align,
|
||||
elements,
|
||||
});
|
||||
self.layouts.push(BoxLayout { size, align: self.ctx.align, elements });
|
||||
|
||||
// ------------------------------------------------------------------ //
|
||||
// Step 5: Start the next space.
|
||||
|
@ -7,11 +7,11 @@
|
||||
use fontdock::{FaceId, FaceQuery, FontStyle};
|
||||
use ttf_parser::GlyphId;
|
||||
|
||||
use super::elements::{LayoutElement, Shaped};
|
||||
use super::*;
|
||||
use crate::font::SharedFontLoader;
|
||||
use crate::geom::Size;
|
||||
use crate::style::TextStyle;
|
||||
use super::elements::{LayoutElement, Shaped};
|
||||
use super::*;
|
||||
|
||||
/// Layouts text into a box.
|
||||
pub async fn layout_text(text: &str, ctx: TextContext<'_>) -> BoxLayout {
|
||||
|
@ -1,19 +1,16 @@
|
||||
//! 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::text::{layout_text, TextContext};
|
||||
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.
|
||||
pub async fn layout_tree(
|
||||
tree: &SyntaxTree,
|
||||
ctx: LayoutContext<'_>,
|
||||
) -> Pass<MultiLayout> {
|
||||
pub async fn layout_tree(tree: &SyntaxTree, ctx: LayoutContext<'_>) -> Pass<MultiLayout> {
|
||||
let mut layouter = TreeLayouter::new(ctx);
|
||||
layouter.layout_tree(tree).await;
|
||||
layouter.finish()
|
||||
@ -75,8 +72,12 @@ impl<'a> TreeLayouter<'a> {
|
||||
}
|
||||
|
||||
SyntaxNode::Text(text) => {
|
||||
if self.style.text.italic { decorate(self, Decoration::Italic); }
|
||||
if self.style.text.bolder { decorate(self, Decoration::Bold); }
|
||||
if self.style.text.italic {
|
||||
decorate(self, Decoration::Italic);
|
||||
}
|
||||
if self.style.text.bolder {
|
||||
decorate(self, Decoration::Bold);
|
||||
}
|
||||
self.layout_text(text).await;
|
||||
}
|
||||
|
||||
@ -90,10 +91,8 @@ impl<'a> TreeLayouter<'a> {
|
||||
}
|
||||
|
||||
fn layout_space(&mut self) {
|
||||
self.layouter.add_primary_spacing(
|
||||
self.style.text.word_spacing(),
|
||||
SpacingKind::WORD,
|
||||
);
|
||||
self.layouter
|
||||
.add_primary_spacing(self.style.text.word_spacing(), SpacingKind::WORD);
|
||||
}
|
||||
|
||||
fn layout_parbreak(&mut self) {
|
||||
@ -105,24 +104,20 @@ impl<'a> TreeLayouter<'a> {
|
||||
|
||||
async fn layout_text(&mut self, text: &str) {
|
||||
self.layouter.add(
|
||||
layout_text(
|
||||
text,
|
||||
TextContext {
|
||||
loader: &self.ctx.loader,
|
||||
style: &self.style.text,
|
||||
dir: self.ctx.axes.primary,
|
||||
align: self.ctx.align,
|
||||
}
|
||||
).await
|
||||
layout_text(text, TextContext {
|
||||
loader: &self.ctx.loader,
|
||||
style: &self.style.text,
|
||||
dir: self.ctx.axes.primary,
|
||||
align: self.ctx.align,
|
||||
})
|
||||
.await,
|
||||
);
|
||||
}
|
||||
|
||||
async fn layout_raw(&mut self, lines: &[String]) {
|
||||
// TODO: Make this more efficient.
|
||||
let fallback = self.style.text.fallback.clone();
|
||||
self.style.text.fallback
|
||||
.list_mut()
|
||||
.insert(0, "monospace".to_string());
|
||||
self.style.text.fallback.list_mut().insert(0, "monospace".to_string());
|
||||
self.style.text.fallback.flatten();
|
||||
|
||||
let mut first = true;
|
||||
@ -176,7 +171,7 @@ impl<'a> TreeLayouter<'a> {
|
||||
AddSpacing(space, kind, axis) => match axis {
|
||||
Primary => self.layouter.add_primary_spacing(space, kind),
|
||||
Secondary => self.layouter.add_secondary_spacing(space, kind),
|
||||
}
|
||||
},
|
||||
|
||||
BreakLine => self.layouter.finish_line(),
|
||||
BreakPage => {
|
||||
@ -203,13 +198,14 @@ impl<'a> TreeLayouter<'a> {
|
||||
// new page style and update it within the layouter.
|
||||
let margins = style.margins();
|
||||
self.ctx.base = style.size.unpadded(margins);
|
||||
self.layouter.set_spaces(vec![
|
||||
LayoutSpace {
|
||||
self.layouter.set_spaces(
|
||||
vec![LayoutSpace {
|
||||
size: style.size,
|
||||
padding: margins,
|
||||
expansion: LayoutExpansion::new(true, true),
|
||||
}
|
||||
], true);
|
||||
}],
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
error!(
|
||||
@self.feedback, span,
|
||||
|
@ -150,7 +150,7 @@ impl FromStr for Length {
|
||||
// have valid ASCII chars as subbytes.
|
||||
let split = len - 2;
|
||||
let bytes = src.as_bytes();
|
||||
let unit = match &bytes[split..] {
|
||||
let unit = match &bytes[split ..] {
|
||||
b"pt" => Unit::Pt,
|
||||
b"mm" => Unit::Mm,
|
||||
b"cm" => Unit::Cm,
|
||||
@ -158,7 +158,7 @@ impl FromStr for Length {
|
||||
_ => return Err(ParseLengthError),
|
||||
};
|
||||
|
||||
src[..split]
|
||||
src[.. split]
|
||||
.parse::<f64>()
|
||||
.map(|val| Self::new(val, unit))
|
||||
.map_err(|_| ParseLengthError)
|
||||
|
39
src/lib.rs
39
src/lib.rs
@ -95,24 +95,22 @@ impl Typesetter {
|
||||
use crate::layout::prelude::*;
|
||||
|
||||
let margins = self.style.page.margins();
|
||||
layout(
|
||||
&tree,
|
||||
LayoutContext {
|
||||
loader: &self.loader,
|
||||
scope: &self.std,
|
||||
style: &self.style,
|
||||
base: self.style.page.size.unpadded(margins),
|
||||
spaces: vec![LayoutSpace {
|
||||
size: self.style.page.size,
|
||||
padding: margins,
|
||||
expansion: LayoutExpansion::new(true, true),
|
||||
}],
|
||||
repeat: true,
|
||||
axes: LayoutAxes::new(LTR, TTB),
|
||||
align: LayoutAlign::new(Start, Start),
|
||||
root: true,
|
||||
},
|
||||
).await
|
||||
layout(&tree, LayoutContext {
|
||||
loader: &self.loader,
|
||||
scope: &self.std,
|
||||
style: &self.style,
|
||||
base: self.style.page.size.unpadded(margins),
|
||||
spaces: vec![LayoutSpace {
|
||||
size: self.style.page.size,
|
||||
padding: margins,
|
||||
expansion: LayoutExpansion::new(true, true),
|
||||
}],
|
||||
repeat: true,
|
||||
axes: LayoutAxes::new(LTR, TTB),
|
||||
align: LayoutAlign::new(Start, Start),
|
||||
root: true,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Process source code directly into a collection of layouts.
|
||||
@ -177,10 +175,7 @@ pub struct Feedback {
|
||||
impl Feedback {
|
||||
/// Create a new feedback instance without errors and decos.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
diagnostics: vec![],
|
||||
decorations: vec![],
|
||||
}
|
||||
Self { diagnostics: vec![], decorations: vec![] }
|
||||
}
|
||||
|
||||
/// Merged two feedbacks into one.
|
||||
|
@ -1,12 +1,16 @@
|
||||
use crate::length::ScaleLength;
|
||||
use super::*;
|
||||
use crate::length::ScaleLength;
|
||||
|
||||
/// `box`: Layouts its contents into a box.
|
||||
///
|
||||
/// # Keyword arguments
|
||||
/// - `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).
|
||||
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 content = args.take::<SyntaxTree>().unwrap_or(SyntaxTree::new());
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::color::RgbaColor;
|
||||
use super::*;
|
||||
use crate::color::RgbaColor;
|
||||
|
||||
/// `rgb`: Create an RGB(A) color.
|
||||
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 mut clamp = |component: Option<Spanned<f64>>, default| {
|
||||
component.map(|c| {
|
||||
if c.v < 0.0 || c.v > 255.0 {
|
||||
error!(@f, c.span, "should be between 0 and 255")
|
||||
}
|
||||
c.v.min(255.0).max(0.0).round() as u8
|
||||
}).unwrap_or(default)
|
||||
component
|
||||
.map(|c| {
|
||||
if c.v < 0.0 || c.v > 255.0 {
|
||||
error!(@f, c.span, "should be between 0 and 255")
|
||||
}
|
||||
c.v.min(255.0).max(0.0).round() as u8
|
||||
})
|
||||
.unwrap_or(default)
|
||||
};
|
||||
|
||||
let color = RgbaColor::new(
|
||||
clamp(r, 0),
|
||||
clamp(g, 0),
|
||||
clamp(b, 0),
|
||||
clamp(a, 255),
|
||||
);
|
||||
let color = RgbaColor::new(clamp(r, 0), clamp(g, 0), clamp(b, 0), clamp(a, 255));
|
||||
|
||||
args.unexpected(&mut f);
|
||||
Pass::new(Value::Color(color), f)
|
||||
|
@ -1,7 +1,7 @@
|
||||
use fontdock::{FontStyle, FontWeight, FontWidth};
|
||||
|
||||
use crate::length::ScaleLength;
|
||||
use super::*;
|
||||
use crate::length::ScaleLength;
|
||||
|
||||
/// `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())
|
||||
.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>() {
|
||||
let fallback = table.take_all_num_vals::<StringLike>()
|
||||
let fallback = table
|
||||
.take_all_num_vals::<StringLike>()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use crate::length::{Length, ScaleLength};
|
||||
use crate::paper::{Paper, PaperClass};
|
||||
use super::*;
|
||||
|
||||
/// `page`: Configure pages.
|
||||
///
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use crate::layout::SpacingKind;
|
||||
use crate::length::ScaleLength;
|
||||
use super::*;
|
||||
|
||||
/// `h`: Add horizontal spacing.
|
||||
///
|
||||
|
22
src/paper.rs
22
src/paper.rs
@ -39,19 +39,21 @@ pub enum PaperClass {
|
||||
impl PaperClass {
|
||||
/// The default margins for this page class.
|
||||
pub fn default_margins(self) -> Value4<ScaleLength> {
|
||||
let values = |l, t, r, b| Value4::new(
|
||||
ScaleLength::Scaled(l),
|
||||
ScaleLength::Scaled(t),
|
||||
ScaleLength::Scaled(r),
|
||||
ScaleLength::Scaled(b),
|
||||
);
|
||||
let values = |l, t, r, b| {
|
||||
Value4::new(
|
||||
ScaleLength::Scaled(l),
|
||||
ScaleLength::Scaled(t),
|
||||
ScaleLength::Scaled(r),
|
||||
ScaleLength::Scaled(b),
|
||||
)
|
||||
};
|
||||
|
||||
match self {
|
||||
Self::Custom => values(0.1190, 0.0842, 0.1190, 0.0842),
|
||||
Self::Base => values(0.1190, 0.0842, 0.1190, 0.0842),
|
||||
Self::US => values(0.1760, 0.1092, 0.1760, 0.0910),
|
||||
Self::Custom => values(0.1190, 0.0842, 0.1190, 0.0842),
|
||||
Self::Base => values(0.1190, 0.0842, 0.1190, 0.0842),
|
||||
Self::US => values(0.1760, 0.1092, 0.1760, 0.0910),
|
||||
Self::Newspaper => values(0.0455, 0.0587, 0.0455, 0.0294),
|
||||
Self::Book => values(0.1200, 0.0852, 0.1500, 0.0965),
|
||||
Self::Book => values(0.1200, 0.0852, 0.1500, 0.0965),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
//! A prelude for building custom functions.
|
||||
|
||||
pub use super::*;
|
||||
pub use crate::compute::value::*;
|
||||
pub use crate::layout::prelude::*;
|
||||
pub use crate::layout::Commands;
|
||||
pub use crate::layout::Command::{self, *};
|
||||
pub use crate::layout::Commands;
|
||||
pub use crate::style::*;
|
||||
pub use crate::syntax::parsing::parse;
|
||||
pub use crate::syntax::span::{Pos, Span, SpanVec, Spanned};
|
||||
pub use crate::syntax::tree::*;
|
||||
pub use crate::{Pass, Feedback};
|
||||
pub use super::*;
|
||||
pub use crate::{Feedback, Pass};
|
||||
|
@ -1,8 +1,6 @@
|
||||
//! Styles for text and pages.
|
||||
|
||||
use fontdock::{
|
||||
fallback, FallbackTree, FontStyle, FontVariant, FontWeight, FontWidth,
|
||||
};
|
||||
use fontdock::{fallback, FallbackTree, FontStyle, FontVariant, FontWeight, FontWidth};
|
||||
|
||||
use crate::geom::{Margins, Size, Value4};
|
||||
use crate::length::{Length, ScaleLength};
|
||||
|
@ -37,9 +37,9 @@ impl Debug for Ident {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fmt::Debug;
|
||||
use crate::prelude::*;
|
||||
use super::span;
|
||||
use crate::prelude::*;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Assert that expected and found are equal, printing both and panicking
|
||||
/// and the source of their test case if they aren't.
|
||||
|
@ -2,16 +2,14 @@
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{Feedback, Pass};
|
||||
use crate::color::RgbaColor;
|
||||
use crate::compute::table::SpannedEntry;
|
||||
use super::decoration::Decoration;
|
||||
use super::span::{Pos, Span, Spanned};
|
||||
use super::tokens::{is_newline_char, Token, TokenMode, Tokens};
|
||||
use super::tree::{
|
||||
CallExpr, Expr, SyntaxNode, SyntaxTree, TableExpr, Code,
|
||||
};
|
||||
use super::tree::{CallExpr, Code, Expr, SyntaxNode, SyntaxTree, TableExpr};
|
||||
use super::Ident;
|
||||
use crate::color::RgbaColor;
|
||||
use crate::compute::table::SpannedEntry;
|
||||
use crate::{Feedback, Pass};
|
||||
|
||||
/// Parse a string of source code.
|
||||
pub fn parse(src: &str) -> Pass<SyntaxTree> {
|
||||
@ -106,9 +104,7 @@ impl Parser<'_> {
|
||||
self.with_span(SyntaxNode::Code(Code { lang, lines, block }))
|
||||
}
|
||||
|
||||
Token::Text(text) => {
|
||||
self.with_span(SyntaxNode::Text(text.to_string()))
|
||||
}
|
||||
Token::Text(text) => self.with_span(SyntaxNode::Text(text.to_string())),
|
||||
|
||||
Token::UnicodeEscape { sequence, terminated } => {
|
||||
if !terminated {
|
||||
@ -222,7 +218,10 @@ impl Parser<'_> {
|
||||
let mut table = TableExpr::new();
|
||||
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() {
|
||||
self.skip_white();
|
||||
|
||||
@ -243,7 +242,7 @@ impl Parser<'_> {
|
||||
(None, call.map(Expr::Call))
|
||||
}
|
||||
|
||||
_ => (None, ident.map(Expr::Ident))
|
||||
_ => (None, ident.map(Expr::Ident)),
|
||||
}
|
||||
} else if let Some(value) = self.parse_expr() {
|
||||
(None, value)
|
||||
@ -256,13 +255,17 @@ impl Parser<'_> {
|
||||
if let Some(key) = key {
|
||||
comma_and_keyless = false;
|
||||
table.insert(key.v.0, SpannedEntry::new(key.span, val));
|
||||
self.feedback.decorations
|
||||
self.feedback
|
||||
.decorations
|
||||
.push(Spanned::new(Decoration::TableKey, key.span));
|
||||
} else {
|
||||
table.push(SpannedEntry::val(val));
|
||||
}
|
||||
|
||||
if { self.skip_white(); self.eof() } {
|
||||
if {
|
||||
self.skip_white();
|
||||
self.eof()
|
||||
} {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -389,9 +392,7 @@ impl Parser<'_> {
|
||||
let span = self.end_group();
|
||||
|
||||
let expr = if coercable {
|
||||
table.into_values()
|
||||
.next()
|
||||
.expect("table is coercable").val.v
|
||||
table.into_values().next().expect("table is coercable").val.v
|
||||
} else {
|
||||
Expr::Table(table)
|
||||
};
|
||||
@ -479,8 +480,7 @@ impl<'s> Parser<'s> {
|
||||
fn end_group(&mut self) -> Span {
|
||||
let peeked = self.peek();
|
||||
|
||||
let (start, end_token) = self.delimiters.pop()
|
||||
.expect("group was not started");
|
||||
let (start, end_token) = self.delimiters.pop().expect("group was not started");
|
||||
|
||||
if end_token != Token::Chain && peeked != None {
|
||||
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>>> {
|
||||
if self.check(token) {
|
||||
self.eat()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if self.check(token) { self.eat() } else { None }
|
||||
}
|
||||
|
||||
/// Checks if the next token is of some kind
|
||||
@ -590,8 +586,7 @@ impl Group {
|
||||
fn is_delimiter(token: Token<'_>) -> bool {
|
||||
matches!(
|
||||
token,
|
||||
Token::RightParen | Token::RightBracket
|
||||
| Token::RightBrace | Token::Chain
|
||||
Token::RightParen | Token::RightBracket | Token::RightBrace | Token::Chain
|
||||
)
|
||||
}
|
||||
|
||||
@ -655,7 +650,10 @@ fn unescape_string(string: &str) -> String {
|
||||
}
|
||||
Some('n') => out.push('\n'),
|
||||
Some('t') => out.push('\t'),
|
||||
Some(c) => { out.push('\\'); out.push(c); }
|
||||
Some(c) => {
|
||||
out.push('\\');
|
||||
out.push(c);
|
||||
}
|
||||
None => out.push('\\'),
|
||||
}
|
||||
} else {
|
||||
@ -785,22 +783,20 @@ fn split_lines(text: &str) -> Vec<String> {
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::syntax::tests::*;
|
||||
use crate::length::Length;
|
||||
use super::*;
|
||||
use crate::length::Length;
|
||||
use crate::syntax::tests::*;
|
||||
use Decoration::*;
|
||||
|
||||
// ----------------------- Construct Syntax Nodes ----------------------- //
|
||||
|
||||
use SyntaxNode::{
|
||||
Spacing as S,
|
||||
Linebreak as L,
|
||||
Parbreak as P,
|
||||
ToggleItalic as I,
|
||||
ToggleBolder as B,
|
||||
Linebreak as L, Parbreak as P, Spacing as S, ToggleBolder as B, ToggleItalic as I,
|
||||
};
|
||||
|
||||
fn T(text: &str) -> SyntaxNode { SyntaxNode::Text(text.to_string()) }
|
||||
fn T(text: &str) -> SyntaxNode {
|
||||
SyntaxNode::Text(text.to_string())
|
||||
}
|
||||
|
||||
macro_rules! R {
|
||||
($($line:expr),* $(,)?) => {
|
||||
@ -833,10 +829,14 @@ mod tests {
|
||||
|
||||
// ------------------------ 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 Str(string: &str) -> Expr { Expr::Str(string.to_string()) }
|
||||
fn Id(ident: &str) -> Expr {
|
||||
Expr::Ident(Ident(ident.to_string()))
|
||||
}
|
||||
fn Str(string: &str) -> Expr {
|
||||
Expr::Str(string.to_string())
|
||||
}
|
||||
|
||||
macro_rules! Table {
|
||||
(@table=$table:expr,) => {};
|
||||
|
@ -4,8 +4,8 @@ use std::iter::Peekable;
|
||||
use std::str::Chars;
|
||||
use unicode_xid::UnicodeXID;
|
||||
|
||||
use crate::length::Length;
|
||||
use super::span::{Pos, Span, Spanned};
|
||||
use crate::length::Length;
|
||||
|
||||
use Token::*;
|
||||
use TokenMode::*;
|
||||
@ -224,7 +224,10 @@ impl<'s> Iterator for Tokens<'s> {
|
||||
// Comments.
|
||||
'/' if self.peek() == Some('/') => self.read_line_comment(),
|
||||
'/' if self.peek() == Some('*') => self.read_block_comment(),
|
||||
'*' if self.peek() == Some('/') => { self.eat(); Invalid("*/") }
|
||||
'*' if self.peek() == Some('/') => {
|
||||
self.eat();
|
||||
Invalid("*/")
|
||||
}
|
||||
|
||||
// Whitespace.
|
||||
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 => Comma,
|
||||
'=' if self.mode == Header => Equals,
|
||||
'>' if self.mode == Header && self.peek() == Some('>') =>
|
||||
self.read_chain(),
|
||||
'>' if self.mode == Header && self.peek() == Some('>') => self.read_chain(),
|
||||
|
||||
// Expression operators.
|
||||
'+' if self.mode == Header => Plus,
|
||||
@ -276,10 +278,10 @@ impl<'s> Iterator for Tokens<'s> {
|
||||
let (text, _) = self.read_string_until(false, start_offset, 0, |n| {
|
||||
let val = match n {
|
||||
c if c.is_whitespace() => true,
|
||||
'[' | ']' | '{' | '}' | '/' | '*' => true,
|
||||
'[' | ']' | '{' | '}' | '/' | '*' => true,
|
||||
'\\' | '_' | '`' if body => true,
|
||||
':' | '=' | ',' | '"' | '(' | ')' if !body => true,
|
||||
'+' | '-' if !body && !last_was_e => true,
|
||||
':' | '=' | ',' | '"' | '(' | ')' if !body => true,
|
||||
'+' | '-' if !body && !last_was_e => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -309,7 +311,11 @@ impl<'s> Tokens<'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 last = Last::Other;
|
||||
@ -322,12 +328,12 @@ impl<'s> Tokens<'s> {
|
||||
'/' => match last {
|
||||
Last::Star if depth == 0 => return true,
|
||||
Last::Star => depth -= 1,
|
||||
_ => last = Last::Slash
|
||||
}
|
||||
_ => last = Last::Slash,
|
||||
},
|
||||
'*' => match last {
|
||||
Last::Slash => depth += 1,
|
||||
_ => last = Last::Star,
|
||||
}
|
||||
},
|
||||
_ => last = Last::Other,
|
||||
}
|
||||
|
||||
@ -409,8 +415,8 @@ impl<'s> Tokens<'s> {
|
||||
|
||||
Code {
|
||||
lang,
|
||||
raw: &self.src[start..end],
|
||||
terminated
|
||||
raw: &self.src[start .. end],
|
||||
terminated,
|
||||
}
|
||||
} else {
|
||||
Raw { raw, terminated }
|
||||
@ -443,9 +449,8 @@ impl<'s> Tokens<'s> {
|
||||
self.eat();
|
||||
if self.peek() == Some('{') {
|
||||
self.eat();
|
||||
let (sequence, _) = self.read_string_until(false, 0, 0, |c| {
|
||||
!c.is_ascii_hexdigit()
|
||||
});
|
||||
let (sequence, _) =
|
||||
self.read_string_until(false, 0, 0, |c| !c.is_ascii_hexdigit());
|
||||
|
||||
let terminated = self.peek() == Some('}');
|
||||
if terminated {
|
||||
@ -460,7 +465,7 @@ impl<'s> Tokens<'s> {
|
||||
Some(c) if is_escapable(c) => {
|
||||
let index = self.index();
|
||||
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(_) => Text("\\"),
|
||||
@ -522,7 +527,7 @@ impl<'s> Tokens<'s> {
|
||||
end = ((end as isize) + offset_end) as usize;
|
||||
}
|
||||
|
||||
(&self.src[start..end], matched)
|
||||
(&self.src[start .. end], matched)
|
||||
}
|
||||
|
||||
fn eat(&mut self) -> Option<char> {
|
||||
@ -546,7 +551,7 @@ impl<'s> Tokens<'s> {
|
||||
|
||||
fn parse_percentage(text: &str) -> Option<f64> {
|
||||
if text.ends_with('%') {
|
||||
text[..text.len() - 1].parse::<f64>().ok()
|
||||
text[.. text.len() - 1].parse::<f64>().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -556,7 +561,7 @@ fn parse_percentage(text: &str) -> Option<f64> {
|
||||
pub fn is_newline_char(character: char) -> bool {
|
||||
match character {
|
||||
// Line Feed, Vertical Tab, Form Feed, Carriage Return.
|
||||
'\x0A'..='\x0D' => true,
|
||||
'\x0A' ..= '\x0D' => true,
|
||||
// Next Line, Line Separator, Paragraph Separator.
|
||||
'\u{0085}' | '\u{2028}' | '\u{2029}' => true,
|
||||
_ => false,
|
||||
@ -588,35 +593,33 @@ pub fn is_identifier(string: &str) -> bool {
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use super::super::span::Spanned;
|
||||
use super::*;
|
||||
use crate::length::Length;
|
||||
use crate::syntax::tests::*;
|
||||
use super::*;
|
||||
use super::super::span::Spanned;
|
||||
use Token::{
|
||||
Space as S,
|
||||
LineComment as LC, BlockComment as BC,
|
||||
LeftBracket as L, RightBracket as R,
|
||||
LeftParen as LP, RightParen as RP,
|
||||
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,
|
||||
BlockComment as BC, Bool, Chain, Hex, Hyphen as Min, Ident as Id,
|
||||
LeftBrace as LB, LeftBracket as L, LeftParen as LP, Length as Len,
|
||||
LineComment as LC, Number as Num, Plus, RightBrace as RB, RightBracket as R,
|
||||
RightParen as RP, Slash, Space as S, Star, Text as T,
|
||||
};
|
||||
|
||||
fn Str(string: &str, terminated: bool) -> Token { Token::Str { string, 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 Str(string: &str, terminated: bool) -> Token {
|
||||
Token::Str { string, 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! ts { ($($tts:tt)*) => {test!(@spans=true, $($tts)*)} }
|
||||
|
@ -2,15 +2,15 @@
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use super::decoration::Decoration;
|
||||
use super::span::{SpanVec, Spanned};
|
||||
use super::Ident;
|
||||
use crate::color::RgbaColor;
|
||||
use crate::compute::table::{SpannedEntry, Table};
|
||||
use crate::compute::value::{TableValue, Value};
|
||||
use crate::layout::LayoutContext;
|
||||
use crate::length::Length;
|
||||
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.
|
||||
pub type SyntaxTree = SpanVec<SyntaxNode>;
|
||||
@ -96,11 +96,7 @@ impl Expr {
|
||||
}
|
||||
|
||||
/// Evaluate the expression to a value.
|
||||
pub async fn eval(
|
||||
&self,
|
||||
ctx: &LayoutContext<'_>,
|
||||
f: &mut Feedback,
|
||||
) -> Value {
|
||||
pub async fn eval(&self, ctx: &LayoutContext<'_>, f: &mut Feedback) -> Value {
|
||||
use Expr::*;
|
||||
match self {
|
||||
Ident(i) => Value::Ident(i.clone()),
|
||||
|
@ -98,8 +98,10 @@ fn test(
|
||||
" {:?}: {}:{}:{} - {}:{}: {}",
|
||||
diagnostic.v.level,
|
||||
path.display(),
|
||||
span.start.line + 1, span.start.column + 1,
|
||||
span.end.line + 1, span.end.column + 1,
|
||||
span.start.line + 1,
|
||||
span.start.column + 1,
|
||||
span.end.line + 1,
|
||||
span.end.column + 1,
|
||||
diagnostic.v.message,
|
||||
);
|
||||
}
|
||||
@ -137,28 +139,23 @@ impl TestFilter {
|
||||
if self.perfect {
|
||||
self.filter.iter().any(|p| name == p)
|
||||
} else {
|
||||
self.filter.is_empty()
|
||||
|| self.filter.iter().any(|p| name.contains(p))
|
||||
self.filter.is_empty() || self.filter.iter().any(|p| name.contains(p))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render(
|
||||
layouts: &MultiLayout,
|
||||
loader: &SharedFontLoader,
|
||||
scale: f64,
|
||||
) -> DrawTarget {
|
||||
fn render(layouts: &MultiLayout, loader: &SharedFontLoader, scale: f64) -> DrawTarget {
|
||||
let pad = scale * 10.0;
|
||||
let width = 2.0 * pad + layouts.iter()
|
||||
.map(|l| scale * l.size.x)
|
||||
.max_by(|a, b| a.partial_cmp(&b).unwrap())
|
||||
.unwrap()
|
||||
.round();
|
||||
let width = 2.0 * pad
|
||||
+ layouts
|
||||
.iter()
|
||||
.map(|l| scale * l.size.x)
|
||||
.max_by(|a, b| a.partial_cmp(&b).unwrap())
|
||||
.unwrap()
|
||||
.round();
|
||||
|
||||
let height = pad + layouts.iter()
|
||||
.map(|l| scale * l.size.y + pad)
|
||||
.sum::<f64>()
|
||||
.round();
|
||||
let height =
|
||||
pad + layouts.iter().map(|l| scale * l.size.y + pad).sum::<f64>().round();
|
||||
|
||||
let mut surface = DrawTarget::new(width as i32, height as i32);
|
||||
surface.clear(BLACK);
|
||||
|
Loading…
x
Reference in New Issue
Block a user