mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Make clippy a bit happier
This commit is contained in:
parent
fef5502517
commit
f5dcb84e36
@ -372,13 +372,13 @@ impl Packer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.par.styles.compatible(&styles, ParNode::has_property) {
|
if !self.par.styles.compatible(styles, ParNode::has_property) {
|
||||||
self.parbreak(None);
|
self.parbreak(None);
|
||||||
self.par.styles = styles.clone();
|
self.par.styles = styles.clone();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.par.styles.intersect(&styles);
|
self.par.styles.intersect(styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Break to a new page if the `styles` contain page styles that are
|
/// Break to a new page if the `styles` contain page styles that are
|
||||||
@ -389,7 +389,7 @@ impl Packer {
|
|||||||
return;
|
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.pagebreak();
|
||||||
self.flow.styles = styles.clone();
|
self.flow.styles = styles.clone();
|
||||||
return;
|
return;
|
||||||
|
@ -390,7 +390,7 @@ impl<'a> PageExporter<'a> {
|
|||||||
// Make the coordinate system start at the top-left.
|
// Make the coordinate system start at the top-left.
|
||||||
self.bottom = frame.size.y.to_f32();
|
self.bottom = frame.size.y.to_f32();
|
||||||
self.content.transform([1.0, 0.0, 0.0, -1.0, 0.0, self.bottom]);
|
self.content.transform([1.0, 0.0, 0.0, -1.0, 0.0, self.bottom]);
|
||||||
self.write_frame(&frame);
|
self.write_frame(frame);
|
||||||
Page {
|
Page {
|
||||||
size: frame.size,
|
size: frame.size,
|
||||||
content: self.content,
|
content: self.content,
|
||||||
|
@ -656,7 +656,7 @@ mod cff {
|
|||||||
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
let offsize = usize::from(s.read::<u8>()?);
|
let offsize = usize::from(s.read::<u8>()?);
|
||||||
if offsize < 1 || offsize > 4 {
|
if !matches!(offsize, 1 ..= 4) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ impl RgbaColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for RgbaColor {
|
impl FromStr for RgbaColor {
|
||||||
type Err = ParseRgbaError;
|
type Err = RgbaError;
|
||||||
|
|
||||||
/// Constructs a new color from hex strings like the following:
|
/// Constructs a new color from hex strings like the following:
|
||||||
/// - `#aef` (shorthand, with leading hashtag),
|
/// - `#aef` (shorthand, with leading hashtag),
|
||||||
@ -83,7 +83,7 @@ impl FromStr for RgbaColor {
|
|||||||
fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
|
fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
|
||||||
let hex_str = hex_str.strip_prefix('#').unwrap_or(hex_str);
|
let hex_str = hex_str.strip_prefix('#').unwrap_or(hex_str);
|
||||||
if !hex_str.is_ascii() {
|
if !hex_str.is_ascii() {
|
||||||
return Err(ParseRgbaError);
|
return Err(RgbaError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let len = hex_str.len();
|
let len = hex_str.len();
|
||||||
@ -92,7 +92,7 @@ impl FromStr for RgbaColor {
|
|||||||
let alpha = len == 4 || len == 8;
|
let alpha = len == 4 || len == 8;
|
||||||
|
|
||||||
if !long && !short {
|
if !long && !short {
|
||||||
return Err(ParseRgbaError);
|
return Err(RgbaError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut values: [u8; 4] = [255; 4];
|
let mut values: [u8; 4] = [255; 4];
|
||||||
@ -102,7 +102,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).map_err(|_| ParseRgbaError)?;
|
values[elem] = u8::from_str_radix(item, 16).map_err(|_| RgbaError)?;
|
||||||
|
|
||||||
if short {
|
if short {
|
||||||
// Duplicate number for shorthand notation, i.e. `a` -> `aa`
|
// 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.
|
/// The error when parsing an [`RgbaColor`] from a string fails.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[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 {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -166,7 +166,7 @@ mod tests {
|
|||||||
fn test_parse_invalid_colors() {
|
fn test_parse_invalid_colors() {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test(hex: &str) {
|
fn test(hex: &str) {
|
||||||
assert_eq!(RgbaColor::from_str(hex), Err(ParseRgbaError));
|
assert_eq!(RgbaColor::from_str(hex), Err(RgbaError));
|
||||||
}
|
}
|
||||||
|
|
||||||
test("12345");
|
test("12345");
|
||||||
|
@ -27,7 +27,7 @@ impl Debug for Scalar {
|
|||||||
|
|
||||||
impl Ord for Scalar {
|
impl Ord for Scalar {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.partial_cmp(&other).expect("float is NaN")
|
self.partial_cmp(other).expect("float is NaN")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ impl ImageStore {
|
|||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
let buffer = self.loader.load(path)?;
|
let buffer = self.loader.load(path)?;
|
||||||
let ext = path.extension().and_then(OsStr::to_str).unwrap_or_default();
|
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);
|
let id = ImageId(self.images.len() as u32);
|
||||||
if let Some(callback) = &self.on_load {
|
if let Some(callback) = &self.on_load {
|
||||||
callback(id, &image);
|
callback(id, &image);
|
||||||
|
@ -377,22 +377,14 @@ pub struct PatternProperties {
|
|||||||
impl PatternProperties {
|
impl PatternProperties {
|
||||||
/// Check if it is vital to keep an entry based on its properties.
|
/// Check if it is vital to keep an entry based on its properties.
|
||||||
pub fn must_keep(&self) -> bool {
|
pub fn must_keep(&self) -> bool {
|
||||||
if self.top_level && !self.mature {
|
|
||||||
// Keep an undo stack.
|
// Keep an undo stack.
|
||||||
true
|
(self.top_level && !self.mature)
|
||||||
} else if self.all_zeros && !self.mature {
|
|
||||||
// Keep the most recently created items, even if they have not yet
|
// Keep the most recently created items, even if they have not yet
|
||||||
// been used.
|
// been used.
|
||||||
true
|
|| (self.all_zeros && !self.mature)
|
||||||
} else if self.multi_use && !self.abandoned {
|
|| (self.multi_use && !self.abandoned)
|
||||||
true
|
|| self.hit
|
||||||
} else if self.hit {
|
|| self.sparse
|
||||||
true
|
|
||||||
} else if self.sparse {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,10 @@ impl Debug for PackedNode {
|
|||||||
|
|
||||||
impl PartialEq for PackedNode {
|
impl PartialEq for PackedNode {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
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 (),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,10 @@
|
|||||||
//! [cache]: layout::LayoutCache
|
//! [cache]: layout::LayoutCache
|
||||||
//! [PDF]: export::pdf
|
//! [PDF]: export::pdf
|
||||||
|
|
||||||
|
#![allow(clippy::len_without_is_empty)]
|
||||||
|
#![allow(clippy::or_fun_call)]
|
||||||
|
#![allow(clippy::try_err)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod util;
|
pub mod util;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -6,16 +6,14 @@ use super::ParNode;
|
|||||||
/// `align`: Configure the alignment along the layouting axes.
|
/// `align`: Configure the alignment along the layouting axes.
|
||||||
pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let aligns: Spec<_> = args.find().unwrap_or_default();
|
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();
|
let mut styles = Styles::new();
|
||||||
if let Some(align) = aligns.x {
|
if let Some(align) = aligns.x {
|
||||||
styles.set(ParNode::ALIGN, align);
|
styles.set(ParNode::ALIGN, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::block(
|
Ok(Value::block(body.styled(styles).aligned(aligns)))
|
||||||
body.into_block().styled(styles).aligned(aligns),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic! {
|
dynamic! {
|
||||||
|
@ -5,13 +5,10 @@ use super::ParNode;
|
|||||||
|
|
||||||
/// `columns`: Set content into multiple columns.
|
/// `columns`: Set content into multiple columns.
|
||||||
pub fn columns(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
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 {
|
Ok(Value::block(ColumnsNode {
|
||||||
columns,
|
columns: args.expect("column count")?,
|
||||||
gutter,
|
gutter: args.named("gutter")?.unwrap_or(Relative::new(0.04).into()),
|
||||||
child: body.into_block(),
|
child: args.expect("body")?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ impl Layout for FlowNode {
|
|||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Rc<Frame>>> {
|
) -> 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.
|
/// A child of a flow node.
|
||||||
#[derive(Hash)]
|
#[derive(Hash)]
|
||||||
pub enum FlowChild {
|
pub enum FlowChild {
|
||||||
/// A paragraph/block break.
|
|
||||||
Break(Styles),
|
|
||||||
/// Vertical spacing between other children.
|
/// Vertical spacing between other children.
|
||||||
Spacing(SpacingNode),
|
Spacing(SpacingNode),
|
||||||
/// An arbitrary node.
|
/// An arbitrary node.
|
||||||
Node(PackedNode),
|
Node(PackedNode),
|
||||||
|
/// A paragraph/block break.
|
||||||
|
Break(Styles),
|
||||||
/// Skip the rest of the region and move to the next.
|
/// Skip the rest of the region and move to the next.
|
||||||
Skip,
|
Skip,
|
||||||
}
|
}
|
||||||
@ -46,9 +46,9 @@ impl FlowChild {
|
|||||||
/// A reference to the child's styles.
|
/// A reference to the child's styles.
|
||||||
pub fn styles(&self) -> Option<&Styles> {
|
pub fn styles(&self) -> Option<&Styles> {
|
||||||
match self {
|
match self {
|
||||||
Self::Break(styles) => Some(styles),
|
|
||||||
Self::Spacing(node) => Some(&node.styles),
|
Self::Spacing(node) => Some(&node.styles),
|
||||||
Self::Node(node) => Some(&node.styles),
|
Self::Node(node) => Some(&node.styles),
|
||||||
|
Self::Break(styles) => Some(styles),
|
||||||
Self::Skip => None,
|
Self::Skip => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,9 +56,9 @@ impl FlowChild {
|
|||||||
/// A mutable reference to the child's styles.
|
/// A mutable reference to the child's styles.
|
||||||
pub fn styles_mut(&mut self) -> Option<&mut Styles> {
|
pub fn styles_mut(&mut self) -> Option<&mut Styles> {
|
||||||
match self {
|
match self {
|
||||||
Self::Break(styles) => Some(styles),
|
|
||||||
Self::Spacing(node) => Some(&mut node.styles),
|
Self::Spacing(node) => Some(&mut node.styles),
|
||||||
Self::Node(node) => Some(&mut node.styles),
|
Self::Node(node) => Some(&mut node.styles),
|
||||||
|
Self::Break(styles) => Some(styles),
|
||||||
Self::Skip => None,
|
Self::Skip => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,14 +67,14 @@ impl FlowChild {
|
|||||||
impl Debug for FlowChild {
|
impl Debug for FlowChild {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Spacing(node) => node.fmt(f),
|
||||||
|
Self::Node(node) => node.fmt(f),
|
||||||
Self::Break(styles) => {
|
Self::Break(styles) => {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
styles.fmt(f)?;
|
styles.fmt(f)?;
|
||||||
}
|
}
|
||||||
write!(f, "Break")
|
write!(f, "Break")
|
||||||
}
|
}
|
||||||
Self::Spacing(node) => node.fmt(f),
|
|
||||||
Self::Node(node) => node.fmt(f),
|
|
||||||
Self::Skip => f.pad("Skip"),
|
Self::Skip => f.pad("Skip"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,10 +84,10 @@ impl Debug for FlowChild {
|
|||||||
struct FlowLayouter<'a> {
|
struct FlowLayouter<'a> {
|
||||||
/// The flow node to layout.
|
/// The flow node to layout.
|
||||||
children: &'a [FlowChild],
|
children: &'a [FlowChild],
|
||||||
/// Whether the flow should expand to fill the region.
|
|
||||||
expand: Spec<bool>,
|
|
||||||
/// The regions to layout children into.
|
/// The regions to layout children into.
|
||||||
regions: Regions,
|
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
|
/// The full size of `regions.current` that was available before we started
|
||||||
/// subtracting.
|
/// subtracting.
|
||||||
full: Size,
|
full: Size,
|
||||||
@ -115,19 +115,18 @@ enum FlowItem {
|
|||||||
|
|
||||||
impl<'a> FlowLayouter<'a> {
|
impl<'a> FlowLayouter<'a> {
|
||||||
/// Create a new flow layouter.
|
/// 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 expand = regions.expand;
|
||||||
let full = regions.current;
|
let full = regions.current;
|
||||||
|
|
||||||
// Disable vertical expansion for children.
|
// Disable vertical expansion for children.
|
||||||
let mut regions = regions.clone();
|
|
||||||
regions.expand.y = false;
|
regions.expand.y = false;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
children: &flow.0,
|
children: &flow.0,
|
||||||
|
regions,
|
||||||
expand,
|
expand,
|
||||||
full,
|
full,
|
||||||
regions,
|
|
||||||
used: Size::zero(),
|
used: Size::zero(),
|
||||||
fr: Fractional::zero(),
|
fr: Fractional::zero(),
|
||||||
items: vec![],
|
items: vec![],
|
||||||
@ -139,6 +138,16 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
for child in self.children {
|
for child in self.children {
|
||||||
match child {
|
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) => {
|
FlowChild::Break(styles) => {
|
||||||
let chain = styles.chain(&ctx.styles);
|
let chain = styles.chain(&ctx.styles);
|
||||||
let em = chain.get(TextNode::SIZE).abs;
|
let em = chain.get(TextNode::SIZE).abs;
|
||||||
@ -148,20 +157,6 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
FlowChild::Skip => {
|
FlowChild::Skip => {
|
||||||
self.finish_region();
|
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
|
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.
|
/// Layout absolute spacing.
|
||||||
fn layout_absolute(&mut self, amount: Linear) {
|
fn layout_absolute(&mut self, amount: Linear) {
|
||||||
// Resolve the linear, limiting it to the remaining available space.
|
// Resolve the linear, limiting it to the remaining available space.
|
||||||
|
@ -15,7 +15,7 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
column_gutter.unwrap_or_else(|| base_gutter.clone()),
|
column_gutter.unwrap_or_else(|| base_gutter.clone()),
|
||||||
row_gutter.unwrap_or(base_gutter),
|
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> {
|
struct GridLayouter<'a> {
|
||||||
/// The children of the grid.
|
/// The children of the grid.
|
||||||
children: &'a [PackedNode],
|
children: &'a [PackedNode],
|
||||||
/// Whether the grid should expand to fill the region.
|
|
||||||
expand: Spec<bool>,
|
|
||||||
/// The column tracks including gutter tracks.
|
/// The column tracks including gutter tracks.
|
||||||
cols: Vec<TrackSizing>,
|
cols: Vec<TrackSizing>,
|
||||||
/// The row tracks including gutter tracks.
|
/// The row tracks including gutter tracks.
|
||||||
@ -97,6 +95,10 @@ struct GridLayouter<'a> {
|
|||||||
regions: Regions,
|
regions: Regions,
|
||||||
/// Resolved column sizes.
|
/// Resolved column sizes.
|
||||||
rcols: Vec<Length>,
|
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.
|
/// The full height of the current region.
|
||||||
full: Length,
|
full: Length,
|
||||||
/// The used-up size of the current region. The horizontal size is
|
/// The used-up size of the current region. The horizontal size is
|
||||||
@ -104,8 +106,6 @@ struct GridLayouter<'a> {
|
|||||||
used: Size,
|
used: Size,
|
||||||
/// The sum of fractional ratios in the current region.
|
/// The sum of fractional ratios in the current region.
|
||||||
fr: Fractional,
|
fr: Fractional,
|
||||||
/// Rows in the current region.
|
|
||||||
lrows: Vec<Row>,
|
|
||||||
/// Constraints for the active region.
|
/// Constraints for the active region.
|
||||||
cts: Constraints,
|
cts: Constraints,
|
||||||
/// Frames for finished regions.
|
/// Frames for finished regions.
|
||||||
@ -161,22 +161,26 @@ impl<'a> GridLayouter<'a> {
|
|||||||
cols.pop();
|
cols.pop();
|
||||||
rows.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,
|
// We use the regions for auto row measurement. Since at that moment,
|
||||||
// columns are already sized, we can enable horizontal expansion.
|
// columns are already sized, we can enable horizontal expansion.
|
||||||
let expand = regions.expand;
|
|
||||||
regions.expand = Spec::new(true, false);
|
regions.expand = Spec::new(true, false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
children: &grid.children,
|
children: &grid.children,
|
||||||
expand,
|
|
||||||
rcols: vec![Length::zero(); cols.len()],
|
|
||||||
cols,
|
cols,
|
||||||
rows,
|
rows,
|
||||||
full: regions.current.y,
|
|
||||||
regions,
|
regions,
|
||||||
|
rcols,
|
||||||
|
lrows,
|
||||||
|
expand,
|
||||||
|
full,
|
||||||
used: Size::zero(),
|
used: Size::zero(),
|
||||||
fr: Fractional::zero(),
|
fr: Fractional::zero(),
|
||||||
lrows: vec![],
|
|
||||||
cts: Constraints::new(expand),
|
cts: Constraints::new(expand),
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ pub struct HeadingNode {
|
|||||||
#[properties]
|
#[properties]
|
||||||
impl HeadingNode {
|
impl HeadingNode {
|
||||||
/// The heading's font family.
|
/// 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
|
/// The fill color of heading in the text. Just the surrounding text color
|
||||||
/// if `auto`.
|
/// if `auto`.
|
||||||
pub const FILL: Smart<Paint> = Smart::Auto;
|
pub const FILL: Smart<Paint> = Smart::Auto;
|
||||||
@ -25,7 +25,7 @@ impl HeadingNode {
|
|||||||
impl Construct for HeadingNode {
|
impl Construct for HeadingNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
||||||
Ok(Node::block(Self {
|
Ok(Node::block(Self {
|
||||||
child: args.expect::<Node>("body")?.into_block(),
|
child: args.expect("body")?,
|
||||||
level: args.named("level")?.unwrap_or(1),
|
level: args.named("level")?.unwrap_or(1),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -50,8 +50,9 @@ impl Layout for HeadingNode {
|
|||||||
ctx.styles.set(TextNode::SIZE, Relative::new(upscale).into());
|
ctx.styles.set(TextNode::SIZE, Relative::new(upscale).into());
|
||||||
|
|
||||||
if let Smart::Custom(family) = ctx.styles.get_ref(Self::FAMILY) {
|
if let Smart::Custom(family) = ctx.styles.get_ref(Self::FAMILY) {
|
||||||
let list: Vec<_> = std::iter::once(FontFamily::named(family))
|
let list = std::iter::once(family)
|
||||||
.chain(ctx.styles.get_ref(TextNode::FAMILY_LIST).iter().cloned())
|
.chain(ctx.styles.get_ref(TextNode::FAMILY_LIST))
|
||||||
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
ctx.styles.set(TextNode::FAMILY_LIST, list);
|
ctx.styles.set(TextNode::FAMILY_LIST, list);
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,7 @@ impl<L: Labelling> Construct for ListNode<L> {
|
|||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
||||||
Ok(args
|
Ok(args
|
||||||
.all()
|
.all()
|
||||||
.map(|node: Node| {
|
.map(|child: PackedNode| Node::block(Self { child, labelling: L::default() }))
|
||||||
Node::block(Self {
|
|
||||||
child: node.into_block(),
|
|
||||||
labelling: L::default(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.sum())
|
.sum())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,3 +193,9 @@ castable! {
|
|||||||
Expected: "string",
|
Expected: "string",
|
||||||
Value::Str(string) => string.into(),
|
Value::Str(string) => string.into(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
castable! {
|
||||||
|
PackedNode,
|
||||||
|
Expected: "node",
|
||||||
|
Value::Node(node) => node.into_block(),
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
let top = args.named("top")?;
|
let top = args.named("top")?;
|
||||||
let right = args.named("right")?;
|
let right = args.named("right")?;
|
||||||
let bottom = args.named("bottom")?;
|
let bottom = args.named("bottom")?;
|
||||||
let body: Node = args.expect("body")?;
|
let body: PackedNode = args.expect("body")?;
|
||||||
let padding = Sides::new(
|
let padding = Sides::new(
|
||||||
left.or(all).unwrap_or_default(),
|
left.or(all).unwrap_or_default(),
|
||||||
top.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(),
|
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.
|
/// A node that adds padding to its child.
|
||||||
|
@ -44,8 +44,8 @@ impl PageNode {
|
|||||||
impl Construct for PageNode {
|
impl Construct for PageNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
||||||
Ok(Node::Page(Self {
|
Ok(Node::Page(Self {
|
||||||
child: args.expect::<Node>("body")?.into_block(),
|
|
||||||
styles: Styles::new(),
|
styles: Styles::new(),
|
||||||
|
child: args.expect("body")?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,6 +114,7 @@ impl PageNode {
|
|||||||
bottom: ctx.styles.get(Self::BOTTOM).unwrap_or(default.bottom),
|
bottom: ctx.styles.get(Self::BOTTOM).unwrap_or(default.bottom),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Realize columns with columns node.
|
||||||
let columns = ctx.styles.get(Self::COLUMNS);
|
let columns = ctx.styles.get(Self::COLUMNS);
|
||||||
let child = if columns.get() > 1 {
|
let child = if columns.get() > 1 {
|
||||||
ColumnsNode {
|
ColumnsNode {
|
||||||
@ -126,14 +127,14 @@ impl PageNode {
|
|||||||
self.child.clone()
|
self.child.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pad the child.
|
// Realize margins with padding node.
|
||||||
let padded = PadNode { child, padding }.pack();
|
let child = PadNode { child, padding }.pack();
|
||||||
|
|
||||||
// Layout the child.
|
// Layout the child.
|
||||||
let expand = size.map(Length::is_finite);
|
let expand = size.map(Length::is_finite);
|
||||||
let regions = Regions::repeat(size, size, expand);
|
let regions = Regions::repeat(size, size, expand);
|
||||||
let mut frames: Vec<_> =
|
let mut frames: Vec<_> =
|
||||||
padded.layout(ctx, ®ions).into_iter().map(|c| c.item).collect();
|
child.layout(ctx, ®ions).into_iter().map(|c| c.item).collect();
|
||||||
|
|
||||||
// Add background fill if requested.
|
// Add background fill if requested.
|
||||||
if let Some(fill) = ctx.styles.get(Self::FILL) {
|
if let Some(fill) = ctx.styles.get(Self::FILL) {
|
||||||
@ -238,12 +239,12 @@ macro_rules! papers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Paper {
|
impl FromStr for Paper {
|
||||||
type Err = ParsePaperError;
|
type Err = PaperError;
|
||||||
|
|
||||||
fn from_str(name: &str) -> Result<Self, Self::Err> {
|
fn from_str(name: &str) -> Result<Self, Self::Err> {
|
||||||
match name.to_lowercase().as_str() {
|
match name.to_lowercase().as_str() {
|
||||||
$($($pats)* => Ok(Self::$var),)*
|
$($($pats)* => Ok(Self::$var),)*
|
||||||
_ => Err(ParsePaperError),
|
_ => Err(PaperError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,12 +414,12 @@ castable! {
|
|||||||
|
|
||||||
/// The error when parsing a [`Paper`] from a string fails.
|
/// The error when parsing a [`Paper`] from a string fails.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[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 {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.pad("invalid paper name")
|
f.pad("invalid paper name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for ParsePaperError {}
|
impl std::error::Error for PaperError {}
|
||||||
|
@ -30,7 +30,7 @@ impl ParNode {
|
|||||||
impl Construct for ParNode {
|
impl Construct for ParNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
||||||
// Lift to a block so that it doesn't merge with adjacent stuff.
|
// 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");
|
bail!(span, "must be horizontal");
|
||||||
}
|
}
|
||||||
Some(v)
|
Some(v)
|
||||||
} else if let Some(dir) = dir {
|
|
||||||
Some(if dir == Dir::LTR { Align::Left } else { Align::Right })
|
|
||||||
} else {
|
} else {
|
||||||
None
|
dir.map(|dir| dir.start().into())
|
||||||
};
|
};
|
||||||
|
|
||||||
styles.set_opt(Self::DIR, dir);
|
styles.set_opt(Self::DIR, dir);
|
||||||
@ -85,7 +83,8 @@ impl Layout for ParNode {
|
|||||||
let text = self.collect_text();
|
let text = self.collect_text();
|
||||||
|
|
||||||
// Find out the BiDi embedding levels.
|
// 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
|
// Prepare paragraph layout by building a representation on which we can
|
||||||
// do line breaking without layouting each and every line from scratch.
|
// do line breaking without layouting each and every line from scratch.
|
||||||
@ -255,7 +254,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
let subrange = start .. cursor;
|
let subrange = start .. cursor;
|
||||||
let text = &bidi.text[subrange.clone()];
|
let text = &bidi.text[subrange.clone()];
|
||||||
let styles = node.styles.chain(&ctx.styles);
|
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));
|
items.push(ParItem::Text(shaped));
|
||||||
ranges.push(subrange);
|
ranges.push(subrange);
|
||||||
}
|
}
|
||||||
@ -446,7 +445,7 @@ impl<'a> LineLayout<'a> {
|
|||||||
// empty string.
|
// empty string.
|
||||||
if !range.is_empty() || rest.is_empty() {
|
if !range.is_empty() || rest.is_empty() {
|
||||||
// Reshape that part.
|
// Reshape that part.
|
||||||
let reshaped = shaped.reshape(&mut ctx.fonts, range);
|
let reshaped = shaped.reshape(ctx.fonts, range);
|
||||||
last = Some(ParItem::Text(reshaped));
|
last = Some(ParItem::Text(reshaped));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,7 +466,7 @@ impl<'a> LineLayout<'a> {
|
|||||||
// Reshape if necessary.
|
// Reshape if necessary.
|
||||||
if range.len() < shaped.text.len() {
|
if range.len() < shaped.text.len() {
|
||||||
if !range.is_empty() {
|
if !range.is_empty() {
|
||||||
let reshaped = shaped.reshape(&mut ctx.fonts, range);
|
let reshaped = shaped.reshape(ctx.fonts, range);
|
||||||
first = Some(ParItem::Text(reshaped));
|
first = Some(ParItem::Text(reshaped));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,7 +530,7 @@ impl<'a> LineLayout<'a> {
|
|||||||
match item {
|
match item {
|
||||||
ParItem::Absolute(v) => offset += *v,
|
ParItem::Absolute(v) => offset += *v,
|
||||||
ParItem::Fractional(v) => offset += v.resolve(self.fr, remaining),
|
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()),
|
ParItem::Frame(frame) => position(frame.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 aligns = args.find().unwrap_or(Spec::new(Some(Align::Left), None));
|
||||||
let tx = args.named("dx")?.unwrap_or_default();
|
let tx = args.named("dx")?.unwrap_or_default();
|
||||||
let ty = args.named("dy")?.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(
|
Ok(Value::block(PlacedNode(
|
||||||
body.into_block().moved(Point::new(tx, ty)).aligned(aligns),
|
body.moved(Point::new(tx, ty)).aligned(aligns),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,9 +79,7 @@ fn shape_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The shape's contents.
|
// The shape's contents.
|
||||||
let child = args
|
let child = args.find().map(|body: PackedNode| body.padded(Sides::splat(padding)));
|
||||||
.find()
|
|
||||||
.map(|body: Node| body.into_block().padded(Sides::splat(padding)));
|
|
||||||
|
|
||||||
Ok(Value::inline(
|
Ok(Value::inline(
|
||||||
ShapeNode { kind, fill, stroke, child }
|
ShapeNode { kind, fill, stroke, child }
|
||||||
|
@ -6,16 +6,14 @@ use super::prelude::*;
|
|||||||
pub fn box_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn box_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let width = args.named("width")?;
|
let width = args.named("width")?;
|
||||||
let height = args.named("height")?;
|
let height = args.named("height")?;
|
||||||
let body: Node = args.find().unwrap_or_default();
|
let body: PackedNode = args.find().unwrap_or_default();
|
||||||
Ok(Value::inline(
|
Ok(Value::inline(body.sized(Spec::new(width, height))))
|
||||||
body.into_block().sized(Spec::new(width, height)),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `block`: Place content into the flow.
|
/// `block`: Place content into the flow.
|
||||||
pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let body: Node = args.find().unwrap_or_default();
|
let body: PackedNode = args.find().unwrap_or_default();
|
||||||
Ok(Value::block(body.into_block()))
|
Ok(Value::block(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node that sizes its child.
|
/// A node that sizes its child.
|
||||||
|
@ -1,33 +1,15 @@
|
|||||||
//! Side-by-side layout of nodes along an axis.
|
//! Side-by-side layout of nodes along an axis.
|
||||||
|
|
||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::{AlignNode, SpacingKind, SpacingNode};
|
use super::{AlignNode, SpacingKind, SpacingNode};
|
||||||
|
|
||||||
/// `stack`: Stack children along an axis.
|
/// `stack`: Stack children along an axis.
|
||||||
pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let dir = args.named("dir")?.unwrap_or(Dir::TTB);
|
Ok(Value::block(StackNode {
|
||||||
let spacing = args.named("spacing")?;
|
dir: args.named("dir")?.unwrap_or(Dir::TTB),
|
||||||
|
spacing: args.named("spacing")?,
|
||||||
let mut children = vec![];
|
children: args.all().collect(),
|
||||||
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 }))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node that stacks its children.
|
/// A node that stacks its children.
|
||||||
@ -35,6 +17,8 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
pub struct StackNode {
|
pub struct StackNode {
|
||||||
/// The stacking direction.
|
/// The stacking direction.
|
||||||
pub dir: Dir,
|
pub dir: Dir,
|
||||||
|
/// The spacing between non-spacing children.
|
||||||
|
pub spacing: Option<SpacingKind>,
|
||||||
/// The children to be stacked.
|
/// The children to be stacked.
|
||||||
pub children: Vec<StackChild>,
|
pub children: Vec<StackChild>,
|
||||||
}
|
}
|
||||||
@ -45,7 +29,7 @@ impl Layout for StackNode {
|
|||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Rc<Frame>>> {
|
) -> 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),
|
Node(PackedNode),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackChild {
|
impl From<SpacingKind> for StackChild {
|
||||||
/// Create a spacing node from a spacing kind.
|
fn from(kind: SpacingKind) -> Self {
|
||||||
pub fn spacing(kind: SpacingKind) -> Self {
|
|
||||||
Self::Spacing(SpacingNode { kind, styles: Styles::new() })
|
Self::Spacing(SpacingNode { kind, styles: Styles::new() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,23 +60,27 @@ impl Debug for StackChild {
|
|||||||
castable! {
|
castable! {
|
||||||
StackChild,
|
StackChild,
|
||||||
Expected: "linear, fractional or template",
|
Expected: "linear, fractional or template",
|
||||||
Value::Length(v) => Self::spacing(SpacingKind::Linear(v.into())),
|
Value::Length(v) => SpacingKind::Linear(v.into()).into(),
|
||||||
Value::Relative(v) => Self::spacing(SpacingKind::Linear(v.into())),
|
Value::Relative(v) => SpacingKind::Linear(v.into()).into(),
|
||||||
Value::Linear(v) => Self::spacing(SpacingKind::Linear(v)),
|
Value::Linear(v) => SpacingKind::Linear(v).into(),
|
||||||
Value::Fractional(v) => Self::spacing(SpacingKind::Fractional(v)),
|
Value::Fractional(v) => SpacingKind::Fractional(v).into(),
|
||||||
Value::Node(v) => Self::Node(v.into_block()),
|
Value::Node(v) => Self::Node(v.into_block()),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs stack layout.
|
/// Performs stack layout.
|
||||||
struct StackLayouter<'a> {
|
struct StackLayouter<'a> {
|
||||||
/// The stack node to layout.
|
/// The flow node to layout.
|
||||||
stack: &'a StackNode,
|
children: &'a [StackChild],
|
||||||
/// The axis of the block direction.
|
/// The stacking direction.
|
||||||
|
dir: Dir,
|
||||||
|
/// The axis of the stacking direction.
|
||||||
axis: SpecAxis,
|
axis: SpecAxis,
|
||||||
/// Whether the stack should expand to fill the region.
|
/// The spacing between non-spacing children.
|
||||||
expand: Spec<bool>,
|
spacing: Option<SpacingKind>,
|
||||||
/// The regions to layout children into.
|
/// The regions to layout children into.
|
||||||
regions: Regions,
|
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
|
/// The full size of `regions.current` that was available before we started
|
||||||
/// subtracting.
|
/// subtracting.
|
||||||
full: Size,
|
full: Size,
|
||||||
@ -119,21 +106,23 @@ enum StackItem {
|
|||||||
|
|
||||||
impl<'a> StackLayouter<'a> {
|
impl<'a> StackLayouter<'a> {
|
||||||
/// Create a new stack layouter.
|
/// Create a new stack layouter.
|
||||||
fn new(stack: &'a StackNode, regions: &Regions) -> Self {
|
fn new(stack: &'a StackNode, mut regions: Regions) -> Self {
|
||||||
let axis = stack.dir.axis();
|
let dir = stack.dir;
|
||||||
|
let axis = dir.axis();
|
||||||
let expand = regions.expand;
|
let expand = regions.expand;
|
||||||
let full = regions.current;
|
let full = regions.current;
|
||||||
|
|
||||||
// Disable expansion along the block axis for children.
|
// Disable expansion along the block axis for children.
|
||||||
let mut regions = regions.clone();
|
|
||||||
regions.expand.set(axis, false);
|
regions.expand.set(axis, false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
stack,
|
children: &stack.children,
|
||||||
|
dir,
|
||||||
axis,
|
axis,
|
||||||
|
spacing: stack.spacing,
|
||||||
|
regions,
|
||||||
expand,
|
expand,
|
||||||
full,
|
full,
|
||||||
regions,
|
|
||||||
used: Gen::zero(),
|
used: Gen::zero(),
|
||||||
fr: Fractional::zero(),
|
fr: Fractional::zero(),
|
||||||
items: vec![],
|
items: vec![],
|
||||||
@ -143,21 +132,26 @@ impl<'a> StackLayouter<'a> {
|
|||||||
|
|
||||||
/// Layout all children.
|
/// Layout all children.
|
||||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
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 {
|
match child {
|
||||||
StackChild::Spacing(node) => match node.kind {
|
StackChild::Spacing(node) => {
|
||||||
SpacingKind::Linear(v) => self.layout_absolute(v),
|
self.layout_spacing(node.kind);
|
||||||
SpacingKind::Fractional(v) => {
|
deferred = None;
|
||||||
self.items.push(StackItem::Fractional(v));
|
|
||||||
self.fr += v;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
StackChild::Node(node) => {
|
StackChild::Node(node) => {
|
||||||
|
if let Some(kind) = deferred {
|
||||||
|
self.layout_spacing(kind);
|
||||||
|
}
|
||||||
|
|
||||||
if self.regions.is_full() {
|
if self.regions.is_full() {
|
||||||
self.finish_region();
|
self.finish_region();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.layout_node(ctx, node);
|
self.layout_node(ctx, node);
|
||||||
|
deferred = self.spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,6 +160,17 @@ impl<'a> StackLayouter<'a> {
|
|||||||
self.finished
|
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.
|
/// Layout absolute spacing.
|
||||||
fn layout_absolute(&mut self, amount: Linear) {
|
fn layout_absolute(&mut self, amount: Linear) {
|
||||||
// Resolve the linear, limiting it to the remaining available space.
|
// Resolve the linear, limiting it to the remaining available space.
|
||||||
@ -183,7 +188,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
let align = node
|
let align = node
|
||||||
.downcast::<AlignNode>()
|
.downcast::<AlignNode>()
|
||||||
.and_then(|node| node.aligns.get(self.axis))
|
.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 frames = node.layout(ctx, &self.regions);
|
||||||
let len = frames.len();
|
let len = frames.len();
|
||||||
@ -218,7 +223,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
|
|
||||||
let mut output = Frame::new(size);
|
let mut output = Frame::new(size);
|
||||||
let mut cursor = Length::zero();
|
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.
|
// Place all frames.
|
||||||
for item in self.items.drain(..) {
|
for item in self.items.drain(..) {
|
||||||
@ -230,7 +235,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
cursor += v.resolve(self.fr, remaining);
|
cursor += v.resolve(self.fr, remaining);
|
||||||
}
|
}
|
||||||
StackItem::Frame(frame, align) => {
|
StackItem::Frame(frame, align) => {
|
||||||
if self.stack.dir.is_positive() {
|
if self.dir.is_positive() {
|
||||||
ruler = ruler.max(align);
|
ruler = ruler.max(align);
|
||||||
} else {
|
} else {
|
||||||
ruler = ruler.min(align);
|
ruler = ruler.min(align);
|
||||||
@ -240,7 +245,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
let parent = size.get(self.axis);
|
let parent = size.get(self.axis);
|
||||||
let child = frame.size.get(self.axis);
|
let child = frame.size.get(self.axis);
|
||||||
let block = ruler.resolve(parent - self.used.main)
|
let block = ruler.resolve(parent - self.used.main)
|
||||||
+ if self.stack.dir.is_positive() {
|
+ if self.dir.is_positive() {
|
||||||
cursor
|
cursor
|
||||||
} else {
|
} else {
|
||||||
self.used.main - child - cursor
|
self.used.main - child - cursor
|
||||||
|
@ -173,13 +173,6 @@ pub enum FontFamily {
|
|||||||
Named(NamedFamily),
|
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 {
|
impl Debug for FontFamily {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -193,13 +186,13 @@ impl Debug for FontFamily {
|
|||||||
|
|
||||||
dynamic! {
|
dynamic! {
|
||||||
FontFamily: "font family",
|
FontFamily: "font family",
|
||||||
Value::Str(string) => Self::named(&string),
|
Value::Str(string) => Self::Named(NamedFamily::new(&string)),
|
||||||
}
|
}
|
||||||
|
|
||||||
castable! {
|
castable! {
|
||||||
Vec<FontFamily>,
|
Vec<FontFamily>,
|
||||||
Expected: "string, generic family or array thereof",
|
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) => {
|
Value::Array(values) => {
|
||||||
values.into_iter().filter_map(|v| v.cast().ok()).collect()
|
values.into_iter().filter_map(|v| v.cast().ok()).collect()
|
||||||
},
|
},
|
||||||
|
@ -28,15 +28,13 @@ pub fn rotate(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn transform_impl(args: &mut Args, transform: Transform) -> 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
|
let origin = args
|
||||||
.named("origin")?
|
.named("origin")?
|
||||||
.unwrap_or(Spec::splat(None))
|
.unwrap_or(Spec::splat(None))
|
||||||
.unwrap_or(Align::CENTER_HORIZON);
|
.unwrap_or(Align::CENTER_HORIZON);
|
||||||
|
|
||||||
Ok(Value::inline(
|
Ok(Value::inline(body.transformed(transform, origin)))
|
||||||
body.into_block().transformed(transform, origin),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node that transforms its child without affecting layout.
|
/// A node that transforms its child without affecting layout.
|
||||||
|
@ -275,13 +275,13 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
|
|||||||
|
|
||||||
Some(NodeKind::Error(_, _)) => {
|
Some(NodeKind::Error(_, _)) => {
|
||||||
p.eat();
|
p.eat();
|
||||||
Err(())
|
Err(ParseError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing.
|
// Nothing.
|
||||||
_ => {
|
_ => {
|
||||||
p.expected("expression");
|
p.expected("expression");
|
||||||
Err(())
|
Err(ParseError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,7 +428,7 @@ fn item(p: &mut Parser) -> ParseResult<NodeKind> {
|
|||||||
marker.end(p, error);
|
marker.end(p, error);
|
||||||
p.eat();
|
p.eat();
|
||||||
expr(p).ok();
|
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 => {}
|
Some(NodeKind::LeftBracket) if brackets => {}
|
||||||
_ => {
|
_ => {
|
||||||
p.expected("argument list");
|
p.expected("argument list");
|
||||||
return Err(());
|
return Err(ParseError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,7 +689,7 @@ fn ident(p: &mut Parser) -> ParseResult {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
p.expected("identifier");
|
p.expected("identifier");
|
||||||
Err(())
|
Err(ParseError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -701,7 +701,7 @@ fn body(p: &mut Parser) -> ParseResult {
|
|||||||
Some(NodeKind::LeftBrace) => block(p),
|
Some(NodeKind::LeftBrace) => block(p),
|
||||||
_ => {
|
_ => {
|
||||||
p.expected_at("body");
|
p.expected_at("body");
|
||||||
return Err(());
|
return Err(ParseError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use super::{TokenMode, Tokens};
|
use super::{TokenMode, Tokens};
|
||||||
use crate::syntax::{ErrorPos, Green, GreenData, GreenNode, NodeKind};
|
use crate::syntax::{ErrorPos, Green, GreenData, GreenNode, NodeKind};
|
||||||
use crate::util::EcoString;
|
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.
|
/// A convenient token-based parser.
|
||||||
pub struct Parser<'s> {
|
pub struct Parser<'s> {
|
||||||
/// An iterator over the source tokens.
|
/// An iterator over the source tokens.
|
||||||
@ -121,7 +118,7 @@ impl<'s> Parser<'s> {
|
|||||||
if !eaten {
|
if !eaten {
|
||||||
self.expected_at(t.as_str());
|
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.
|
/// 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`.
|
/// A group for import items, ended by a semicolon, line break or `from`.
|
||||||
Imports,
|
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 {}
|
||||||
|
@ -21,6 +21,7 @@ pub trait Pretty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A buffer into which items can be pretty printed.
|
/// A buffer into which items can be pretty printed.
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Printer {
|
pub struct Printer {
|
||||||
buf: String,
|
buf: String,
|
||||||
}
|
}
|
||||||
@ -28,7 +29,7 @@ pub struct Printer {
|
|||||||
impl Printer {
|
impl Printer {
|
||||||
/// Create a new pretty printer.
|
/// Create a new pretty printer.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { buf: String::new() }
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a character into the buffer.
|
/// Push a character into the buffer.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user