Public style entry enum
This commit is contained in:
parent
649c101f07
commit
09aabc3a21
@ -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<u8>)>,
|
||||
/// 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> {
|
||||
|
@ -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)?;
|
||||
|
@ -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<Vec<Arc<Frame>>> {
|
||||
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()
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use crate::Context;
|
||||
|
||||
/// A map of style properties.
|
||||
#[derive(Default, Clone, PartialEq, Hash)]
|
||||
pub struct StyleMap(Vec<Entry>);
|
||||
pub struct StyleMap(Vec<StyleEntry>);
|
||||
|
||||
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<T: Node>(&mut self, func: Func, span: Span) {
|
||||
self.0.push(Entry::Recipe(Recipe::new::<T>(func, span)));
|
||||
self.push(StyleEntry::Recipe(Recipe::new::<T>(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<StyleEntry> 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<Barrier> 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::<K>(),
|
||||
node: K::node(),
|
||||
@ -276,7 +276,7 @@ impl Property {
|
||||
}
|
||||
|
||||
/// What kind of structure the property interrupts.
|
||||
fn interruption(&self) -> Option<Interruption> {
|
||||
pub fn interruption(&self) -> Option<Interruption> {
|
||||
if self.is_of::<PageNode>() {
|
||||
Some(Interruption::Page)
|
||||
} else if self.is_of::<ParNode>() {
|
||||
@ -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::<K>() {
|
||||
(**self.value).as_any().downcast_ref()
|
||||
} else {
|
||||
@ -296,7 +296,7 @@ impl Property {
|
||||
}
|
||||
|
||||
/// Whether this property belongs to the node `T`.
|
||||
fn is_of<T: Node>(&self) -> bool {
|
||||
pub fn is_of<T: 'static>(&self) -> bool {
|
||||
self.node == NodeId::of::<T>()
|
||||
}
|
||||
}
|
||||
@ -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<T: Node>(func: Func, span: Span) -> Self {
|
||||
pub fn new<T: Node>(func: Func, span: Span) -> Self {
|
||||
Self { node: NodeId::of::<T>(), 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<Self::Item> {
|
||||
while let Some(entry) = self.entries.next() {
|
||||
match entry {
|
||||
Entry::Property(property) => {
|
||||
StyleEntry::Property(property) => {
|
||||
if let Some(value) = property.downcast::<K>() {
|
||||
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<Self::Item> {
|
||||
loop {
|
||||
@ -696,7 +694,7 @@ impl<'a> Iterator for Entries<'a> {
|
||||
struct Links<'a>(Option<StyleChain<'a>>);
|
||||
|
||||
impl<'a> Iterator for Links<'a> {
|
||||
type Item = &'a [Entry];
|
||||
type Item = &'a [StyleEntry];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let StyleChain { head, tail } = self.0?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user