mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
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::frame::Frame;
|
||||||
use typst::geom::*;
|
use typst::geom::*;
|
||||||
use typst::model::{
|
use typst::model::{
|
||||||
capability, Content, Node, SequenceNode, Show, Style, StyleChain, StyleVecBuilder,
|
capability, Content, Node, SequenceNode, Style, StyleChain, StyleVecBuilder,
|
||||||
StyledNode,
|
StyledNode,
|
||||||
};
|
};
|
||||||
use typst::World;
|
use typst::World;
|
||||||
@ -87,7 +87,7 @@ impl LayoutBlock for Content {
|
|||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> SourceResult<Vec<Frame>> {
|
) -> SourceResult<Vec<Frame>> {
|
||||||
if !self.has::<dyn Show>() || !styles.applicable(self) {
|
if !styles.applicable(self) {
|
||||||
if let Some(node) = self.to::<dyn LayoutBlock>() {
|
if let Some(node) = self.to::<dyn LayoutBlock>() {
|
||||||
let barrier = Style::Barrier(self.id());
|
let barrier = Style::Barrier(self.id());
|
||||||
let styles = barrier.chain(&styles);
|
let styles = barrier.chain(&styles);
|
||||||
@ -126,7 +126,7 @@ impl LayoutInline for Content {
|
|||||||
assert!(regions.backlog.is_empty());
|
assert!(regions.backlog.is_empty());
|
||||||
assert!(regions.last.is_none());
|
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>() {
|
if let Some(node) = self.to::<dyn LayoutInline>() {
|
||||||
let barrier = Style::Barrier(self.id());
|
let barrier = Style::Barrier(self.id());
|
||||||
let styles = barrier.chain(&styles);
|
let styles = barrier.chain(&styles);
|
||||||
@ -312,16 +312,17 @@ impl<'a> Builder<'a> {
|
|||||||
content: &'a Content,
|
content: &'a Content,
|
||||||
styles: StyleChain<'a>,
|
styles: StyleChain<'a>,
|
||||||
) -> SourceResult<()> {
|
) -> SourceResult<()> {
|
||||||
if content.is::<TextNode>() {
|
if let Some(styled) = content.downcast::<StyledNode>() {
|
||||||
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>() {
|
|
||||||
return self.styled(styled, styles);
|
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);
|
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(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,17 +362,6 @@ impl<'a> Builder<'a> {
|
|||||||
Ok(())
|
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(
|
fn styled(
|
||||||
&mut self,
|
&mut self,
|
||||||
styled: &'a StyledNode,
|
styled: &'a StyledNode,
|
||||||
|
@ -28,15 +28,16 @@ impl MathNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Show for MathNode {
|
impl Show for MathNode {
|
||||||
fn unguard_parts(&self, _: RecipeId) -> Content {
|
|
||||||
self.clone().pack()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show(&self, _: Tracked<dyn World>, styles: StyleChain) -> SourceResult<Content> {
|
fn show(&self, _: Tracked<dyn World>, styles: StyleChain) -> SourceResult<Content> {
|
||||||
let mut map = StyleMap::new();
|
let mut map = StyleMap::new();
|
||||||
map.set_family(FontFamily::new("NewComputerModernMath"), styles);
|
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 {
|
if self.display {
|
||||||
realized = realized.aligned(Axes::with_x(Some(Align::Center.into())))
|
realized = realized.aligned(Axes::with_x(Some(Align::Center.into())))
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ pub use typst::geom::*;
|
|||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use typst::model::{
|
pub use typst::model::{
|
||||||
array, capability, castable, dict, dynamic, format_str, node, Args, Array, Cast,
|
array, capability, castable, dict, dynamic, format_str, node, Args, Array, Cast,
|
||||||
Content, Dict, Finalize, Fold, Func, Node, RecipeId, Resolve, Show, Smart, Str,
|
Content, Dict, Finalize, Fold, Func, Node, NodeId, RecipeId, Resolve, Show, Smart,
|
||||||
StyleChain, StyleMap, StyleVec, Value, Vm,
|
Str, StyleChain, StyleMap, StyleVec, Value, Vm,
|
||||||
};
|
};
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use typst::syntax::{Span, Spanned};
|
pub use typst::syntax::{Span, Spanned};
|
||||||
|
@ -34,10 +34,6 @@ impl HeadingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Show for 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> {
|
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(BlockNode(self.body.clone()).pack())
|
Ok(BlockNode(self.body.clone()).pack())
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::prelude::*;
|
|||||||
use crate::text::{ParNode, SpaceNode, TextNode};
|
use crate::text::{ParNode, SpaceNode, TextNode};
|
||||||
|
|
||||||
/// An unordered (bulleted) or ordered (numbered) list.
|
/// An unordered (bulleted) or ordered (numbered) list.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct ListNode<const L: ListKind = LIST> {
|
pub struct ListNode<const L: ListKind = LIST> {
|
||||||
/// If true, the items are separated by leading instead of list spacing.
|
/// If true, the items are separated by leading instead of list spacing.
|
||||||
pub tight: bool,
|
pub tight: bool,
|
||||||
@ -20,7 +20,7 @@ pub type EnumNode = ListNode<ENUM>;
|
|||||||
/// A description list.
|
/// A description list.
|
||||||
pub type DescNode = ListNode<DESC>;
|
pub type DescNode = ListNode<DESC>;
|
||||||
|
|
||||||
#[node(Show, LayoutBlock)]
|
#[node(LayoutBlock)]
|
||||||
impl<const L: ListKind> ListNode<L> {
|
impl<const L: ListKind> ListNode<L> {
|
||||||
/// How the list is labelled.
|
/// How the list is labelled.
|
||||||
#[property(referenced)]
|
#[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> {
|
impl<const L: ListKind> LayoutBlock for ListNode<L> {
|
||||||
fn layout_block(
|
fn layout_block(
|
||||||
&self,
|
&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.
|
/// Encode the item into a value.
|
||||||
fn encode(&self) -> Value {
|
fn encode(&self) -> Value {
|
||||||
match self {
|
match self {
|
||||||
|
@ -20,10 +20,6 @@ impl RefNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Show for 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> {
|
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(TextNode::packed(format_eco!("@{}", self.0)))
|
Ok(TextNode::packed(format_eco!("@{}", self.0)))
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::layout::{GridNode, TrackSizing, TrackSizings};
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// A table of items.
|
/// A table of items.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct TableNode {
|
pub struct TableNode {
|
||||||
/// Defines sizing for content rows and columns.
|
/// Defines sizing for content rows and columns.
|
||||||
pub tracks: Axes<Vec<TrackSizing>>,
|
pub tracks: Axes<Vec<TrackSizing>>,
|
||||||
@ -12,7 +12,7 @@ pub struct TableNode {
|
|||||||
pub cells: Vec<Content>,
|
pub cells: Vec<Content>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node(Show, LayoutBlock)]
|
#[node(LayoutBlock)]
|
||||||
impl TableNode {
|
impl TableNode {
|
||||||
/// How to fill the cells.
|
/// How to fill the cells.
|
||||||
#[property(referenced)]
|
#[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 {
|
impl LayoutBlock for TableNode {
|
||||||
fn layout_block(
|
fn layout_block(
|
||||||
&self,
|
&self,
|
||||||
|
@ -47,10 +47,6 @@ impl<const L: DecoLine> DecoNode<L> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<const L: DecoLine> Show for 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> {
|
fn show(&self, _: Tracked<dyn World>, styles: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(self.0.clone().styled(
|
Ok(self.0.clone().styled(
|
||||||
TextNode::DECO,
|
TextNode::DECO,
|
||||||
|
@ -50,14 +50,6 @@ impl LinkNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Show for 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> {
|
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(self.body.clone())
|
Ok(self.body.clone())
|
||||||
}
|
}
|
||||||
|
@ -528,10 +528,6 @@ impl StrongNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Show for 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> {
|
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(self.0.clone().styled(TextNode::BOLD, Toggle))
|
Ok(self.0.clone().styled(TextNode::BOLD, Toggle))
|
||||||
}
|
}
|
||||||
@ -556,10 +552,6 @@ impl EmphNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Show for 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> {
|
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(self.0.clone().styled(TextNode::ITALIC, Toggle))
|
Ok(self.0.clone().styled(TextNode::ITALIC, Toggle))
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,6 @@ impl RawNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Show for 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> {
|
fn show(&self, _: Tracked<dyn World>, styles: StyleChain) -> SourceResult<Content> {
|
||||||
let lang = styles.get(Self::LANG).as_ref().map(|s| s.to_lowercase());
|
let lang = styles.get(Self::LANG).as_ref().map(|s| s.to_lowercase());
|
||||||
let foreground = THEME
|
let foreground = THEME
|
||||||
|
@ -43,10 +43,6 @@ impl<const S: ShiftKind> ShiftNode<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<const S: ShiftKind> Show for ShiftNode<S> {
|
impl<const S: ShiftKind> Show for ShiftNode<S> {
|
||||||
fn unguard_parts(&self, _: RecipeId) -> Content {
|
|
||||||
Self(self.0.clone()).pack()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show(
|
fn show(
|
||||||
&self,
|
&self,
|
||||||
world: Tracked<dyn World>,
|
world: Tracked<dyn World>,
|
||||||
|
@ -20,7 +20,7 @@ use crate::World;
|
|||||||
/// - anything written between square brackets in Typst
|
/// - anything written between square brackets in Typst
|
||||||
/// - any constructor function
|
/// - any constructor function
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
pub struct Content(Arc<dyn Bounds>);
|
pub struct Content(Arc<dyn Bounds>, Vec<RecipeId>);
|
||||||
|
|
||||||
impl Content {
|
impl Content {
|
||||||
/// Create empty content.
|
/// Create empty content.
|
||||||
@ -112,16 +112,16 @@ impl Content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Style this content with a style entry.
|
/// 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>() {
|
if let Some(styled) = self.try_downcast_mut::<StyledNode>() {
|
||||||
styled.map.apply(entry);
|
styled.map.apply(style);
|
||||||
self
|
self
|
||||||
} else if let Some(styled) = self.downcast::<StyledNode>() {
|
} else if let Some(styled) = self.downcast::<StyledNode>() {
|
||||||
let mut map = styled.map.clone();
|
let mut map = styled.map.clone();
|
||||||
map.apply(entry);
|
map.apply(style);
|
||||||
StyledNode { sub: styled.sub.clone(), map }.pack()
|
StyledNode { sub: styled.sub.clone(), map }.pack()
|
||||||
} else {
|
} 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()
|
StyledNode { sub: self, map: styles }.pack()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reenable a specific show rule recipe.
|
/// Disable a show rule recipe.
|
||||||
pub fn unguard(&self, id: RecipeId) -> Self {
|
pub fn guard(mut self, id: RecipeId) -> Self {
|
||||||
self.clone().styled_with_entry(Style::Unguard(id))
|
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
|
where
|
||||||
Self: Debug + Hash + Sync + Send + Sized + 'static,
|
Self: Debug + Hash + Sync + Send + Sized + 'static,
|
||||||
{
|
{
|
||||||
Content(Arc::new(self))
|
Content(Arc::new(self), vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a node from the arguments.
|
/// Construct a node from the arguments.
|
||||||
|
@ -31,13 +31,6 @@ impl StyleMap {
|
|||||||
self.0.is_empty()
|
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.
|
/// Set an inner value for a style property.
|
||||||
///
|
///
|
||||||
/// If the property needs folding and the value is already contained in the
|
/// 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
|
/// Like [`chain`](Self::chain) or [`apply_map`](Self::apply_map), but with
|
||||||
/// only a entry.
|
/// only a entry.
|
||||||
pub fn apply(&mut self, entry: Style) {
|
pub fn apply(&mut self, style: Style) {
|
||||||
self.0.insert(0, entry);
|
self.0.insert(0, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply styles from `tail` in-place. The resulting style map is equivalent
|
/// Apply styles from `tail` in-place. The resulting style map is equivalent
|
||||||
@ -135,10 +128,6 @@ pub enum Style {
|
|||||||
Recipe(Recipe),
|
Recipe(Recipe),
|
||||||
/// A barrier for scoped styles.
|
/// A barrier for scoped styles.
|
||||||
Barrier(NodeId),
|
Barrier(NodeId),
|
||||||
/// Guards against recursive show rules.
|
|
||||||
Guard(RecipeId),
|
|
||||||
/// Allows recursive show rules again.
|
|
||||||
Unguard(RecipeId),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Style {
|
impl Style {
|
||||||
@ -190,8 +179,6 @@ impl Debug for Style {
|
|||||||
Self::Property(property) => property.fmt(f)?,
|
Self::Property(property) => property.fmt(f)?,
|
||||||
Self::Recipe(recipe) => recipe.fmt(f)?,
|
Self::Recipe(recipe) => recipe.fmt(f)?,
|
||||||
Self::Barrier(id) => write!(f, "Barrier for {id:?}")?,
|
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("]")
|
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]
|
#[capability]
|
||||||
pub trait Show: 'static + Sync + Send {
|
pub trait Show: 'static + Sync + Send {
|
||||||
/// Unguard nested content against a specific recipe.
|
/// Execute the base recipe for this node.
|
||||||
fn unguard_parts(&self, id: RecipeId) -> Content;
|
|
||||||
|
|
||||||
/// The base recipe for this node that is executed if there is no
|
|
||||||
/// user-defined show rule.
|
|
||||||
fn show(
|
fn show(
|
||||||
&self,
|
&self,
|
||||||
world: Tracked<dyn World>,
|
world: Tracked<dyn World>,
|
||||||
@ -356,9 +339,9 @@ pub trait Show: 'static + Sync + Send {
|
|||||||
/// Post-process a node after it was realized.
|
/// Post-process a node after it was realized.
|
||||||
#[capability]
|
#[capability]
|
||||||
pub trait Finalize: 'static + Sync + Send {
|
pub trait Finalize: 'static + Sync + Send {
|
||||||
/// Finalize this node given the realization of a base or user recipe. Use
|
/// Finalize the fully realized form of the node. Use this for effects that
|
||||||
/// this for effects that should work even in the face of a user-defined
|
/// should work even in the face of a user-defined show rule, for example
|
||||||
/// show rule, for example the linking behaviour of a link node.
|
/// the linking behaviour of a link node.
|
||||||
fn finalize(
|
fn finalize(
|
||||||
&self,
|
&self,
|
||||||
world: Tracked<dyn World>,
|
world: Tracked<dyn World>,
|
||||||
@ -400,7 +383,7 @@ impl Recipe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.transform.apply(world, self.span, || {
|
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, || {
|
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);
|
result.push(transformed);
|
||||||
@ -441,7 +424,7 @@ impl Recipe {
|
|||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(content.styled_with_entry(Style::Guard(sel))))
|
Ok(Some(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this recipe is for the given node.
|
/// Whether this recipe is for the given node.
|
||||||
@ -566,87 +549,41 @@ impl<'a> StyleChain<'a> {
|
|||||||
K::get(self, self.values(key))
|
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.
|
/// Apply show recipes in this style chain to a target.
|
||||||
pub fn apply(
|
pub fn show(
|
||||||
self,
|
self,
|
||||||
world: Tracked<dyn World>,
|
world: Tracked<dyn World>,
|
||||||
target: &Content,
|
target: &Content,
|
||||||
) -> SourceResult<Option<Content>> {
|
) -> SourceResult<Option<Content>> {
|
||||||
// Find out how many recipes there any and whether any of them match.
|
// Find out how many recipes there are.
|
||||||
let mut n = 0;
|
let mut n = self.entries().filter_map(Style::recipe).count();
|
||||||
let mut any = true;
|
|
||||||
for recipe in self.entries().filter_map(Style::recipe) {
|
|
||||||
n += 1;
|
|
||||||
any |= recipe.applicable(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find an applicable recipe.
|
// Find an applicable recipe.
|
||||||
let mut realized = None;
|
let mut realized = None;
|
||||||
let mut guarded = false;
|
for recipe in self.entries().filter_map(Style::recipe) {
|
||||||
if any {
|
let sel = RecipeId::Nth(n);
|
||||||
for recipe in self.entries().filter_map(Style::recipe) {
|
if recipe.applicable(target) && !target.guarded(sel) {
|
||||||
if recipe.applicable(target) {
|
if let Some(content) = recipe.apply(world, sel, target)? {
|
||||||
let sel = RecipeId::Nth(n);
|
realized = Some(content);
|
||||||
if self.guarded(sel) {
|
break;
|
||||||
guarded = true;
|
|
||||||
} else 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>() {
|
// Finalize only if this is the first application for this node.
|
||||||
// Realize if there was no matching recipe.
|
if let Some(node) = target.to::<dyn Finalize>() {
|
||||||
if realized.is_none() {
|
if target.pristine() {
|
||||||
let sel = RecipeId::Base(target.id());
|
if let Some(content) = realized {
|
||||||
if self.guarded(sel) {
|
realized = Some(node.finalize(world, self, content)?);
|
||||||
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)?);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -654,14 +591,17 @@ impl<'a> StyleChain<'a> {
|
|||||||
Ok(realized)
|
Ok(realized)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the recipe identified by the selector is guarded.
|
/// Whether the style chain has a matching recipe for the content.
|
||||||
fn guarded(self, sel: RecipeId) -> bool {
|
pub fn applicable(self, target: &Content) -> bool {
|
||||||
for entry in self.entries() {
|
// Find out how many recipes there are.
|
||||||
match *entry {
|
let mut n = self.entries().filter_map(Style::recipe).count();
|
||||||
Style::Guard(s) if s == sel => return true,
|
|
||||||
Style::Unguard(s) if s == sel => return false,
|
// 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
|
false
|
||||||
@ -689,7 +629,6 @@ impl<'a> StyleChain<'a> {
|
|||||||
entries: self.entries(),
|
entries: self.entries(),
|
||||||
key: PhantomData,
|
key: PhantomData,
|
||||||
barriers: 0,
|
barriers: 0,
|
||||||
guarded: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,7 +666,6 @@ struct Values<'a, K> {
|
|||||||
entries: Entries<'a>,
|
entries: Entries<'a>,
|
||||||
key: PhantomData<K>,
|
key: PhantomData<K>,
|
||||||
barriers: usize,
|
barriers: usize,
|
||||||
guarded: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
|
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 {
|
match entry {
|
||||||
Style::Property(property) => {
|
Style::Property(property) => {
|
||||||
if let Some(value) = property.downcast::<K>() {
|
if let Some(value) = property.downcast::<K>() {
|
||||||
if !property.scoped()
|
if !property.scoped() || self.barriers <= 1 {
|
||||||
|| if self.guarded {
|
|
||||||
self.barriers == 1
|
|
||||||
} else {
|
|
||||||
self.barriers <= 1
|
|
||||||
}
|
|
||||||
{
|
|
||||||
return Some(value);
|
return Some(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -752,9 +684,6 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
|
|||||||
Style::Barrier(id) => {
|
Style::Barrier(id) => {
|
||||||
self.barriers += (*id == K::node()) as usize;
|
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!
|
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.
|
// Test that replacements happen exactly once.
|
||||||
#show "A": [BB]
|
#show "A": [BB]
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
// Test sub- and superscipt shifts.
|
// Test sub- and superscipt shifts.
|
||||||
|
|
||||||
---
|
---
|
||||||
#table(columns: 3,
|
#table(
|
||||||
[Typo.], [Fallb.], [Synth],
|
columns: 3,
|
||||||
[x#super[1]], [x#super[5n]], [x#super[2 #square(width: 6pt)]],
|
[Typo.], [Fallb.], [Synth],
|
||||||
[x#sub[1]], [x#sub[5n]], [x#sub[2 #square(width: 6pt)]],
|
[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)
|
#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)
|
#set underline(stroke: 0.5pt, offset: 0.15em)
|
||||||
|
|
||||||
#underline[The claim#super[\[4\]]] has been disputed. \
|
#underline[The claim#super[\[4\]]] has been disputed. \
|
||||||
The claim#super[#underline[\[4\]]] has been disputed. \
|
The claim#super[#underline[\[4\]]] has been disputed. \
|
||||||
It really has been#super(box(text(baseline: 0pt, underline[\[4\]]))) \
|
It really has been#super(box(text(baseline: 0pt, underline[\[4\]]))) \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user