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");
|
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) {
|
||||||
|
15
main/main.rs
15
main/main.rs
@ -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");
|
|
||||||
}
|
}
|
||||||
|
14
src/color.rs
14
src/color.rs
@ -64,8 +64,7 @@ impl FromStr for RgbaColor {
|
|||||||
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);
|
||||||
|
@ -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.
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
@ -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()))?;
|
||||||
|
@ -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,
|
||||||
|
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.
|
/// 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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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::*;
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
13
src/lib.rs
13
src/lib.rs
@ -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.
|
||||||
|
@ -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());
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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.
|
||||||
///
|
///
|
||||||
|
@ -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.
|
||||||
///
|
///
|
||||||
|
@ -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),
|
||||||
|
@ -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::*;
|
|
||||||
|
@ -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};
|
||||||
|
@ -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.
|
||||||
|
@ -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,) => {};
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +416,7 @@ 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 {
|
||||||
@ -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)*)} }
|
||||||
|
@ -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()),
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user