diff --git a/src/model/collapse.rs b/src/model/collapse.rs index 5e7a25f88..18cfae8b9 100644 --- a/src/model/collapse.rs +++ b/src/model/collapse.rs @@ -2,8 +2,12 @@ use super::{StyleChain, StyleVec, StyleVecBuilder}; /// A wrapper around a [`StyleVecBuilder`] that allows to collapse items. pub struct CollapsingBuilder<'a, T> { + /// The internal builder. builder: StyleVecBuilder<'a, T>, + /// Staged weak and ignorant items that we can't yet commit to the builder. + /// The option is `Some(_)` for weak items and `None` for ignorant items. staged: Vec<(T, StyleChain<'a>, Option)>, + /// What the last non-ignorant item was. last: Last, } @@ -51,14 +55,14 @@ impl<'a, T> CollapsingBuilder<'a, T> { /// Forces nearby weak items to collapse. pub fn destructive(&mut self, item: T, styles: StyleChain<'a>) { self.flush(false); - self.push(item, styles); + self.builder.push(item, styles); self.last = Last::Destructive; } /// Allows nearby weak items to exist. pub fn supportive(&mut self, item: T, styles: StyleChain<'a>) { self.flush(true); - self.push(item, styles); + self.builder.push(item, styles); self.last = Last::Supportive; } @@ -78,7 +82,8 @@ impl<'a, T> CollapsingBuilder<'a, T> { self.builder.finish() } - /// Push the staged items, filtering out weak items if `supportive` is false. + /// Push the staged items, filtering out weak items if `supportive` is + /// false. fn flush(&mut self, supportive: bool) { for (item, styles, strength) in self.staged.drain(..) { if supportive || strength.is_none() { @@ -86,11 +91,6 @@ impl<'a, T> CollapsingBuilder<'a, T> { } } } - - /// Push a new item into the style vector. - fn push(&mut self, item: T, styles: StyleChain<'a>) { - self.builder.push(item, styles); - } } impl<'a, T> Default for CollapsingBuilder<'a, T> { diff --git a/src/model/content.rs b/src/model/content.rs index 04d5fc5f7..a7eb906a1 100644 --- a/src/model/content.rs +++ b/src/model/content.rs @@ -238,19 +238,11 @@ impl Debug for Content { Self::Horizontal(kind) => write!(f, "Horizontal({kind:?})"), Self::Text(text) => write!(f, "Text({text:?})"), Self::Quote(double) => write!(f, "Quote({double})"), - Self::Inline(node) => { - f.write_str("Inline(")?; - node.fmt(f)?; - f.write_str(")") - } + Self::Inline(node) => node.fmt(f), Self::Parbreak => f.pad("Parbreak"), Self::Colbreak => f.pad("Colbreak"), Self::Vertical(kind) => write!(f, "Vertical({kind:?})"), - Self::Block(node) => { - f.write_str("Block(")?; - node.fmt(f)?; - f.write_str(")") - } + Self::Block(node) => node.fmt(f), Self::List(item) => { f.write_str("- ")?; item.body.fmt(f) @@ -264,11 +256,7 @@ impl Debug for Content { } Self::Pagebreak(soft) => write!(f, "Pagebreak({soft})"), Self::Page(page) => page.fmt(f), - Self::Show(node) => { - f.write_str("Show(")?; - node.fmt(f)?; - f.write_str(")") - } + Self::Show(node) => node.fmt(f), Self::Styled(styled) => { let (sub, map) = styled.as_ref(); map.fmt(f)?; diff --git a/src/model/layout.rs b/src/model/layout.rs index 9a4d5df35..78bfedc7b 100644 --- a/src/model/layout.rs +++ b/src/model/layout.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Debug, Formatter}; use std::hash::Hash; use std::sync::Arc; -use super::{Barrier, NodeId, Resolve, StyleChain, StyleSlot}; +use super::{Barrier, NodeId, Resolve, StyleChain, StyleEntry}; use crate::diag::TypResult; use crate::eval::{RawAlign, RawLength}; use crate::frame::{Element, Frame, Geometry}; @@ -220,8 +220,8 @@ impl Layout for LayoutNode { styles: StyleChain, ) -> TypResult>> { ctx.query((self, regions, styles), |ctx, (node, regions, styles)| { - let slot = StyleSlot::from(Barrier::new(node.id())); - node.0.layout(ctx, regions, slot.chain(&styles)) + let entry = StyleEntry::Barrier(Barrier::new(node.id())); + node.0.layout(ctx, regions, entry.chain(&styles)) }) .clone() } diff --git a/src/model/styles.rs b/src/model/styles.rs index 8c9092a4d..7e5bfe944 100644 --- a/src/model/styles.rs +++ b/src/model/styles.rs @@ -16,7 +16,7 @@ use crate::Context; /// A map of style properties. #[derive(Default, Clone, PartialEq, Hash)] -pub struct StyleMap(Vec); +pub struct StyleMap(Vec); impl StyleMap { /// Create a new, empty style map. @@ -29,6 +29,11 @@ impl StyleMap { self.0.is_empty() } + /// Push an arbitary style entry. + pub fn push(&mut self, style: StyleEntry) { + self.0.push(style); + } + /// Create a style map from a single property-value pair. pub fn with<'a, K: Key<'a>>(key: K, value: K::Value) -> Self { let mut styles = Self::new(); @@ -42,7 +47,7 @@ impl StyleMap { /// style map, `self` contributes the outer values and `value` is the inner /// one. pub fn set<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) { - self.0.push(Entry::Property(Property::new(key, value))); + self.push(StyleEntry::Property(Property::new(key, value))); } /// Set an inner value for a style property if it is `Some(_)`. @@ -65,7 +70,7 @@ impl StyleMap { /// Set a show rule recipe for a node. pub fn set_recipe(&mut self, func: Func, span: Span) { - self.0.push(Entry::Recipe(Recipe::new::(func, span))); + self.push(StyleEntry::Recipe(Recipe::new::(func, span))); } /// Whether the map contains a style property for the given key. @@ -98,7 +103,7 @@ impl StyleMap { /// Like [`chain`](Self::chain) or [`apply_map`](Self::apply_map), but with /// only a single property. pub fn apply<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) { - self.0.insert(0, Entry::Property(Property::new(key, value))); + self.0.insert(0, StyleEntry::Property(Property::new(key, value))); } /// Apply styles from `tail` in-place. The resulting style map is equivalent @@ -115,7 +120,7 @@ impl StyleMap { /// not its children, too. This is used by [constructors](Node::construct). pub fn scoped(mut self) -> Self { for entry in &mut self.0 { - if let Entry::Property(property) = entry { + if let StyleEntry::Property(property) = entry { property.scoped = true; } } @@ -132,6 +137,12 @@ impl StyleMap { } } +impl From for StyleMap { + fn from(entry: StyleEntry) -> Self { + Self(vec![entry]) + } +} + impl Debug for StyleMap { fn fmt(&self, f: &mut Formatter) -> fmt::Result { for entry in self.0.iter().rev() { @@ -141,76 +152,6 @@ impl Debug for StyleMap { } } -/// A stack-allocated slot for a single style property or barrier. -pub struct StyleSlot(Entry); - -impl StyleSlot { - /// Make this slot the first link of the `tail` chain. - pub fn chain<'a>(&'a self, tail: &'a StyleChain) -> StyleChain<'a> { - if let Entry::Barrier(barrier) = &self.0 { - if !tail - .entries() - .filter_map(Entry::property) - .any(|p| p.scoped && p.node == barrier.0) - { - return *tail; - } - } - - StyleChain { - head: std::slice::from_ref(&self.0), - tail: Some(tail), - } - } -} - -impl From for StyleSlot { - fn from(barrier: Barrier) -> Self { - Self(Entry::Barrier(barrier)) - } -} - -/// An entry for a single style property, recipe or barrier. -#[derive(Clone, PartialEq, Hash)] -enum Entry { - /// A style property originating from a set rule or constructor. - Property(Property), - /// A barrier for scoped styles. - Barrier(Barrier), - /// A show rule recipe. - Recipe(Recipe), -} - -impl Entry { - /// If this is a property, return it. - fn property(&self) -> Option<&Property> { - match self { - Self::Property(property) => Some(property), - _ => None, - } - } - - /// If this is a recipe, return it. - fn recipe(&self) -> Option<&Recipe> { - match self { - Self::Recipe(recipe) => Some(recipe), - _ => None, - } - } -} - -impl Debug for Entry { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str("#[")?; - match self { - Self::Property(property) => property.fmt(f)?, - Self::Recipe(recipe) => recipe.fmt(f)?, - Self::Barrier(barrier) => barrier.fmt(f)?, - } - f.write_str("]") - } -} - /// A unique identifier for a node. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct NodeId(ReadableTypeId); @@ -245,9 +186,68 @@ impl Debug for KeyId { } } +/// An entry for a single style property, recipe or barrier. +#[derive(Clone, PartialEq, Hash)] +pub enum StyleEntry { + /// A style property originating from a set rule or constructor. + Property(Property), + /// A barrier for scoped styles. + Barrier(Barrier), + /// A show rule recipe. + Recipe(Recipe), +} + +impl StyleEntry { + /// If this is a property, return it. + pub fn property(&self) -> Option<&Property> { + match self { + Self::Property(property) => Some(property), + _ => None, + } + } + + /// If this is a recipe, return it. + pub fn recipe(&self) -> Option<&Recipe> { + match self { + Self::Recipe(recipe) => Some(recipe), + _ => None, + } + } + + /// Make this style the first link of the `tail` chain. + pub fn chain<'a>(&'a self, tail: &'a StyleChain) -> StyleChain<'a> { + if let StyleEntry::Barrier(barrier) = self { + if !tail + .entries() + .filter_map(StyleEntry::property) + .any(|p| p.scoped && p.node == barrier.0) + { + return *tail; + } + } + + StyleChain { + head: std::slice::from_ref(self), + tail: Some(tail), + } + } +} + +impl Debug for StyleEntry { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.write_str("#[")?; + match self { + Self::Property(property) => property.fmt(f)?, + Self::Recipe(recipe) => recipe.fmt(f)?, + Self::Barrier(barrier) => barrier.fmt(f)?, + } + f.write_str("]") + } +} + /// A style property originating from a set rule or constructor. #[derive(Clone, Hash)] -struct Property { +pub struct Property { /// The id of the property's [key](Key). key: KeyId, /// The id of the node the property belongs to. @@ -264,7 +264,7 @@ struct Property { impl Property { /// Create a new property from a key-value pair. - fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self { + pub fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self { Self { key: KeyId::of::(), node: K::node(), @@ -276,7 +276,7 @@ impl Property { } /// What kind of structure the property interrupts. - fn interruption(&self) -> Option { + pub fn interruption(&self) -> Option { if self.is_of::() { Some(Interruption::Page) } else if self.is_of::() { @@ -287,7 +287,7 @@ impl Property { } /// Access the property's value if it is of the given key. - fn downcast<'a, K: Key<'a>>(&'a self) -> Option<&'a K::Value> { + pub fn downcast<'a, K: Key<'a>>(&'a self) -> Option<&'a K::Value> { if self.key == KeyId::of::() { (**self.value).as_any().downcast_ref() } else { @@ -296,7 +296,7 @@ impl Property { } /// Whether this property belongs to the node `T`. - fn is_of(&self) -> bool { + pub fn is_of(&self) -> bool { self.node == NodeId::of::() } } @@ -478,7 +478,7 @@ impl Debug for Barrier { /// A show rule recipe. #[derive(Clone, PartialEq, Hash)] -struct Recipe { +pub struct Recipe { /// The affected node. node: NodeId, /// The function that defines the recipe. @@ -489,7 +489,7 @@ struct Recipe { impl Recipe { /// Create a new recipe for the node `T`. - fn new(func: Func, span: Span) -> Self { + pub fn new(func: Func, span: Span) -> Self { Self { node: NodeId::of::(), func, span } } } @@ -519,7 +519,7 @@ pub enum Interruption { #[derive(Default, Clone, Copy, Hash)] pub struct StyleChain<'a> { /// The first link of this chain. - head: &'a [Entry], + head: &'a [StyleEntry], /// The remaining links in the chain. tail: Option<&'a Self>, } @@ -553,7 +553,7 @@ impl<'a> StyleChain<'a> { let id = node.id(); if let Some(recipe) = self .entries() - .filter_map(Entry::recipe) + .filter_map(StyleEntry::recipe) .find(|recipe| recipe.node == id) { let dict = node.encode(); @@ -563,16 +563,14 @@ impl<'a> StyleChain<'a> { Ok(None) } } -} -impl<'a> StyleChain<'a> { - /// Return the chain, but without the trailing scoped property for the given - /// `node`. This is a 90% hack fix for show node constructor scoping. - pub(super) fn unscoped(mut self, node: NodeId) -> Self { + /// Return the chain, but without trailing scoped properties for the given + /// `node`. + pub fn unscoped(mut self, node: NodeId) -> Self { while self .head .last() - .and_then(Entry::property) + .and_then(StyleEntry::property) .map_or(false, |p| p.scoped && p.node == node) { let len = self.head.len(); @@ -651,17 +649,17 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> { fn next(&mut self) -> Option { while let Some(entry) = self.entries.next() { match entry { - Entry::Property(property) => { + StyleEntry::Property(property) => { if let Some(value) = property.downcast::() { if !property.scoped || self.depth <= 1 { return Some(value); } } } - Entry::Barrier(barrier) => { + StyleEntry::Barrier(barrier) => { self.depth += (barrier.0 == K::node()) as usize; } - Entry::Recipe(_) => {} + StyleEntry::Recipe(_) => {} } } @@ -671,12 +669,12 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> { /// An iterator over the entries in a style chain. struct Entries<'a> { - inner: std::slice::Iter<'a, Entry>, + inner: std::slice::Iter<'a, StyleEntry>, links: Links<'a>, } impl<'a> Iterator for Entries<'a> { - type Item = &'a Entry; + type Item = &'a StyleEntry; fn next(&mut self) -> Option { loop { @@ -696,7 +694,7 @@ impl<'a> Iterator for Entries<'a> { struct Links<'a>(Option>); impl<'a> Iterator for Links<'a> { - type Item = &'a [Entry]; + type Item = &'a [StyleEntry]; fn next(&mut self) -> Option { let StyleChain { head, tail } = self.0?;