summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/doc.rs2
-rw-r--r--src/eval/func.rs14
-rw-r--r--src/model/content.rs33
-rw-r--r--src/model/realize.rs4
-rw-r--r--src/model/styles.rs178
5 files changed, 115 insertions, 116 deletions
diff --git a/src/doc.rs b/src/doc.rs
index ce6f4c96..67e13bc8 100644
--- a/src/doc.rs
+++ b/src/doc.rs
@@ -605,9 +605,7 @@ pub enum Meta {
pub struct MetaNode {
/// Metadata that should be attached to all elements affected by this style
/// property.
- #[settable]
#[fold]
- #[default]
pub data: Vec<Meta>,
}
diff --git a/src/eval/func.rs b/src/eval/func.rs
index 8243b4f6..6f98e316 100644
--- a/src/eval/func.rs
+++ b/src/eval/func.rs
@@ -54,15 +54,11 @@ impl Func {
/// Create a new function from a native rust node.
pub fn from_node<T: Node>(mut info: FuncInfo) -> Self {
- info.params.extend(T::properties());
+ info.params.extend(T::params());
Self(
Arc::new(Prehashed::new(Repr::Native(Native {
- func: |ctx, args| {
- let styles = T::set(args, true)?;
- let content = T::construct(ctx, args)?;
- Ok(Value::Content(content.styled_with_map(styles.scoped())))
- },
- set: Some(|args| T::set(args, false)),
+ func: |vm, args| T::construct(vm, args).map(Value::Content),
+ set: Some(T::set),
node: Some(NodeId::of::<T>()),
info,
}))),
@@ -281,10 +277,10 @@ pub struct ParamInfo {
/// Can be true even if `positional` is true if the parameter can be given
/// in both variants.
pub named: bool,
- /// Is the parameter required?
- pub required: bool,
/// Can the parameter be given any number of times?
pub variadic: bool,
+ /// Is the parameter required?
+ pub required: bool,
/// Is the parameter settable with a set rule?
pub settable: bool,
}
diff --git a/src/model/content.rs b/src/model/content.rs
index 05c5d430..6b4f5e5d 100644
--- a/src/model/content.rs
+++ b/src/model/content.rs
@@ -55,7 +55,7 @@ impl Content {
/// Attach a span to the content.
pub fn spanned(mut self, span: Span) -> Self {
if let Some(styled) = self.to::<StyledNode>() {
- self = StyledNode::new(styled.body().spanned(span), styled.map()).pack();
+ self = StyledNode::new(styled.map(), styled.body().spanned(span)).pack();
}
self.span = Some(span);
self
@@ -78,9 +78,9 @@ impl Content {
} else if let Some(styled) = self.to::<StyledNode>() {
let mut map = styled.map();
map.apply(styles);
- StyledNode::new(styled.body(), map).pack()
+ StyledNode::new(map, styled.body()).pack()
} else {
- StyledNode::new(self, styles).pack()
+ StyledNode::new(styles, self).pack()
}
}
@@ -161,7 +161,7 @@ impl Content {
}
#[track_caller]
- pub fn cast_field<T: Cast>(&self, name: &str) -> T {
+ pub fn cast_required_field<T: Cast>(&self, name: &str) -> T {
match self.field(name) {
Some(value) => value.clone().cast().unwrap(),
None => field_is_missing(name),
@@ -329,15 +329,15 @@ impl Sum for Content {
/// Category: special
#[node]
pub struct StyledNode {
- /// The styled content.
+ /// The styles.
#[positional]
#[required]
- pub body: Content,
+ pub map: StyleMap,
- /// The styles.
+ /// The styled content.
#[positional]
#[required]
- pub map: StyleMap,
+ pub body: Content,
}
cast_from_value! {
@@ -353,8 +353,8 @@ cast_from_value! {
/// Category: special
#[node]
pub struct SequenceNode {
+ #[positional]
#[variadic]
- #[required]
pub children: Vec<Content>,
}
@@ -370,11 +370,14 @@ impl Debug for Label {
/// A constructable, stylable content node.
pub trait Node: Construct + Set + Sized + 'static {
+ /// Pack a node into type-erased content.
+ fn pack(self) -> Content;
+
/// The node's ID.
fn id() -> NodeId;
- /// Pack a node into type-erased content.
- fn pack(self) -> Content;
+ /// List the fields of the node.
+ fn params() -> Vec<ParamInfo>;
}
/// A unique identifier for a node.
@@ -432,13 +435,7 @@ pub trait Construct {
pub trait Set {
/// Parse relevant arguments into style properties for this node.
- ///
- /// When `constructor` is true, [`construct`](Construct::construct) will run
- /// after this invocation of `set` with the remaining arguments.
- fn set(args: &mut Args, constructor: bool) -> SourceResult<StyleMap>;
-
- /// List the settable properties.
- fn properties() -> Vec<ParamInfo>;
+ fn set(args: &mut Args) -> SourceResult<StyleMap>;
}
/// Indicates that a node cannot be labelled.
diff --git a/src/model/realize.rs b/src/model/realize.rs
index 2f38df51..502774bb 100644
--- a/src/model/realize.rs
+++ b/src/model/realize.rs
@@ -59,7 +59,7 @@ pub fn realize(
if let Some(node) = target.with::<dyn Finalize>() {
if target.is_pristine() {
if let Some(already) = realized {
- realized = Some(node.finalize(already));
+ realized = Some(node.finalize(already, styles));
}
}
}
@@ -159,7 +159,7 @@ pub trait Finalize {
/// Finalize the fully realized form of the node. Use this for effects that
/// should work even in the face of a user-defined show rule, for example
/// the linking behaviour of a link node.
- fn finalize(&self, realized: Content) -> Content;
+ fn finalize(&self, realized: Content, styles: StyleChain) -> Content;
}
/// Guards content against being affected by the same show rule multiple times.
diff --git a/src/model/styles.rs b/src/model/styles.rs
index bd7a062f..0b74e162 100644
--- a/src/model/styles.rs
+++ b/src/model/styles.rs
@@ -34,11 +34,6 @@ impl StyleMap {
self.0.push(Style::Property(property));
}
- /// Set an inner value for a style property if it is `Some(_)`.
- pub fn set_opt(&mut self, property: Option<Property>) {
- self.0.extend(property.map(Style::Property));
- }
-
/// Remove the style that was last set.
pub fn unset(&mut self) {
self.0.pop();
@@ -49,30 +44,11 @@ impl StyleMap {
self.0.splice(0..0, outer.0.iter().cloned());
}
- /// Set an outer style. Like [`chain_one`](StyleChain::chain_one), but
- /// in-place.
- pub fn apply_one(&mut self, outer: Style) {
- self.0.insert(0, outer);
- }
-
- /// Mark all contained properties as _scoped_. This means that they only
- /// apply to the first descendant node (of their type) in the hierarchy and
- /// not its children, too. This is used by
- /// [constructors](super::Construct::construct).
- pub fn scoped(mut self) -> Self {
- for entry in &mut self.0 {
- if let Style::Property(property) = entry {
- property.scoped = true;
- }
- }
- self
- }
-
/// Add an origin span to all contained properties.
pub fn spanned(mut self, span: Span) -> Self {
for entry in &mut self.0 {
if let Style::Property(property) = entry {
- property.origin = Some(span);
+ property.span = Some(span);
}
}
self
@@ -83,9 +59,8 @@ impl StyleMap {
pub fn interruption<T: Node>(&self) -> Option<Option<Span>> {
let node = NodeId::of::<T>();
self.0.iter().find_map(|entry| match entry {
- Style::Property(property) => property.is_of(node).then(|| property.origin),
+ Style::Property(property) => property.is_of(node).then(|| property.span),
Style::Recipe(recipe) => recipe.is_of(node).then(|| Some(recipe.span)),
- _ => None,
})
}
}
@@ -118,8 +93,6 @@ pub enum Style {
Property(Property),
/// A show rule recipe.
Recipe(Recipe),
- /// A barrier for scoped styles.
- Barrier(NodeId),
}
impl Style {
@@ -145,7 +118,6 @@ impl Debug for Style {
match self {
Self::Property(property) => property.fmt(f),
Self::Recipe(recipe) => recipe.fmt(f),
- Self::Barrier(id) => write!(f, "#[Barrier for {id:?}]"),
}
}
}
@@ -165,17 +137,14 @@ pub struct Property {
name: EcoString,
/// The property's value.
value: Value,
- /// Whether the property should only affect the first node down the
- /// hierarchy. Used by constructors.
- scoped: bool,
/// The span of the set rule the property stems from.
- origin: Option<Span>,
+ span: Option<Span>,
}
impl Property {
/// Create a new property from a key-value pair.
pub fn new(node: NodeId, name: EcoString, value: Value) -> Self {
- Self { node, name, value, scoped: false, origin: None }
+ Self { node, name, value, span: None }
}
/// Whether this property is the given one.
@@ -187,28 +156,11 @@ impl Property {
pub fn is_of(&self, node: NodeId) -> bool {
self.node == node
}
-
- /// Access the property's value as the given type.
- #[track_caller]
- pub fn cast<T: Cast>(&self) -> T {
- self.value.clone().cast().unwrap_or_else(|err| {
- panic!(
- "{} (for {}.{} with value {:?})",
- err,
- self.node.name(),
- self.name,
- self.value
- )
- })
- }
}
impl Debug for Property {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "#set {}({}: {:?})", self.node.name(), self.name, self.value)?;
- if self.scoped {
- write!(f, " [scoped]")?;
- }
Ok(())
}
}
@@ -381,55 +333,111 @@ impl<'a> StyleChain<'a> {
/// Make the given style the first link of the this chain.
pub fn chain_one<'b>(&'b self, style: &'b Style) -> StyleChain<'b> {
- if let Style::Barrier(id) = style {
- if !self
- .entries()
- .filter_map(Style::property)
- .any(|p| p.scoped && *id == p.node)
- {
- return *self;
- }
- }
-
StyleChain {
head: std::slice::from_ref(style),
tail: Some(self),
}
}
- /// Iterate over all style recipes in the chain.
- pub fn recipes(self) -> impl Iterator<Item = &'a Recipe> {
- self.entries().filter_map(Style::recipe)
+ /// Cast the first value for the given property in the chain.
+ pub fn get<T: Cast>(
+ self,
+ node: NodeId,
+ name: &'a str,
+ inherent: Option<Value>,
+ default: impl Fn() -> T,
+ ) -> T {
+ self.properties::<T>(node, name, inherent)
+ .next()
+ .unwrap_or_else(default)
}
/// Cast the first value for the given property in the chain.
- pub fn property<T: Cast>(self, node: NodeId, name: &'a str) -> Option<T> {
- self.properties(node, name).next()
+ pub fn get_resolve<T: Cast + Resolve>(
+ self,
+ node: NodeId,
+ name: &'a str,
+ inherent: Option<Value>,
+ default: impl Fn() -> T,
+ ) -> T::Output {
+ self.get(node, name, inherent, default).resolve(self)
+ }
+
+ /// Cast the first value for the given property in the chain.
+ pub fn get_fold<T: Cast + Fold>(
+ self,
+ node: NodeId,
+ name: &'a str,
+ inherent: Option<Value>,
+ default: impl Fn() -> T::Output,
+ ) -> T::Output {
+ fn next<T: Fold>(
+ mut values: impl Iterator<Item = T>,
+ styles: StyleChain,
+ default: &impl Fn() -> T::Output,
+ ) -> T::Output {
+ values
+ .next()
+ .map(|value| value.fold(next(values, styles, default)))
+ .unwrap_or_else(|| default())
+ }
+ next(self.properties::<T>(node, name, inherent), self, &default)
+ }
+
+ /// Cast the first value for the given property in the chain.
+ pub fn get_resolve_fold<T>(
+ self,
+ node: NodeId,
+ name: &'a str,
+ inherent: Option<Value>,
+ default: impl Fn() -> <T::Output as Fold>::Output,
+ ) -> <T::Output as Fold>::Output
+ where
+ T: Cast + Resolve,
+ T::Output: Fold,
+ {
+ fn next<T>(
+ mut values: impl Iterator<Item = T>,
+ styles: StyleChain,
+ default: &impl Fn() -> <T::Output as Fold>::Output,
+ ) -> <T::Output as Fold>::Output
+ where
+ T: Resolve,
+ T::Output: Fold,
+ {
+ values
+ .next()
+ .map(|value| value.resolve(styles).fold(next(values, styles, default)))
+ .unwrap_or_else(|| default())
+ }
+ next(self.properties::<T>(node, name, inherent), self, &default)
+ }
+
+ /// Iterate over all style recipes in the chain.
+ pub fn recipes(self) -> impl Iterator<Item = &'a Recipe> {
+ self.entries().filter_map(Style::recipe)
}
/// Iterate over all values for the given property in the chain.
- pub fn properties<T: Cast>(
+ pub fn properties<T: Cast + 'a>(
self,
node: NodeId,
name: &'a str,
+ inherent: Option<Value>,
) -> impl Iterator<Item = T> + '_ {
- let mut barriers = 0;
- self.entries().filter_map(move |entry| {
- match entry {
- Style::Property(property) => {
- if property.is(node, name) {
- if !property.scoped || barriers <= 1 {
- return Some(property.cast());
- }
- }
- }
- Style::Barrier(id) => {
- barriers += (*id == node) as usize;
- }
- _ => {}
- }
- None
- })
+ inherent
+ .into_iter()
+ .chain(
+ self.entries()
+ .filter_map(Style::property)
+ .filter(move |property| property.is(node, name))
+ .map(|property| property.value.clone()),
+ )
+ .map(move |value| {
+ value.cast().unwrap_or_else(|err| {
+ panic!("{} (for {}.{})", err, node.name(), name)
+ })
+ })
}
/// Iterate over the entries of the chain.