Make clippy a bit happier

This commit is contained in:
Laurenz 2021-12-30 11:37:11 +01:00
parent fef5502517
commit f5dcb84e36
28 changed files with 210 additions and 198 deletions

View File

@ -372,13 +372,13 @@ impl Packer {
return;
}
if !self.par.styles.compatible(&styles, ParNode::has_property) {
if !self.par.styles.compatible(styles, ParNode::has_property) {
self.parbreak(None);
self.par.styles = styles.clone();
return;
}
self.par.styles.intersect(&styles);
self.par.styles.intersect(styles);
}
/// Break to a new page if the `styles` contain page styles that are
@ -389,7 +389,7 @@ impl Packer {
return;
}
if self.top && !self.flow.styles.compatible(&styles, PageNode::has_property) {
if self.top && !self.flow.styles.compatible(styles, PageNode::has_property) {
self.pagebreak();
self.flow.styles = styles.clone();
return;

View File

@ -390,7 +390,7 @@ impl<'a> PageExporter<'a> {
// Make the coordinate system start at the top-left.
self.bottom = frame.size.y.to_f32();
self.content.transform([1.0, 0.0, 0.0, -1.0, 0.0, self.bottom]);
self.write_frame(&frame);
self.write_frame(frame);
Page {
size: frame.size,
content: self.content,

View File

@ -656,7 +656,7 @@ mod cff {
if count > 0 {
let offsize = usize::from(s.read::<u8>()?);
if offsize < 1 || offsize > 4 {
if !matches!(offsize, 1 ..= 4) {
return None;
}

View File

@ -72,7 +72,7 @@ impl RgbaColor {
}
impl FromStr for RgbaColor {
type Err = ParseRgbaError;
type Err = RgbaError;
/// Constructs a new color from hex strings like the following:
/// - `#aef` (shorthand, with leading hashtag),
@ -83,7 +83,7 @@ impl FromStr for RgbaColor {
fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
let hex_str = hex_str.strip_prefix('#').unwrap_or(hex_str);
if !hex_str.is_ascii() {
return Err(ParseRgbaError);
return Err(RgbaError);
}
let len = hex_str.len();
@ -92,7 +92,7 @@ impl FromStr for RgbaColor {
let alpha = len == 4 || len == 8;
if !long && !short {
return Err(ParseRgbaError);
return Err(RgbaError);
}
let mut values: [u8; 4] = [255; 4];
@ -102,7 +102,7 @@ impl FromStr for RgbaColor {
let pos = elem * item_len;
let item = &hex_str[pos .. (pos + item_len)];
values[elem] = u8::from_str_radix(item, 16).map_err(|_| ParseRgbaError)?;
values[elem] = u8::from_str_radix(item, 16).map_err(|_| RgbaError)?;
if short {
// Duplicate number for shorthand notation, i.e. `a` -> `aa`
@ -134,15 +134,15 @@ impl Debug for RgbaColor {
/// The error when parsing an [`RgbaColor`] from a string fails.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ParseRgbaError;
pub struct RgbaError;
impl Display for ParseRgbaError {
impl Display for RgbaError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("invalid color")
f.pad("invalid hex string")
}
}
impl std::error::Error for ParseRgbaError {}
impl std::error::Error for RgbaError {}
#[cfg(test)]
mod tests {
@ -166,7 +166,7 @@ mod tests {
fn test_parse_invalid_colors() {
#[track_caller]
fn test(hex: &str) {
assert_eq!(RgbaColor::from_str(hex), Err(ParseRgbaError));
assert_eq!(RgbaColor::from_str(hex), Err(RgbaError));
}
test("12345");

View File

@ -27,7 +27,7 @@ impl Debug for Scalar {
impl Ord for Scalar {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(&other).expect("float is NaN")
self.partial_cmp(other).expect("float is NaN")
}
}

View File

@ -67,7 +67,7 @@ impl ImageStore {
Entry::Vacant(entry) => {
let buffer = self.loader.load(path)?;
let ext = path.extension().and_then(OsStr::to_str).unwrap_or_default();
let image = Image::parse(&buffer, &ext)?;
let image = Image::parse(&buffer, ext)?;
let id = ImageId(self.images.len() as u32);
if let Some(callback) = &self.on_load {
callback(id, &image);

View File

@ -377,22 +377,14 @@ pub struct PatternProperties {
impl PatternProperties {
/// Check if it is vital to keep an entry based on its properties.
pub fn must_keep(&self) -> bool {
if self.top_level && !self.mature {
// Keep an undo stack.
true
} else if self.all_zeros && !self.mature {
// Keep the most recently created items, even if they have not yet
// been used.
true
} else if self.multi_use && !self.abandoned {
true
} else if self.hit {
true
} else if self.sparse {
true
} else {
false
}
// Keep an undo stack.
(self.top_level && !self.mature)
// Keep the most recently created items, even if they have not yet
// been used.
|| (self.all_zeros && !self.mature)
|| (self.multi_use && !self.abandoned)
|| self.hit
|| self.sparse
}
}

View File

@ -282,7 +282,10 @@ impl Debug for PackedNode {
impl PartialEq for PackedNode {
fn eq(&self, other: &Self) -> bool {
Rc::as_ptr(&self.node) as *const () == Rc::as_ptr(&other.node) as *const ()
std::ptr::eq(
Rc::as_ptr(&self.node) as *const (),
Rc::as_ptr(&other.node) as *const (),
)
}
}

View File

@ -30,6 +30,10 @@
//! [cache]: layout::LayoutCache
//! [PDF]: export::pdf
#![allow(clippy::len_without_is_empty)]
#![allow(clippy::or_fun_call)]
#![allow(clippy::try_err)]
#[macro_use]
pub mod util;
#[macro_use]

View File

@ -6,16 +6,14 @@ use super::ParNode;
/// `align`: Configure the alignment along the layouting axes.
pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let aligns: Spec<_> = args.find().unwrap_or_default();
let body: Node = args.expect("body")?;
let body: PackedNode = args.expect("body")?;
let mut styles = Styles::new();
if let Some(align) = aligns.x {
styles.set(ParNode::ALIGN, align);
}
Ok(Value::block(
body.into_block().styled(styles).aligned(aligns),
))
Ok(Value::block(body.styled(styles).aligned(aligns)))
}
dynamic! {

View File

@ -5,13 +5,10 @@ use super::ParNode;
/// `columns`: Set content into multiple columns.
pub fn columns(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let columns = args.expect("column count")?;
let gutter = args.named("gutter")?.unwrap_or(Relative::new(0.04).into());
let body: Node = args.expect("body")?;
Ok(Value::block(ColumnsNode {
columns,
gutter,
child: body.into_block(),
columns: args.expect("column count")?,
gutter: args.named("gutter")?.unwrap_or(Relative::new(0.04).into()),
child: args.expect("body")?,
}))
}

View File

@ -18,7 +18,7 @@ impl Layout for FlowNode {
ctx: &mut LayoutContext,
regions: &Regions,
) -> Vec<Constrained<Rc<Frame>>> {
FlowLayouter::new(self, regions).layout(ctx)
FlowLayouter::new(self, regions.clone()).layout(ctx)
}
}
@ -32,12 +32,12 @@ impl Debug for FlowNode {
/// A child of a flow node.
#[derive(Hash)]
pub enum FlowChild {
/// A paragraph/block break.
Break(Styles),
/// Vertical spacing between other children.
Spacing(SpacingNode),
/// An arbitrary node.
Node(PackedNode),
/// A paragraph/block break.
Break(Styles),
/// Skip the rest of the region and move to the next.
Skip,
}
@ -46,9 +46,9 @@ impl FlowChild {
/// A reference to the child's styles.
pub fn styles(&self) -> Option<&Styles> {
match self {
Self::Break(styles) => Some(styles),
Self::Spacing(node) => Some(&node.styles),
Self::Node(node) => Some(&node.styles),
Self::Break(styles) => Some(styles),
Self::Skip => None,
}
}
@ -56,9 +56,9 @@ impl FlowChild {
/// A mutable reference to the child's styles.
pub fn styles_mut(&mut self) -> Option<&mut Styles> {
match self {
Self::Break(styles) => Some(styles),
Self::Spacing(node) => Some(&mut node.styles),
Self::Node(node) => Some(&mut node.styles),
Self::Break(styles) => Some(styles),
Self::Skip => None,
}
}
@ -67,14 +67,14 @@ impl FlowChild {
impl Debug for FlowChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Spacing(node) => node.fmt(f),
Self::Node(node) => node.fmt(f),
Self::Break(styles) => {
if f.alternate() {
styles.fmt(f)?;
}
write!(f, "Break")
}
Self::Spacing(node) => node.fmt(f),
Self::Node(node) => node.fmt(f),
Self::Skip => f.pad("Skip"),
}
}
@ -84,10 +84,10 @@ impl Debug for FlowChild {
struct FlowLayouter<'a> {
/// The flow node to layout.
children: &'a [FlowChild],
/// Whether the flow should expand to fill the region.
expand: Spec<bool>,
/// The regions to layout children into.
regions: Regions,
/// Whether the flow should expand to fill the region.
expand: Spec<bool>,
/// The full size of `regions.current` that was available before we started
/// subtracting.
full: Size,
@ -115,19 +115,18 @@ enum FlowItem {
impl<'a> FlowLayouter<'a> {
/// Create a new flow layouter.
fn new(flow: &'a FlowNode, regions: &Regions) -> Self {
fn new(flow: &'a FlowNode, mut regions: Regions) -> Self {
let expand = regions.expand;
let full = regions.current;
// Disable vertical expansion for children.
let mut regions = regions.clone();
regions.expand.y = false;
Self {
children: &flow.0,
regions,
expand,
full,
regions,
used: Size::zero(),
fr: Fractional::zero(),
items: vec![],
@ -139,6 +138,16 @@ impl<'a> FlowLayouter<'a> {
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
for child in self.children {
match child {
FlowChild::Spacing(node) => {
self.layout_spacing(node.kind);
}
FlowChild::Node(node) => {
if self.regions.is_full() {
self.finish_region();
}
self.layout_node(ctx, node);
}
FlowChild::Break(styles) => {
let chain = styles.chain(&ctx.styles);
let em = chain.get(TextNode::SIZE).abs;
@ -148,20 +157,6 @@ impl<'a> FlowLayouter<'a> {
FlowChild::Skip => {
self.finish_region();
}
FlowChild::Spacing(node) => match node.kind {
SpacingKind::Linear(v) => self.layout_absolute(v),
SpacingKind::Fractional(v) => {
self.items.push(FlowItem::Fractional(v));
self.fr += v;
}
},
FlowChild::Node(node) => {
if self.regions.is_full() {
self.finish_region();
}
self.layout_node(ctx, node);
}
}
}
@ -169,6 +164,17 @@ impl<'a> FlowLayouter<'a> {
self.finished
}
/// Layout spacing.
fn layout_spacing(&mut self, spacing: SpacingKind) {
match spacing {
SpacingKind::Linear(v) => self.layout_absolute(v),
SpacingKind::Fractional(v) => {
self.items.push(FlowItem::Fractional(v));
self.fr += v;
}
}
}
/// Layout absolute spacing.
fn layout_absolute(&mut self, amount: Linear) {
// Resolve the linear, limiting it to the remaining available space.

View File

@ -15,7 +15,7 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
column_gutter.unwrap_or_else(|| base_gutter.clone()),
row_gutter.unwrap_or(base_gutter),
),
children: args.all().map(Node::into_block).collect(),
children: args.all().collect(),
}))
}
@ -87,8 +87,6 @@ castable! {
struct GridLayouter<'a> {
/// The children of the grid.
children: &'a [PackedNode],
/// Whether the grid should expand to fill the region.
expand: Spec<bool>,
/// The column tracks including gutter tracks.
cols: Vec<TrackSizing>,
/// The row tracks including gutter tracks.
@ -97,6 +95,10 @@ struct GridLayouter<'a> {
regions: Regions,
/// Resolved column sizes.
rcols: Vec<Length>,
/// Rows in the current region.
lrows: Vec<Row>,
/// Whether the grid should expand to fill the region.
expand: Spec<bool>,
/// The full height of the current region.
full: Length,
/// The used-up size of the current region. The horizontal size is
@ -104,8 +106,6 @@ struct GridLayouter<'a> {
used: Size,
/// The sum of fractional ratios in the current region.
fr: Fractional,
/// Rows in the current region.
lrows: Vec<Row>,
/// Constraints for the active region.
cts: Constraints,
/// Frames for finished regions.
@ -161,22 +161,26 @@ impl<'a> GridLayouter<'a> {
cols.pop();
rows.pop();
let expand = regions.expand;
let full = regions.current.y;
let rcols = vec![Length::zero(); cols.len()];
let lrows = vec![];
// We use the regions for auto row measurement. Since at that moment,
// columns are already sized, we can enable horizontal expansion.
let expand = regions.expand;
regions.expand = Spec::new(true, false);
Self {
children: &grid.children,
expand,
rcols: vec![Length::zero(); cols.len()],
cols,
rows,
full: regions.current.y,
regions,
rcols,
lrows,
expand,
full,
used: Size::zero(),
fr: Fractional::zero(),
lrows: vec![],
cts: Constraints::new(expand),
finished: vec![],
}

View File

@ -16,7 +16,7 @@ pub struct HeadingNode {
#[properties]
impl HeadingNode {
/// The heading's font family.
pub const FAMILY: Smart<String> = Smart::Auto;
pub const FAMILY: Smart<FontFamily> = Smart::Auto;
/// The fill color of heading in the text. Just the surrounding text color
/// if `auto`.
pub const FILL: Smart<Paint> = Smart::Auto;
@ -25,7 +25,7 @@ impl HeadingNode {
impl Construct for HeadingNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
Ok(Node::block(Self {
child: args.expect::<Node>("body")?.into_block(),
child: args.expect("body")?,
level: args.named("level")?.unwrap_or(1),
}))
}
@ -50,8 +50,9 @@ impl Layout for HeadingNode {
ctx.styles.set(TextNode::SIZE, Relative::new(upscale).into());
if let Smart::Custom(family) = ctx.styles.get_ref(Self::FAMILY) {
let list: Vec<_> = std::iter::once(FontFamily::named(family))
.chain(ctx.styles.get_ref(TextNode::FAMILY_LIST).iter().cloned())
let list = std::iter::once(family)
.chain(ctx.styles.get_ref(TextNode::FAMILY_LIST))
.cloned()
.collect();
ctx.styles.set(TextNode::FAMILY_LIST, list);
}

View File

@ -26,12 +26,7 @@ impl<L: Labelling> Construct for ListNode<L> {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
Ok(args
.all()
.map(|node: Node| {
Node::block(Self {
child: node.into_block(),
labelling: L::default(),
})
})
.map(|child: PackedNode| Node::block(Self { child, labelling: L::default() }))
.sum())
}
}

View File

@ -193,3 +193,9 @@ castable! {
Expected: "string",
Value::Str(string) => string.into(),
}
castable! {
PackedNode,
Expected: "node",
Value::Node(node) => node.into_block(),
}

View File

@ -9,7 +9,7 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let top = args.named("top")?;
let right = args.named("right")?;
let bottom = args.named("bottom")?;
let body: Node = args.expect("body")?;
let body: PackedNode = args.expect("body")?;
let padding = Sides::new(
left.or(all).unwrap_or_default(),
top.or(all).unwrap_or_default(),
@ -17,7 +17,7 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
bottom.or(all).unwrap_or_default(),
);
Ok(Value::block(body.into_block().padded(padding)))
Ok(Value::block(body.padded(padding)))
}
/// A node that adds padding to its child.

View File

@ -44,8 +44,8 @@ impl PageNode {
impl Construct for PageNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
Ok(Node::Page(Self {
child: args.expect::<Node>("body")?.into_block(),
styles: Styles::new(),
child: args.expect("body")?,
}))
}
}
@ -114,6 +114,7 @@ impl PageNode {
bottom: ctx.styles.get(Self::BOTTOM).unwrap_or(default.bottom),
};
// Realize columns with columns node.
let columns = ctx.styles.get(Self::COLUMNS);
let child = if columns.get() > 1 {
ColumnsNode {
@ -126,14 +127,14 @@ impl PageNode {
self.child.clone()
};
// Pad the child.
let padded = PadNode { child, padding }.pack();
// Realize margins with padding node.
let child = PadNode { child, padding }.pack();
// Layout the child.
let expand = size.map(Length::is_finite);
let regions = Regions::repeat(size, size, expand);
let mut frames: Vec<_> =
padded.layout(ctx, &regions).into_iter().map(|c| c.item).collect();
child.layout(ctx, &regions).into_iter().map(|c| c.item).collect();
// Add background fill if requested.
if let Some(fill) = ctx.styles.get(Self::FILL) {
@ -238,12 +239,12 @@ macro_rules! papers {
}
impl FromStr for Paper {
type Err = ParsePaperError;
type Err = PaperError;
fn from_str(name: &str) -> Result<Self, Self::Err> {
match name.to_lowercase().as_str() {
$($($pats)* => Ok(Self::$var),)*
_ => Err(ParsePaperError),
_ => Err(PaperError),
}
}
}
@ -413,12 +414,12 @@ castable! {
/// The error when parsing a [`Paper`] from a string fails.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ParsePaperError;
pub struct PaperError;
impl Display for ParsePaperError {
impl Display for PaperError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("invalid paper name")
}
}
impl std::error::Error for ParsePaperError {}
impl std::error::Error for PaperError {}

View File

@ -30,7 +30,7 @@ impl ParNode {
impl Construct for ParNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
// Lift to a block so that it doesn't merge with adjacent stuff.
Ok(Node::Block(args.expect::<Node>("body")?.into_block()))
Ok(Node::Block(args.expect("body")?))
}
}
@ -60,10 +60,8 @@ impl Set for ParNode {
bail!(span, "must be horizontal");
}
Some(v)
} else if let Some(dir) = dir {
Some(if dir == Dir::LTR { Align::Left } else { Align::Right })
} else {
None
dir.map(|dir| dir.start().into())
};
styles.set_opt(Self::DIR, dir);
@ -85,7 +83,8 @@ impl Layout for ParNode {
let text = self.collect_text();
// Find out the BiDi embedding levels.
let bidi = BidiInfo::new(&text, Level::from_dir(ctx.styles.get(Self::DIR)));
let level = Level::from_dir(ctx.styles.get(Self::DIR));
let bidi = BidiInfo::new(&text, level);
// Prepare paragraph layout by building a representation on which we can
// do line breaking without layouting each and every line from scratch.
@ -255,7 +254,7 @@ impl<'a> ParLayouter<'a> {
let subrange = start .. cursor;
let text = &bidi.text[subrange.clone()];
let styles = node.styles.chain(&ctx.styles);
let shaped = shape(&mut ctx.fonts, text, styles, level.dir());
let shaped = shape(ctx.fonts, text, styles, level.dir());
items.push(ParItem::Text(shaped));
ranges.push(subrange);
}
@ -446,7 +445,7 @@ impl<'a> LineLayout<'a> {
// empty string.
if !range.is_empty() || rest.is_empty() {
// Reshape that part.
let reshaped = shaped.reshape(&mut ctx.fonts, range);
let reshaped = shaped.reshape(ctx.fonts, range);
last = Some(ParItem::Text(reshaped));
}
@ -467,7 +466,7 @@ impl<'a> LineLayout<'a> {
// Reshape if necessary.
if range.len() < shaped.text.len() {
if !range.is_empty() {
let reshaped = shaped.reshape(&mut ctx.fonts, range);
let reshaped = shaped.reshape(ctx.fonts, range);
first = Some(ParItem::Text(reshaped));
}
@ -531,7 +530,7 @@ impl<'a> LineLayout<'a> {
match item {
ParItem::Absolute(v) => offset += *v,
ParItem::Fractional(v) => offset += v.resolve(self.fr, remaining),
ParItem::Text(shaped) => position(shaped.build(&ctx.fonts)),
ParItem::Text(shaped) => position(shaped.build(ctx.fonts)),
ParItem::Frame(frame) => position(frame.clone()),
}
}

View File

@ -8,9 +8,9 @@ pub fn place(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let aligns = args.find().unwrap_or(Spec::new(Some(Align::Left), None));
let tx = args.named("dx")?.unwrap_or_default();
let ty = args.named("dy")?.unwrap_or_default();
let body: Node = args.expect("body")?;
let body: PackedNode = args.expect("body")?;
Ok(Value::block(PlacedNode(
body.into_block().moved(Point::new(tx, ty)).aligned(aligns),
body.moved(Point::new(tx, ty)).aligned(aligns),
)))
}

View File

@ -79,9 +79,7 @@ fn shape_impl(
}
// The shape's contents.
let child = args
.find()
.map(|body: Node| body.into_block().padded(Sides::splat(padding)));
let child = args.find().map(|body: PackedNode| body.padded(Sides::splat(padding)));
Ok(Value::inline(
ShapeNode { kind, fill, stroke, child }

View File

@ -6,16 +6,14 @@ use super::prelude::*;
pub fn box_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let width = args.named("width")?;
let height = args.named("height")?;
let body: Node = args.find().unwrap_or_default();
Ok(Value::inline(
body.into_block().sized(Spec::new(width, height)),
))
let body: PackedNode = args.find().unwrap_or_default();
Ok(Value::inline(body.sized(Spec::new(width, height))))
}
/// `block`: Place content into the flow.
pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let body: Node = args.find().unwrap_or_default();
Ok(Value::block(body.into_block()))
let body: PackedNode = args.find().unwrap_or_default();
Ok(Value::block(body))
}
/// A node that sizes its child.

View File

@ -1,33 +1,15 @@
//! Side-by-side layout of nodes along an axis.
use std::fmt::{self, Debug, Formatter};
use super::prelude::*;
use super::{AlignNode, SpacingKind, SpacingNode};
/// `stack`: Stack children along an axis.
pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let dir = args.named("dir")?.unwrap_or(Dir::TTB);
let spacing = args.named("spacing")?;
let mut children = vec![];
let mut deferred = None;
// Build the list of stack children.
for child in args.all() {
match child {
StackChild::Spacing(_) => deferred = None,
StackChild::Node(_) => {
if let Some(v) = deferred {
children.push(StackChild::spacing(v));
}
deferred = spacing;
}
}
children.push(child);
}
Ok(Value::block(StackNode { dir, children }))
Ok(Value::block(StackNode {
dir: args.named("dir")?.unwrap_or(Dir::TTB),
spacing: args.named("spacing")?,
children: args.all().collect(),
}))
}
/// A node that stacks its children.
@ -35,6 +17,8 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
pub struct StackNode {
/// The stacking direction.
pub dir: Dir,
/// The spacing between non-spacing children.
pub spacing: Option<SpacingKind>,
/// The children to be stacked.
pub children: Vec<StackChild>,
}
@ -45,7 +29,7 @@ impl Layout for StackNode {
ctx: &mut LayoutContext,
regions: &Regions,
) -> Vec<Constrained<Rc<Frame>>> {
StackLayouter::new(self, regions).layout(ctx)
StackLayouter::new(self, regions.clone()).layout(ctx)
}
}
@ -58,9 +42,8 @@ pub enum StackChild {
Node(PackedNode),
}
impl StackChild {
/// Create a spacing node from a spacing kind.
pub fn spacing(kind: SpacingKind) -> Self {
impl From<SpacingKind> for StackChild {
fn from(kind: SpacingKind) -> Self {
Self::Spacing(SpacingNode { kind, styles: Styles::new() })
}
}
@ -77,23 +60,27 @@ impl Debug for StackChild {
castable! {
StackChild,
Expected: "linear, fractional or template",
Value::Length(v) => Self::spacing(SpacingKind::Linear(v.into())),
Value::Relative(v) => Self::spacing(SpacingKind::Linear(v.into())),
Value::Linear(v) => Self::spacing(SpacingKind::Linear(v)),
Value::Fractional(v) => Self::spacing(SpacingKind::Fractional(v)),
Value::Length(v) => SpacingKind::Linear(v.into()).into(),
Value::Relative(v) => SpacingKind::Linear(v.into()).into(),
Value::Linear(v) => SpacingKind::Linear(v).into(),
Value::Fractional(v) => SpacingKind::Fractional(v).into(),
Value::Node(v) => Self::Node(v.into_block()),
}
/// Performs stack layout.
struct StackLayouter<'a> {
/// The stack node to layout.
stack: &'a StackNode,
/// The axis of the block direction.
/// The flow node to layout.
children: &'a [StackChild],
/// The stacking direction.
dir: Dir,
/// The axis of the stacking direction.
axis: SpecAxis,
/// Whether the stack should expand to fill the region.
expand: Spec<bool>,
/// The spacing between non-spacing children.
spacing: Option<SpacingKind>,
/// The regions to layout children into.
regions: Regions,
/// Whether the stack should expand to fill the region.
expand: Spec<bool>,
/// The full size of `regions.current` that was available before we started
/// subtracting.
full: Size,
@ -119,21 +106,23 @@ enum StackItem {
impl<'a> StackLayouter<'a> {
/// Create a new stack layouter.
fn new(stack: &'a StackNode, regions: &Regions) -> Self {
let axis = stack.dir.axis();
fn new(stack: &'a StackNode, mut regions: Regions) -> Self {
let dir = stack.dir;
let axis = dir.axis();
let expand = regions.expand;
let full = regions.current;
// Disable expansion along the block axis for children.
let mut regions = regions.clone();
regions.expand.set(axis, false);
Self {
stack,
children: &stack.children,
dir,
axis,
spacing: stack.spacing,
regions,
expand,
full,
regions,
used: Gen::zero(),
fr: Fractional::zero(),
items: vec![],
@ -143,21 +132,26 @@ impl<'a> StackLayouter<'a> {
/// Layout all children.
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
for child in &self.stack.children {
// Spacing to insert before the next node.
let mut deferred = None;
for child in self.children {
match child {
StackChild::Spacing(node) => match node.kind {
SpacingKind::Linear(v) => self.layout_absolute(v),
SpacingKind::Fractional(v) => {
self.items.push(StackItem::Fractional(v));
self.fr += v;
}
},
StackChild::Spacing(node) => {
self.layout_spacing(node.kind);
deferred = None;
}
StackChild::Node(node) => {
if let Some(kind) = deferred {
self.layout_spacing(kind);
}
if self.regions.is_full() {
self.finish_region();
}
self.layout_node(ctx, node);
deferred = self.spacing;
}
}
}
@ -166,6 +160,17 @@ impl<'a> StackLayouter<'a> {
self.finished
}
/// Layout spacing.
fn layout_spacing(&mut self, spacing: SpacingKind) {
match spacing {
SpacingKind::Linear(v) => self.layout_absolute(v),
SpacingKind::Fractional(v) => {
self.items.push(StackItem::Fractional(v));
self.fr += v;
}
}
}
/// Layout absolute spacing.
fn layout_absolute(&mut self, amount: Linear) {
// Resolve the linear, limiting it to the remaining available space.
@ -183,7 +188,7 @@ impl<'a> StackLayouter<'a> {
let align = node
.downcast::<AlignNode>()
.and_then(|node| node.aligns.get(self.axis))
.unwrap_or(self.stack.dir.start().into());
.unwrap_or(self.dir.start().into());
let frames = node.layout(ctx, &self.regions);
let len = frames.len();
@ -218,7 +223,7 @@ impl<'a> StackLayouter<'a> {
let mut output = Frame::new(size);
let mut cursor = Length::zero();
let mut ruler: Align = self.stack.dir.start().into();
let mut ruler: Align = self.dir.start().into();
// Place all frames.
for item in self.items.drain(..) {
@ -230,7 +235,7 @@ impl<'a> StackLayouter<'a> {
cursor += v.resolve(self.fr, remaining);
}
StackItem::Frame(frame, align) => {
if self.stack.dir.is_positive() {
if self.dir.is_positive() {
ruler = ruler.max(align);
} else {
ruler = ruler.min(align);
@ -240,7 +245,7 @@ impl<'a> StackLayouter<'a> {
let parent = size.get(self.axis);
let child = frame.size.get(self.axis);
let block = ruler.resolve(parent - self.used.main)
+ if self.stack.dir.is_positive() {
+ if self.dir.is_positive() {
cursor
} else {
self.used.main - child - cursor

View File

@ -173,13 +173,6 @@ pub enum FontFamily {
Named(NamedFamily),
}
impl FontFamily {
/// Create a named font family variant, directly from a string.
pub fn named(string: &str) -> Self {
Self::Named(NamedFamily::new(string))
}
}
impl Debug for FontFamily {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
@ -193,13 +186,13 @@ impl Debug for FontFamily {
dynamic! {
FontFamily: "font family",
Value::Str(string) => Self::named(&string),
Value::Str(string) => Self::Named(NamedFamily::new(&string)),
}
castable! {
Vec<FontFamily>,
Expected: "string, generic family or array thereof",
Value::Str(string) => vec![FontFamily::named(&string)],
Value::Str(string) => vec![FontFamily::Named(NamedFamily::new(&string))],
Value::Array(values) => {
values.into_iter().filter_map(|v| v.cast().ok()).collect()
},

View File

@ -28,15 +28,13 @@ pub fn rotate(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
}
fn transform_impl(args: &mut Args, transform: Transform) -> TypResult<Value> {
let body: Node = args.expect("body")?;
let body: PackedNode = args.expect("body")?;
let origin = args
.named("origin")?
.unwrap_or(Spec::splat(None))
.unwrap_or(Align::CENTER_HORIZON);
Ok(Value::inline(
body.into_block().transformed(transform, origin),
))
Ok(Value::inline(body.transformed(transform, origin)))
}
/// A node that transforms its child without affecting layout.

View File

@ -275,13 +275,13 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
Some(NodeKind::Error(_, _)) => {
p.eat();
Err(())
Err(ParseError)
}
// Nothing.
_ => {
p.expected("expression");
Err(())
Err(ParseError)
}
}
}
@ -428,7 +428,7 @@ fn item(p: &mut Parser) -> ParseResult<NodeKind> {
marker.end(p, error);
p.eat();
expr(p).ok();
Err(())
Err(ParseError)
}
})?;
@ -519,7 +519,7 @@ fn args(p: &mut Parser, direct: bool, brackets: bool) -> ParseResult {
Some(NodeKind::LeftBracket) if brackets => {}
_ => {
p.expected("argument list");
return Err(());
return Err(ParseError);
}
}
@ -689,7 +689,7 @@ fn ident(p: &mut Parser) -> ParseResult {
}
_ => {
p.expected("identifier");
Err(())
Err(ParseError)
}
}
}
@ -701,7 +701,7 @@ fn body(p: &mut Parser) -> ParseResult {
Some(NodeKind::LeftBrace) => block(p),
_ => {
p.expected_at("body");
return Err(());
return Err(ParseError);
}
}
Ok(())

View File

@ -1,13 +1,10 @@
use std::fmt::{self, Display, Formatter};
use std::mem;
use super::{TokenMode, Tokens};
use crate::syntax::{ErrorPos, Green, GreenData, GreenNode, NodeKind};
use crate::util::EcoString;
/// Allows parser methods to use the try operator. Not exposed as the parser
/// recovers from all errors.
pub(crate) type ParseResult<T = ()> = Result<T, ()>;
/// A convenient token-based parser.
pub struct Parser<'s> {
/// An iterator over the source tokens.
@ -121,7 +118,7 @@ impl<'s> Parser<'s> {
if !eaten {
self.expected_at(t.as_str());
}
if eaten { Ok(()) } else { Err(()) }
if eaten { Ok(()) } else { Err(ParseError) }
}
/// Eat, debug-asserting that the token is the given one.
@ -448,3 +445,19 @@ pub enum Group {
/// A group for import items, ended by a semicolon, line break or `from`.
Imports,
}
/// Allows parser methods to use the try operator. Never returned top-level
/// because the parser recovers from all errors.
pub type ParseResult<T = ()> = Result<T, ParseError>;
/// The error type for parsing.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ParseError;
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("failed to parse")
}
}
impl std::error::Error for ParseError {}

View File

@ -21,6 +21,7 @@ pub trait Pretty {
}
/// A buffer into which items can be pretty printed.
#[derive(Default)]
pub struct Printer {
buf: String,
}
@ -28,7 +29,7 @@ pub struct Printer {
impl Printer {
/// Create a new pretty printer.
pub fn new() -> Self {
Self { buf: String::new() }
Self::default()
}
/// Push a character into the buffer.