Show everything!
This commit is contained in:
parent
9b8c1dc19f
commit
1937d746ab
@ -32,7 +32,7 @@ use typst::diag::SourceResult;
|
||||
use typst::frame::Frame;
|
||||
use typst::geom::*;
|
||||
use typst::model::{
|
||||
capability, Content, Node, SequenceNode, Show, Style, StyleChain, StyleVecBuilder,
|
||||
capability, Content, Node, SequenceNode, Style, StyleChain, StyleVecBuilder,
|
||||
StyledNode,
|
||||
};
|
||||
use typst::World;
|
||||
@ -87,7 +87,7 @@ impl LayoutBlock for Content {
|
||||
regions: &Regions,
|
||||
styles: StyleChain,
|
||||
) -> SourceResult<Vec<Frame>> {
|
||||
if !self.has::<dyn Show>() || !styles.applicable(self) {
|
||||
if !styles.applicable(self) {
|
||||
if let Some(node) = self.to::<dyn LayoutBlock>() {
|
||||
let barrier = Style::Barrier(self.id());
|
||||
let styles = barrier.chain(&styles);
|
||||
@ -126,7 +126,7 @@ impl LayoutInline for Content {
|
||||
assert!(regions.backlog.is_empty());
|
||||
assert!(regions.last.is_none());
|
||||
|
||||
if !self.has::<dyn Show>() || !styles.applicable(self) {
|
||||
if !styles.applicable(self) {
|
||||
if let Some(node) = self.to::<dyn LayoutInline>() {
|
||||
let barrier = Style::Barrier(self.id());
|
||||
let styles = barrier.chain(&styles);
|
||||
@ -312,16 +312,17 @@ impl<'a> Builder<'a> {
|
||||
content: &'a Content,
|
||||
styles: StyleChain<'a>,
|
||||
) -> SourceResult<()> {
|
||||
if content.is::<TextNode>() {
|
||||
if let Some(realized) = styles.apply(self.world, content)? {
|
||||
let stored = self.scratch.content.alloc(realized);
|
||||
return self.accept(stored, styles);
|
||||
}
|
||||
} else if let Some(styled) = content.downcast::<StyledNode>() {
|
||||
if let Some(styled) = content.downcast::<StyledNode>() {
|
||||
return self.styled(styled, styles);
|
||||
} else if let Some(seq) = content.downcast::<SequenceNode>() {
|
||||
}
|
||||
|
||||
if let Some(seq) = content.downcast::<SequenceNode>() {
|
||||
return self.sequence(seq, styles);
|
||||
} else if content.has::<dyn Show>() && self.show(content, styles)? {
|
||||
}
|
||||
|
||||
if let Some(realized) = styles.show(self.world, content)? {
|
||||
let stored = self.scratch.content.alloc(realized);
|
||||
self.accept(stored, styles)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -361,17 +362,6 @@ impl<'a> Builder<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show(&mut self, content: &Content, styles: StyleChain<'a>) -> SourceResult<bool> {
|
||||
let Some(realized) = styles.apply(self.world, content)? else {
|
||||
return Ok(false);
|
||||
};
|
||||
|
||||
let stored = self.scratch.content.alloc(realized);
|
||||
self.accept(stored, styles)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn styled(
|
||||
&mut self,
|
||||
styled: &'a StyledNode,
|
||||
|
@ -28,15 +28,16 @@ impl MathNode {
|
||||
}
|
||||
|
||||
impl Show for MathNode {
|
||||
fn unguard_parts(&self, _: RecipeId) -> Content {
|
||||
self.clone().pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, styles: StyleChain) -> SourceResult<Content> {
|
||||
let mut map = StyleMap::new();
|
||||
map.set_family(FontFamily::new("NewComputerModernMath"), styles);
|
||||
|
||||
let mut realized = self.clone().pack().styled_with_map(map);
|
||||
let mut realized = self
|
||||
.clone()
|
||||
.pack()
|
||||
.guard(RecipeId::Base(NodeId::of::<Self>()))
|
||||
.styled_with_map(map);
|
||||
|
||||
if self.display {
|
||||
realized = realized.aligned(Axes::with_x(Some(Align::Center.into())))
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ pub use typst::geom::*;
|
||||
#[doc(no_inline)]
|
||||
pub use typst::model::{
|
||||
array, capability, castable, dict, dynamic, format_str, node, Args, Array, Cast,
|
||||
Content, Dict, Finalize, Fold, Func, Node, RecipeId, Resolve, Show, Smart, Str,
|
||||
StyleChain, StyleMap, StyleVec, Value, Vm,
|
||||
Content, Dict, Finalize, Fold, Func, Node, NodeId, RecipeId, Resolve, Show, Smart,
|
||||
Str, StyleChain, StyleMap, StyleVec, Value, Vm,
|
||||
};
|
||||
#[doc(no_inline)]
|
||||
pub use typst::syntax::{Span, Spanned};
|
||||
|
@ -34,10 +34,6 @@ impl HeadingNode {
|
||||
}
|
||||
|
||||
impl Show for HeadingNode {
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content {
|
||||
Self { body: self.body.unguard(id), ..*self }.pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(BlockNode(self.body.clone()).pack())
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use crate::prelude::*;
|
||||
use crate::text::{ParNode, SpaceNode, TextNode};
|
||||
|
||||
/// An unordered (bulleted) or ordered (numbered) list.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct ListNode<const L: ListKind = LIST> {
|
||||
/// If true, the items are separated by leading instead of list spacing.
|
||||
pub tight: bool,
|
||||
@ -20,7 +20,7 @@ pub type EnumNode = ListNode<ENUM>;
|
||||
/// A description list.
|
||||
pub type DescNode = ListNode<DESC>;
|
||||
|
||||
#[node(Show, LayoutBlock)]
|
||||
#[node(LayoutBlock)]
|
||||
impl<const L: ListKind> ListNode<L> {
|
||||
/// How the list is labelled.
|
||||
#[property(referenced)]
|
||||
@ -77,20 +77,6 @@ impl<const L: ListKind> ListNode<L> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const L: ListKind> Show for ListNode<L> {
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content {
|
||||
Self {
|
||||
items: self.items.map(|item| item.unguard(id)),
|
||||
..*self
|
||||
}
|
||||
.pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.clone().pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const L: ListKind> LayoutBlock for ListNode<L> {
|
||||
fn layout_block(
|
||||
&self,
|
||||
@ -178,17 +164,6 @@ impl ListItem {
|
||||
}
|
||||
}
|
||||
|
||||
fn unguard(&self, sel: RecipeId) -> Self {
|
||||
match self {
|
||||
Self::List(body) => Self::List(Box::new(body.unguard(sel))),
|
||||
Self::Enum(number, body) => Self::Enum(*number, Box::new(body.unguard(sel))),
|
||||
Self::Desc(item) => Self::Desc(Box::new(DescItem {
|
||||
term: item.term.unguard(sel),
|
||||
body: item.body.unguard(sel),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
/// Encode the item into a value.
|
||||
fn encode(&self) -> Value {
|
||||
match self {
|
||||
|
@ -20,10 +20,6 @@ impl RefNode {
|
||||
}
|
||||
|
||||
impl Show for RefNode {
|
||||
fn unguard_parts(&self, _: RecipeId) -> Content {
|
||||
Self(self.0.clone()).pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(TextNode::packed(format_eco!("@{}", self.0)))
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::layout::{GridNode, TrackSizing, TrackSizings};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// A table of items.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct TableNode {
|
||||
/// Defines sizing for content rows and columns.
|
||||
pub tracks: Axes<Vec<TrackSizing>>,
|
||||
@ -12,7 +12,7 @@ pub struct TableNode {
|
||||
pub cells: Vec<Content>,
|
||||
}
|
||||
|
||||
#[node(Show, LayoutBlock)]
|
||||
#[node(LayoutBlock)]
|
||||
impl TableNode {
|
||||
/// How to fill the cells.
|
||||
#[property(referenced)]
|
||||
@ -50,21 +50,6 @@ impl TableNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Show for TableNode {
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content {
|
||||
Self {
|
||||
tracks: self.tracks.clone(),
|
||||
gutter: self.gutter.clone(),
|
||||
cells: self.cells.iter().map(|cell| cell.unguard(id)).collect(),
|
||||
}
|
||||
.pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.clone().pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutBlock for TableNode {
|
||||
fn layout_block(
|
||||
&self,
|
||||
|
@ -47,10 +47,6 @@ impl<const L: DecoLine> DecoNode<L> {
|
||||
}
|
||||
|
||||
impl<const L: DecoLine> Show for DecoNode<L> {
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content {
|
||||
Self(self.0.unguard(id)).pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, styles: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.0.clone().styled(
|
||||
TextNode::DECO,
|
||||
|
@ -50,14 +50,6 @@ impl LinkNode {
|
||||
}
|
||||
|
||||
impl Show for LinkNode {
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content {
|
||||
Self {
|
||||
dest: self.dest.clone(),
|
||||
body: self.body.unguard(id),
|
||||
}
|
||||
.pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.body.clone())
|
||||
}
|
||||
|
@ -528,10 +528,6 @@ impl StrongNode {
|
||||
}
|
||||
|
||||
impl Show for StrongNode {
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content {
|
||||
Self(self.0.unguard(id)).pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.0.clone().styled(TextNode::BOLD, Toggle))
|
||||
}
|
||||
@ -556,10 +552,6 @@ impl EmphNode {
|
||||
}
|
||||
|
||||
impl Show for EmphNode {
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content {
|
||||
Self(self.0.unguard(id)).pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.0.clone().styled(TextNode::ITALIC, Toggle))
|
||||
}
|
||||
|
@ -43,10 +43,6 @@ impl RawNode {
|
||||
}
|
||||
|
||||
impl Show for RawNode {
|
||||
fn unguard_parts(&self, _: RecipeId) -> Content {
|
||||
Self { text: self.text.clone(), ..*self }.pack()
|
||||
}
|
||||
|
||||
fn show(&self, _: Tracked<dyn World>, styles: StyleChain) -> SourceResult<Content> {
|
||||
let lang = styles.get(Self::LANG).as_ref().map(|s| s.to_lowercase());
|
||||
let foreground = THEME
|
||||
|
@ -43,10 +43,6 @@ impl<const S: ShiftKind> ShiftNode<S> {
|
||||
}
|
||||
|
||||
impl<const S: ShiftKind> Show for ShiftNode<S> {
|
||||
fn unguard_parts(&self, _: RecipeId) -> Content {
|
||||
Self(self.0.clone()).pack()
|
||||
}
|
||||
|
||||
fn show(
|
||||
&self,
|
||||
world: Tracked<dyn World>,
|
||||
|
@ -20,7 +20,7 @@ use crate::World;
|
||||
/// - anything written between square brackets in Typst
|
||||
/// - any constructor function
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct Content(Arc<dyn Bounds>);
|
||||
pub struct Content(Arc<dyn Bounds>, Vec<RecipeId>);
|
||||
|
||||
impl Content {
|
||||
/// Create empty content.
|
||||
@ -112,16 +112,16 @@ impl Content {
|
||||
}
|
||||
|
||||
/// Style this content with a style entry.
|
||||
pub fn styled_with_entry(mut self, entry: Style) -> Self {
|
||||
pub fn styled_with_entry(mut self, style: Style) -> Self {
|
||||
if let Some(styled) = self.try_downcast_mut::<StyledNode>() {
|
||||
styled.map.apply(entry);
|
||||
styled.map.apply(style);
|
||||
self
|
||||
} else if let Some(styled) = self.downcast::<StyledNode>() {
|
||||
let mut map = styled.map.clone();
|
||||
map.apply(entry);
|
||||
map.apply(style);
|
||||
StyledNode { sub: styled.sub.clone(), map }.pack()
|
||||
} else {
|
||||
StyledNode { sub: self, map: entry.into() }.pack()
|
||||
StyledNode { sub: self, map: style.into() }.pack()
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,9 +139,20 @@ impl Content {
|
||||
StyledNode { sub: self, map: styles }.pack()
|
||||
}
|
||||
|
||||
/// Reenable a specific show rule recipe.
|
||||
pub fn unguard(&self, id: RecipeId) -> Self {
|
||||
self.clone().styled_with_entry(Style::Unguard(id))
|
||||
/// Disable a show rule recipe.
|
||||
pub fn guard(mut self, id: RecipeId) -> Self {
|
||||
self.1.push(id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether no show rule was executed for this node so far.
|
||||
pub fn pristine(&self) -> bool {
|
||||
self.1.is_empty()
|
||||
}
|
||||
|
||||
/// Check whether a show rule recipe is disabled.
|
||||
pub fn guarded(&self, id: RecipeId) -> bool {
|
||||
self.1.contains(&id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +252,7 @@ pub trait Node: 'static {
|
||||
where
|
||||
Self: Debug + Hash + Sync + Send + Sized + 'static,
|
||||
{
|
||||
Content(Arc::new(self))
|
||||
Content(Arc::new(self), vec![])
|
||||
}
|
||||
|
||||
/// Construct a node from the arguments.
|
||||
|
@ -31,13 +31,6 @@ impl StyleMap {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// 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();
|
||||
styles.set(key, value);
|
||||
styles
|
||||
}
|
||||
|
||||
/// Set an inner value for a style property.
|
||||
///
|
||||
/// If the property needs folding and the value is already contained in the
|
||||
@ -75,12 +68,12 @@ impl StyleMap {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set an outer style property.
|
||||
/// Set an outer style.
|
||||
///
|
||||
/// Like [`chain`](Self::chain) or [`apply_map`](Self::apply_map), but with
|
||||
/// only a entry.
|
||||
pub fn apply(&mut self, entry: Style) {
|
||||
self.0.insert(0, entry);
|
||||
pub fn apply(&mut self, style: Style) {
|
||||
self.0.insert(0, style);
|
||||
}
|
||||
|
||||
/// Apply styles from `tail` in-place. The resulting style map is equivalent
|
||||
@ -135,10 +128,6 @@ pub enum Style {
|
||||
Recipe(Recipe),
|
||||
/// A barrier for scoped styles.
|
||||
Barrier(NodeId),
|
||||
/// Guards against recursive show rules.
|
||||
Guard(RecipeId),
|
||||
/// Allows recursive show rules again.
|
||||
Unguard(RecipeId),
|
||||
}
|
||||
|
||||
impl Style {
|
||||
@ -190,8 +179,6 @@ impl Debug for Style {
|
||||
Self::Property(property) => property.fmt(f)?,
|
||||
Self::Recipe(recipe) => recipe.fmt(f)?,
|
||||
Self::Barrier(id) => write!(f, "Barrier for {id:?}")?,
|
||||
Self::Guard(sel) => write!(f, "Guard against {sel:?}")?,
|
||||
Self::Unguard(sel) => write!(f, "Unguard against {sel:?}")?,
|
||||
}
|
||||
f.write_str("]")
|
||||
}
|
||||
@ -338,14 +325,10 @@ impl Debug for KeyId {
|
||||
}
|
||||
}
|
||||
|
||||
/// A node that can be realized given some styles.
|
||||
/// A built-in show rule for a node.
|
||||
#[capability]
|
||||
pub trait Show: 'static + Sync + Send {
|
||||
/// Unguard nested content against a specific recipe.
|
||||
fn unguard_parts(&self, id: RecipeId) -> Content;
|
||||
|
||||
/// The base recipe for this node that is executed if there is no
|
||||
/// user-defined show rule.
|
||||
/// Execute the base recipe for this node.
|
||||
fn show(
|
||||
&self,
|
||||
world: Tracked<dyn World>,
|
||||
@ -356,9 +339,9 @@ pub trait Show: 'static + Sync + Send {
|
||||
/// Post-process a node after it was realized.
|
||||
#[capability]
|
||||
pub trait Finalize: 'static + Sync + Send {
|
||||
/// Finalize this node given the realization of a base or user recipe. 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.
|
||||
/// 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,
|
||||
world: Tracked<dyn World>,
|
||||
@ -400,7 +383,7 @@ impl Recipe {
|
||||
}
|
||||
|
||||
self.transform.apply(world, self.span, || {
|
||||
Value::Content(target.to::<dyn Show>().unwrap().unguard_parts(sel))
|
||||
Value::Content(target.clone().guard(sel))
|
||||
})?
|
||||
}
|
||||
|
||||
@ -420,7 +403,7 @@ impl Recipe {
|
||||
}
|
||||
|
||||
let transformed = self.transform.apply(world, self.span, || {
|
||||
Value::Content(make(mat.as_str().into()))
|
||||
Value::Content(make(mat.as_str().into()).guard(sel))
|
||||
})?;
|
||||
|
||||
result.push(transformed);
|
||||
@ -441,7 +424,7 @@ impl Recipe {
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
Ok(Some(content.styled_with_entry(Style::Guard(sel))))
|
||||
Ok(Some(content))
|
||||
}
|
||||
|
||||
/// Whether this recipe is for the given node.
|
||||
@ -566,87 +549,41 @@ impl<'a> StyleChain<'a> {
|
||||
K::get(self, self.values(key))
|
||||
}
|
||||
|
||||
/// Whether the style chain has a matching recipe for the content.
|
||||
pub fn applicable(self, target: &Content) -> bool {
|
||||
// Find out how many recipes there any and whether any of them match.
|
||||
let mut n = 0;
|
||||
let mut any = true;
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
n += 1;
|
||||
any |= recipe.applicable(target);
|
||||
}
|
||||
|
||||
// Find an applicable recipe.
|
||||
if any {
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
if recipe.applicable(target) {
|
||||
let sel = RecipeId::Nth(n);
|
||||
if !self.guarded(sel) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Apply show recipes in this style chain to a target.
|
||||
pub fn apply(
|
||||
pub fn show(
|
||||
self,
|
||||
world: Tracked<dyn World>,
|
||||
target: &Content,
|
||||
) -> SourceResult<Option<Content>> {
|
||||
// Find out how many recipes there any and whether any of them match.
|
||||
let mut n = 0;
|
||||
let mut any = true;
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
n += 1;
|
||||
any |= recipe.applicable(target);
|
||||
}
|
||||
// Find out how many recipes there are.
|
||||
let mut n = self.entries().filter_map(Style::recipe).count();
|
||||
|
||||
// Find an applicable recipe.
|
||||
let mut realized = None;
|
||||
let mut guarded = false;
|
||||
if any {
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
if recipe.applicable(target) {
|
||||
let sel = RecipeId::Nth(n);
|
||||
if self.guarded(sel) {
|
||||
guarded = true;
|
||||
} else if let Some(content) = recipe.apply(world, sel, target)? {
|
||||
realized = Some(content);
|
||||
break;
|
||||
}
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
let sel = RecipeId::Nth(n);
|
||||
if recipe.applicable(target) && !target.guarded(sel) {
|
||||
if let Some(content) = recipe.apply(world, sel, target)? {
|
||||
realized = Some(content);
|
||||
break;
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
|
||||
// Realize if there was no matching recipe.
|
||||
let base = RecipeId::Base(target.id());
|
||||
if realized.is_none() && !target.guarded(base) {
|
||||
if let Some(showable) = target.to::<dyn Show>() {
|
||||
realized = Some(showable.show(world, self)?);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(showable) = target.to::<dyn Show>() {
|
||||
// Realize if there was no matching recipe.
|
||||
if realized.is_none() {
|
||||
let sel = RecipeId::Base(target.id());
|
||||
if self.guarded(sel) {
|
||||
guarded = true;
|
||||
} else {
|
||||
let content = showable
|
||||
.unguard_parts(sel)
|
||||
.to::<dyn Show>()
|
||||
.unwrap()
|
||||
.show(world, self)?;
|
||||
|
||||
realized = Some(content.styled_with_entry(Style::Guard(sel)));
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize only if guarding didn't stop any recipe.
|
||||
if !guarded {
|
||||
if let Some(node) = target.to::<dyn Finalize>() {
|
||||
if let Some(content) = realized {
|
||||
realized = Some(node.finalize(world, self, content)?);
|
||||
}
|
||||
// Finalize only if this is the first application for this node.
|
||||
if let Some(node) = target.to::<dyn Finalize>() {
|
||||
if target.pristine() {
|
||||
if let Some(content) = realized {
|
||||
realized = Some(node.finalize(world, self, content)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -654,14 +591,17 @@ impl<'a> StyleChain<'a> {
|
||||
Ok(realized)
|
||||
}
|
||||
|
||||
/// Whether the recipe identified by the selector is guarded.
|
||||
fn guarded(self, sel: RecipeId) -> bool {
|
||||
for entry in self.entries() {
|
||||
match *entry {
|
||||
Style::Guard(s) if s == sel => return true,
|
||||
Style::Unguard(s) if s == sel => return false,
|
||||
_ => {}
|
||||
/// Whether the style chain has a matching recipe for the content.
|
||||
pub fn applicable(self, target: &Content) -> bool {
|
||||
// Find out how many recipes there are.
|
||||
let mut n = self.entries().filter_map(Style::recipe).count();
|
||||
|
||||
// Find out whether any recipe matches and is unguarded.
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
if recipe.applicable(target) && !target.guarded(RecipeId::Nth(n)) {
|
||||
return true;
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
|
||||
false
|
||||
@ -689,7 +629,6 @@ impl<'a> StyleChain<'a> {
|
||||
entries: self.entries(),
|
||||
key: PhantomData,
|
||||
barriers: 0,
|
||||
guarded: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -727,7 +666,6 @@ struct Values<'a, K> {
|
||||
entries: Entries<'a>,
|
||||
key: PhantomData<K>,
|
||||
barriers: usize,
|
||||
guarded: bool,
|
||||
}
|
||||
|
||||
impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
|
||||
@ -738,13 +676,7 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
|
||||
match entry {
|
||||
Style::Property(property) => {
|
||||
if let Some(value) = property.downcast::<K>() {
|
||||
if !property.scoped()
|
||||
|| if self.guarded {
|
||||
self.barriers == 1
|
||||
} else {
|
||||
self.barriers <= 1
|
||||
}
|
||||
{
|
||||
if !property.scoped() || self.barriers <= 1 {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
@ -752,9 +684,6 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
|
||||
Style::Barrier(id) => {
|
||||
self.barriers += (*id == K::node()) as usize;
|
||||
}
|
||||
Style::Guard(RecipeId::Base(id)) => {
|
||||
self.guarded |= *id == K::node();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Binary file not shown.
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 42 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.6 KiB |
@ -13,17 +13,6 @@ Die Zeitung Der Spiegel existiert.
|
||||
|
||||
TeX, LaTeX, LuaTeX and LuaLaTeX!
|
||||
|
||||
---
|
||||
// Test out-of-order guarding.
|
||||
#show "Good": [Typst!]
|
||||
#show "Typst": [Fun!]
|
||||
#show "Fun": [Good!]
|
||||
#show enum: []
|
||||
|
||||
Good \
|
||||
Fun \
|
||||
Typst \
|
||||
|
||||
---
|
||||
// Test that replacements happen exactly once.
|
||||
#show "A": [BB]
|
||||
|
@ -1,19 +1,19 @@
|
||||
// Test sub- and superscipt shifts.
|
||||
|
||||
---
|
||||
#table(columns: 3,
|
||||
[Typo.], [Fallb.], [Synth],
|
||||
[x#super[1]], [x#super[5n]], [x#super[2 #square(width: 6pt)]],
|
||||
[x#sub[1]], [x#sub[5n]], [x#sub[2 #square(width: 6pt)]],
|
||||
#table(
|
||||
columns: 3,
|
||||
[Typo.], [Fallb.], [Synth],
|
||||
[x#super[1]], [x#super[5n]], [x#super[2 #square(width: 6pt)]],
|
||||
[x#sub[1]], [x#sub[5n]], [x#sub[2 #square(width: 6pt)]],
|
||||
)
|
||||
|
||||
---
|
||||
#set super(typographic: false, baseline: -0.25em, size: 0.7em)
|
||||
n#super[1], n#sub[2], ... n#super[N]
|
||||
n#super[1], n#sub[2], ... n#super[N]
|
||||
|
||||
---
|
||||
#set underline(stroke: 0.5pt, offset: 0.15em)
|
||||
|
||||
#underline[The claim#super[\[4\]]] has been disputed. \
|
||||
The claim#super[#underline[\[4\]]] has been disputed. \
|
||||
It really has been#super(box(text(baseline: 0pt, underline[\[4\]]))) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user