diff options
Diffstat (limited to 'crates/typst-library/src')
46 files changed, 424 insertions, 1886 deletions
diff --git a/crates/typst-library/src/foundations/content/element.rs b/crates/typst-library/src/foundations/content/element.rs index 49b0b0f9..65c2e28b 100644 --- a/crates/typst-library/src/foundations/content/element.rs +++ b/crates/typst-library/src/foundations/content/element.rs @@ -246,12 +246,6 @@ pub trait Synthesize { -> SourceResult<()>; } -/// Defines a built-in show rule for an element. -pub trait Show { - /// Execute the base recipe for this element. - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content>; -} - /// Defines built-in show set rules for an element. /// /// This is a bit more powerful than a user-defined show-set because it can diff --git a/crates/typst-library/src/foundations/context.rs b/crates/typst-library/src/foundations/context.rs index bf4bdcd2..56d87775 100644 --- a/crates/typst-library/src/foundations/context.rs +++ b/crates/typst-library/src/foundations/context.rs @@ -3,7 +3,7 @@ use comemo::Track; use crate::diag::{bail, Hint, HintedStrResult, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - elem, Args, Construct, Content, Func, Packed, Show, StyleChain, Value, + elem, Args, Construct, Content, Func, ShowFn, StyleChain, Value, }; use crate::introspection::{Locatable, Location}; @@ -61,7 +61,7 @@ fn require<T>(val: Option<T>) -> HintedStrResult<T> { } /// Executes a `context` block. -#[elem(Construct, Locatable, Show)] +#[elem(Construct, Locatable)] pub struct ContextElem { /// The function to call with the context. #[required] @@ -75,11 +75,8 @@ impl Construct for ContextElem { } } -impl Show for Packed<ContextElem> { - #[typst_macros::time(name = "context", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let loc = self.location().unwrap(); - let context = Context::new(Some(loc), Some(styles)); - Ok(self.func.call::<[Value; 0]>(engine, context.track(), [])?.display()) - } -} +pub const CONTEXT_RULE: ShowFn<ContextElem> = |elem, engine, styles| { + let loc = elem.location().unwrap(); + let context = Context::new(Some(loc), Some(styles)); + Ok(elem.func.call::<[Value; 0]>(engine, context.track(), [])?.display()) +}; diff --git a/crates/typst-library/src/foundations/styles.rs b/crates/typst-library/src/foundations/styles.rs index 978b47d5..0da036f6 100644 --- a/crates/typst-library/src/foundations/styles.rs +++ b/crates/typst-library/src/foundations/styles.rs @@ -1,4 +1,5 @@ use std::any::{Any, TypeId}; +use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::{mem, ptr}; @@ -13,7 +14,7 @@ use crate::diag::{SourceResult, Trace, Tracepoint}; use crate::engine::Engine; use crate::foundations::{ cast, ty, Content, Context, Element, Field, Func, NativeElement, OneOrMultiple, - RefableProperty, Repr, Selector, SettableProperty, + Packed, RefableProperty, Repr, Selector, SettableProperty, Target, }; use crate::text::{FontFamily, FontList, TextElem}; @@ -938,3 +939,129 @@ fn block_wrong_type(func: Element, id: u8, value: &Block) -> ! { value ) } + +/// Holds native show rules. +pub struct NativeRuleMap { + rules: HashMap<(Element, Target), NativeShowRule>, +} + +/// The signature of a native show rule. +pub type ShowFn<T> = fn( + elem: &Packed<T>, + engine: &mut Engine, + styles: StyleChain, +) -> SourceResult<Content>; + +impl NativeRuleMap { + /// Creates a new rule map. + /// + /// Should be populated with rules for all target-element combinations that + /// are supported. + /// + /// Contains built-in rules for a few special elements. + pub fn new() -> Self { + let mut rules = Self { rules: HashMap::new() }; + + // ContextElem is as special as SequenceElem and StyledElem and could, + // in theory, also be special cased in realization. + rules.register_builtin(crate::foundations::CONTEXT_RULE); + + // CounterDisplayElem only exists because the compiler can't currently + // express the equivalent of `context counter(..).display(..)` in native + // code (no native closures). + rules.register_builtin(crate::introspection::COUNTER_DISPLAY_RULE); + + // These are all only for introspection and empty on all targets. + rules.register_empty::<crate::introspection::CounterUpdateElem>(); + rules.register_empty::<crate::introspection::StateUpdateElem>(); + rules.register_empty::<crate::introspection::MetadataElem>(); + rules.register_empty::<crate::model::PrefixInfo>(); + + rules + } + + /// Registers a rule for all targets. + fn register_empty<T: NativeElement>(&mut self) { + self.register_builtin::<T>(|_, _, _| Ok(Content::empty())); + } + + /// Registers a rule for all targets. + fn register_builtin<T: NativeElement>(&mut self, f: ShowFn<T>) { + self.register(Target::Paged, f); + self.register(Target::Html, f); + } + + /// Registers a rule for a target. + /// + /// Panics if a rule already exists for this target-element combination. + pub fn register<T: NativeElement>(&mut self, target: Target, f: ShowFn<T>) { + let res = self.rules.insert((T::ELEM, target), NativeShowRule::new(f)); + if res.is_some() { + panic!( + "duplicate native show rule for `{}` on {target:?} target", + T::ELEM.name() + ) + } + } + + /// Retrieves the rule that applies to the `content` on the current + /// `target`. + pub fn get(&self, target: Target, content: &Content) -> Option<NativeShowRule> { + self.rules.get(&(content.func(), target)).copied() + } +} + +impl Default for NativeRuleMap { + fn default() -> Self { + Self::new() + } +} + +pub use rule::NativeShowRule; + +mod rule { + use super::*; + + /// The show rule for a native element. + #[derive(Copy, Clone)] + pub struct NativeShowRule { + /// The element to which this rule applies. + elem: Element, + /// Must only be called with content of the appropriate type. + f: unsafe fn( + elem: &Content, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Content>, + } + + impl NativeShowRule { + /// Create a new type-erased show rule. + pub fn new<T: NativeElement>(f: ShowFn<T>) -> Self { + Self { + elem: T::ELEM, + // Safety: The two function pointer types only differ in the + // first argument, which changes from `&Packed<T>` to + // `&Content`. `Packed<T>` is a transparent wrapper around + // `Content`. The resulting function is unsafe to call because + // content of the correct type must be passed to it. + #[allow(clippy::missing_transmute_annotations)] + f: unsafe { std::mem::transmute(f) }, + } + } + + /// Applies the rule to content. Panics if the content is of the wrong + /// type. + pub fn apply( + &self, + content: &Content, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Content> { + assert_eq!(content.elem(), self.elem); + + // Safety: We just checked that the element is of the correct type. + unsafe { (self.f)(content, engine, styles) } + } + } +} diff --git a/crates/typst-library/src/foundations/target.rs b/crates/typst-library/src/foundations/target.rs index 71e7554e..ff90f1f7 100644 --- a/crates/typst-library/src/foundations/target.rs +++ b/crates/typst-library/src/foundations/target.rs @@ -4,7 +4,7 @@ use crate::diag::HintedStrResult; use crate::foundations::{elem, func, Cast, Context}; /// The export target. -#[derive(Debug, Default, Copy, Clone, PartialEq, Hash, Cast)] +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Cast)] pub enum Target { /// The target that is used for paged, fully laid-out content. #[default] diff --git a/crates/typst-library/src/introspection/counter.rs b/crates/typst-library/src/introspection/counter.rs index a7925e13..b3c52de4 100644 --- a/crates/typst-library/src/introspection/counter.rs +++ b/crates/typst-library/src/introspection/counter.rs @@ -12,7 +12,7 @@ use crate::engine::{Engine, Route, Sink, Traced}; use crate::foundations::{ cast, elem, func, scope, select_where, ty, Args, Array, Construct, Content, Context, Element, Func, IntoValue, Label, LocatableSelector, NativeElement, Packed, Repr, - Selector, Show, Smart, Str, StyleChain, Value, + Selector, ShowFn, Smart, Str, StyleChain, Value, }; use crate::introspection::{Introspector, Locatable, Location, Tag}; use crate::layout::{Frame, FrameItem, PageElem}; @@ -683,8 +683,8 @@ cast! { } /// Executes an update of a counter. -#[elem(Construct, Locatable, Show, Count)] -struct CounterUpdateElem { +#[elem(Construct, Locatable, Count)] +pub struct CounterUpdateElem { /// The key that identifies the counter. #[required] key: CounterKey, @@ -701,12 +701,6 @@ impl Construct for CounterUpdateElem { } } -impl Show for Packed<CounterUpdateElem> { - fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(Content::empty()) - } -} - impl Count for Packed<CounterUpdateElem> { fn update(&self) -> Option<CounterUpdate> { Some(self.update.clone()) @@ -714,7 +708,7 @@ impl Count for Packed<CounterUpdateElem> { } /// Executes a display of a counter. -#[elem(Construct, Locatable, Show)] +#[elem(Construct, Locatable)] pub struct CounterDisplayElem { /// The counter. #[required] @@ -738,20 +732,18 @@ impl Construct for CounterDisplayElem { } } -impl Show for Packed<CounterDisplayElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(self - .counter - .display_impl( - engine, - self.location().unwrap(), - self.numbering.clone(), - self.both, - Some(styles), - )? - .display()) - } -} +pub const COUNTER_DISPLAY_RULE: ShowFn<CounterDisplayElem> = |elem, engine, styles| { + Ok(elem + .counter + .display_impl( + engine, + elem.location().unwrap(), + elem.numbering.clone(), + elem.both, + Some(styles), + )? + .display()) +}; /// An specialized handler of the page counter that tracks both the physical /// and the logical page counter. diff --git a/crates/typst-library/src/introspection/metadata.rs b/crates/typst-library/src/introspection/metadata.rs index 06000174..8ad74b96 100644 --- a/crates/typst-library/src/introspection/metadata.rs +++ b/crates/typst-library/src/introspection/metadata.rs @@ -1,6 +1,4 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, Packed, Show, StyleChain, Value}; +use crate::foundations::{elem, Value}; use crate::introspection::Locatable; /// Exposes a value to the query system without producing visible content. @@ -24,15 +22,9 @@ use crate::introspection::Locatable; /// query(<note>).first().value /// } /// ``` -#[elem(Show, Locatable)] +#[elem(Locatable)] pub struct MetadataElem { /// The value to embed into the document. #[required] pub value: Value, } - -impl Show for Packed<MetadataElem> { - fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { - Ok(Content::empty()) - } -} diff --git a/crates/typst-library/src/introspection/state.rs b/crates/typst-library/src/introspection/state.rs index 784f2acb..2d15a5de 100644 --- a/crates/typst-library/src/introspection/state.rs +++ b/crates/typst-library/src/introspection/state.rs @@ -6,8 +6,7 @@ use crate::diag::{bail, At, SourceResult}; use crate::engine::{Engine, Route, Sink, Traced}; use crate::foundations::{ cast, elem, func, scope, select_where, ty, Args, Construct, Content, Context, Func, - LocatableSelector, NativeElement, Packed, Repr, Selector, Show, Str, StyleChain, - Value, + LocatableSelector, NativeElement, Repr, Selector, Str, Value, }; use crate::introspection::{Introspector, Locatable, Location}; use crate::routines::Routines; @@ -372,8 +371,8 @@ cast! { } /// Executes a display of a state. -#[elem(Construct, Locatable, Show)] -struct StateUpdateElem { +#[elem(Construct, Locatable)] +pub struct StateUpdateElem { /// The key that identifies the state. #[required] key: Str, @@ -389,9 +388,3 @@ impl Construct for StateUpdateElem { bail!(args.span, "cannot be constructed manually"); } } - -impl Show for Packed<StateUpdateElem> { - fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(Content::empty()) - } -} diff --git a/crates/typst-library/src/layout/align.rs b/crates/typst-library/src/layout/align.rs index e5ceddf6..447648f0 100644 --- a/crates/typst-library/src/layout/align.rs +++ b/crates/typst-library/src/layout/align.rs @@ -2,11 +2,10 @@ use std::ops::Add; use ecow::{eco_format, EcoString}; -use crate::diag::{bail, HintedStrResult, SourceResult, StrResult}; -use crate::engine::Engine; +use crate::diag::{bail, HintedStrResult, StrResult}; use crate::foundations::{ - cast, elem, func, scope, ty, CastInfo, Content, Fold, FromValue, IntoValue, Packed, - Reflect, Repr, Resolve, Show, StyleChain, Value, + cast, elem, func, scope, ty, CastInfo, Content, Fold, FromValue, IntoValue, Reflect, + Repr, Resolve, StyleChain, Value, }; use crate::layout::{Abs, Axes, Axis, Dir, Side}; use crate::text::TextElem; @@ -73,7 +72,7 @@ use crate::text::TextElem; /// ```example /// Start #h(1fr) End /// ``` -#[elem(Show)] +#[elem] pub struct AlignElem { /// The [alignment] along both axes. /// @@ -97,13 +96,6 @@ pub struct AlignElem { pub body: Content, } -impl Show for Packed<AlignElem> { - #[typst_macros::time(name = "align", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(self.body.clone().aligned(self.alignment.get(styles))) - } -} - /// Where to align something along an axis. /// /// Possible values are: diff --git a/crates/typst-library/src/layout/columns.rs b/crates/typst-library/src/layout/columns.rs index 1cea5275..e7bce393 100644 --- a/crates/typst-library/src/layout/columns.rs +++ b/crates/typst-library/src/layout/columns.rs @@ -1,9 +1,7 @@ use std::num::NonZeroUsize; -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, NativeElement, Packed, Show, StyleChain}; -use crate::layout::{BlockElem, Length, Ratio, Rel}; +use crate::foundations::{elem, Content}; +use crate::layout::{Length, Ratio, Rel}; /// Separates a region into multiple equally sized columns. /// @@ -41,7 +39,7 @@ use crate::layout::{BlockElem, Length, Ratio, Rel}; /// /// #lorem(40) /// ``` -#[elem(Show)] +#[elem] pub struct ColumnsElem { /// The number of columns. #[positional] @@ -57,14 +55,6 @@ pub struct ColumnsElem { pub body: Content, } -impl Show for Packed<ColumnsElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::multi_layouter(self.clone(), engine.routines.layout_columns) - .pack() - .spanned(self.span())) - } -} - /// Forces a column break. /// /// The function will behave like a [page break]($pagebreak) when used in a diff --git a/crates/typst-library/src/layout/grid/mod.rs b/crates/typst-library/src/layout/grid/mod.rs index 64e7464b..658523ec 100644 --- a/crates/typst-library/src/layout/grid/mod.rs +++ b/crates/typst-library/src/layout/grid/mod.rs @@ -11,10 +11,10 @@ use crate::diag::{bail, At, HintedStrResult, HintedString, SourceResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, CastInfo, Content, Context, Fold, FromValue, Func, - IntoValue, NativeElement, Packed, Reflect, Resolve, Show, Smart, StyleChain, Value, + IntoValue, Packed, Reflect, Resolve, Smart, StyleChain, Value, }; use crate::layout::{ - Alignment, BlockElem, Length, OuterHAlignment, OuterVAlignment, Rel, Sides, Sizing, + Alignment, Length, OuterHAlignment, OuterVAlignment, Rel, Sides, Sizing, }; use crate::model::{TableCell, TableFooter, TableHLine, TableHeader, TableVLine}; use crate::visualize::{Paint, Stroke}; @@ -136,7 +136,7 @@ use crate::visualize::{Paint, Stroke}; /// /// Furthermore, strokes of a repeated grid header or footer will take /// precedence over regular cell strokes. -#[elem(scope, Show)] +#[elem(scope)] pub struct GridElem { /// The column sizes. /// @@ -320,14 +320,6 @@ impl GridElem { type GridFooter; } -impl Show for Packed<GridElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::multi_layouter(self.clone(), engine.routines.layout_grid) - .pack() - .spanned(self.span())) - } -} - /// Track sizing definitions. #[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct TrackSizings(pub SmallVec<[Sizing; 4]>); @@ -648,7 +640,7 @@ pub struct GridVLine { /// which allows you, for example, to apply styles based on a cell's position. /// Refer to the examples of the [`table.cell`]($table.cell) element to learn /// more about this. -#[elem(name = "cell", title = "Grid Cell", Show)] +#[elem(name = "cell", title = "Grid Cell")] pub struct GridCell { /// The cell's body. #[required] @@ -748,12 +740,6 @@ cast! { v: Content => v.into(), } -impl Show for Packed<GridCell> { - fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - show_grid_cell(self.body.clone(), self.inset.get(styles), self.align.get(styles)) - } -} - impl Default for Packed<GridCell> { fn default() -> Self { Packed::new( @@ -774,28 +760,6 @@ impl From<Content> for GridCell { } } -/// Function with common code to display a grid cell or table cell. -pub(crate) fn show_grid_cell( - mut body: Content, - inset: Smart<Sides<Option<Rel<Length>>>>, - align: Smart<Alignment>, -) -> SourceResult<Content> { - let inset = inset.unwrap_or_default().map(Option::unwrap_or_default); - - if inset != Sides::default() { - // Only pad if some inset is not 0pt. - // Avoids a bug where using .padded() in any way inside Show causes - // alignment in align(...) to break. - body = body.padded(inset); - } - - if let Smart::Custom(alignment) = align { - body = body.aligned(alignment); - } - - Ok(body) -} - /// A value that can be configured per cell. #[derive(Debug, Clone, PartialEq, Hash)] pub enum Celled<T> { diff --git a/crates/typst-library/src/layout/hide.rs b/crates/typst-library/src/layout/hide.rs index 5f3a5a2d..bb40447d 100644 --- a/crates/typst-library/src/layout/hide.rs +++ b/crates/typst-library/src/layout/hide.rs @@ -1,6 +1,4 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, Packed, Show, StyleChain}; +use crate::foundations::{elem, Content}; /// Hides content without affecting layout. /// @@ -14,7 +12,7 @@ use crate::foundations::{elem, Content, Packed, Show, StyleChain}; /// Hello Jane \ /// #hide[Hello] Joe /// ``` -#[elem(Show)] +#[elem] pub struct HideElem { /// The content to hide. #[required] @@ -25,10 +23,3 @@ pub struct HideElem { #[ghost] pub hidden: bool, } - -impl Show for Packed<HideElem> { - #[typst_macros::time(name = "hide", span = self.span())] - fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(self.body.clone().set(HideElem::hidden, true)) - } -} diff --git a/crates/typst-library/src/layout/layout.rs b/crates/typst-library/src/layout/layout.rs index 46271ff2..00897bcf 100644 --- a/crates/typst-library/src/layout/layout.rs +++ b/crates/typst-library/src/layout/layout.rs @@ -1,13 +1,7 @@ -use comemo::Track; use typst_syntax::Span; -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - dict, elem, func, Content, Context, Func, NativeElement, Packed, Show, StyleChain, -}; +use crate::foundations::{elem, func, Content, Func, NativeElement}; use crate::introspection::Locatable; -use crate::layout::{BlockElem, Size}; /// Provides access to the current outer container's (or page's, if none) /// dimensions (width and height). @@ -86,37 +80,9 @@ pub fn layout( } /// Executes a `layout` call. -#[elem(Locatable, Show)] -struct LayoutElem { +#[elem(Locatable)] +pub struct LayoutElem { /// The function to call with the outer container's (or page's) size. #[required] - func: Func, -} - -impl Show for Packed<LayoutElem> { - fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::multi_layouter( - self.clone(), - |elem, engine, locator, styles, regions| { - // Gets the current region's base size, which will be the size of the - // outer container, or of the page if there is no such container. - let Size { x, y } = regions.base(); - let loc = elem.location().unwrap(); - let context = Context::new(Some(loc), Some(styles)); - let result = elem - .func - .call( - engine, - context.track(), - [dict! { "width" => x, "height" => y }], - )? - .display(); - (engine.routines.layout_fragment)( - engine, &result, locator, styles, regions, - ) - }, - ) - .pack() - .spanned(self.span())) - } + pub func: Func, } diff --git a/crates/typst-library/src/layout/pad.rs b/crates/typst-library/src/layout/pad.rs index 1dc6d131..d533df35 100644 --- a/crates/typst-library/src/layout/pad.rs +++ b/crates/typst-library/src/layout/pad.rs @@ -1,7 +1,5 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, NativeElement, Packed, Show, StyleChain}; -use crate::layout::{BlockElem, Length, Rel}; +use crate::foundations::{elem, Content}; +use crate::layout::{Length, Rel}; /// Adds spacing around content. /// @@ -16,7 +14,7 @@ use crate::layout::{BlockElem, Length, Rel}; /// _Typing speeds can be /// measured in words per minute._ /// ``` -#[elem(title = "Padding", Show)] +#[elem(title = "Padding")] pub struct PadElem { /// The padding at the left side. #[parse( @@ -55,11 +53,3 @@ pub struct PadElem { #[required] pub body: Content, } - -impl Show for Packed<PadElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::multi_layouter(self.clone(), engine.routines.layout_pad) - .pack() - .spanned(self.span())) - } -} diff --git a/crates/typst-library/src/layout/repeat.rs b/crates/typst-library/src/layout/repeat.rs index 9579f185..a38d5f89 100644 --- a/crates/typst-library/src/layout/repeat.rs +++ b/crates/typst-library/src/layout/repeat.rs @@ -1,7 +1,5 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, NativeElement, Packed, Show, StyleChain}; -use crate::layout::{BlockElem, Length}; +use crate::foundations::{elem, Content}; +use crate::layout::Length; /// Repeats content to the available space. /// @@ -24,7 +22,7 @@ use crate::layout::{BlockElem, Length}; /// Berlin, the 22nd of December, 2022 /// ] /// ``` -#[elem(Show)] +#[elem] pub struct RepeatElem { /// The content to repeat. #[required] @@ -39,11 +37,3 @@ pub struct RepeatElem { #[default(true)] pub justify: bool, } - -impl Show for Packed<RepeatElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_repeat) - .pack() - .spanned(self.span())) - } -} diff --git a/crates/typst-library/src/layout/stack.rs b/crates/typst-library/src/layout/stack.rs index 5fc78480..fca1ecb8 100644 --- a/crates/typst-library/src/layout/stack.rs +++ b/crates/typst-library/src/layout/stack.rs @@ -1,9 +1,7 @@ use std::fmt::{self, Debug, Formatter}; -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{cast, elem, Content, NativeElement, Packed, Show, StyleChain}; -use crate::layout::{BlockElem, Dir, Spacing}; +use crate::foundations::{cast, elem, Content}; +use crate::layout::{Dir, Spacing}; /// Arranges content and spacing horizontally or vertically. /// @@ -19,7 +17,7 @@ use crate::layout::{BlockElem, Dir, Spacing}; /// rect(width: 90pt), /// ) /// ``` -#[elem(Show)] +#[elem] pub struct StackElem { /// The direction along which the items are stacked. Possible values are: /// @@ -47,14 +45,6 @@ pub struct StackElem { pub children: Vec<StackChild>, } -impl Show for Packed<StackElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::multi_layouter(self.clone(), engine.routines.layout_stack) - .pack() - .spanned(self.span())) - } -} - /// A child of a stack element. #[derive(Clone, PartialEq, Hash)] pub enum StackChild { diff --git a/crates/typst-library/src/layout/transform.rs b/crates/typst-library/src/layout/transform.rs index d153d97d..c2d9a21c 100644 --- a/crates/typst-library/src/layout/transform.rs +++ b/crates/typst-library/src/layout/transform.rs @@ -1,11 +1,5 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - cast, elem, Content, NativeElement, Packed, Show, Smart, StyleChain, -}; -use crate::layout::{ - Abs, Alignment, Angle, BlockElem, HAlignment, Length, Ratio, Rel, VAlignment, -}; +use crate::foundations::{cast, elem, Content, Smart}; +use crate::layout::{Abs, Alignment, Angle, HAlignment, Length, Ratio, Rel, VAlignment}; /// Moves content without affecting layout. /// @@ -25,7 +19,7 @@ use crate::layout::{ /// ) /// )) /// ``` -#[elem(Show)] +#[elem] pub struct MoveElem { /// The horizontal displacement of the content. pub dx: Rel<Length>, @@ -38,14 +32,6 @@ pub struct MoveElem { pub body: Content, } -impl Show for Packed<MoveElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_move) - .pack() - .spanned(self.span())) - } -} - /// Rotates content without affecting layout. /// /// Rotates an element by a given angle. The layout will act as if the element @@ -60,7 +46,7 @@ impl Show for Packed<MoveElem> { /// .map(i => rotate(24deg * i)[X]), /// ) /// ``` -#[elem(Show)] +#[elem] pub struct RotateElem { /// The amount of rotation. /// @@ -107,14 +93,6 @@ pub struct RotateElem { pub body: Content, } -impl Show for Packed<RotateElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_rotate) - .pack() - .spanned(self.span())) - } -} - /// Scales content without affecting layout. /// /// Lets you mirror content by specifying a negative scale on a single axis. @@ -125,7 +103,7 @@ impl Show for Packed<RotateElem> { /// #scale(x: -100%)[This is mirrored.] /// #scale(x: -100%, reflow: true)[This is mirrored.] /// ``` -#[elem(Show)] +#[elem] pub struct ScaleElem { /// The scaling factor for both axes, as a positional argument. This is just /// an optional shorthand notation for setting `x` and `y` to the same @@ -179,14 +157,6 @@ pub struct ScaleElem { pub body: Content, } -impl Show for Packed<ScaleElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_scale) - .pack() - .spanned(self.span())) - } -} - /// To what size something shall be scaled. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ScaleAmount { @@ -215,7 +185,7 @@ cast! { /// This is some fake italic text. /// ] /// ``` -#[elem(Show)] +#[elem] pub struct SkewElem { /// The horizontal skewing angle. /// @@ -265,14 +235,6 @@ pub struct SkewElem { pub body: Content, } -impl Show for Packed<SkewElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_skew) - .pack() - .spanned(self.span())) - } -} - /// A scale-skew-translate transformation. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct Transform { diff --git a/crates/typst-library/src/math/equation.rs b/crates/typst-library/src/math/equation.rs index b97bb18d..0c9ba11d 100644 --- a/crates/typst-library/src/math/equation.rs +++ b/crates/typst-library/src/math/equation.rs @@ -6,13 +6,11 @@ use unicode_math_class::MathClass; use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, ShowSet, Smart, StyleChain, Styles, - Synthesize, + elem, Content, NativeElement, Packed, ShowSet, Smart, StyleChain, Styles, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; use crate::layout::{ - AlignElem, Alignment, BlockElem, InlineElem, OuterHAlignment, SpecificAlignment, - VAlignment, + AlignElem, Alignment, BlockElem, OuterHAlignment, SpecificAlignment, VAlignment, }; use crate::math::{MathSize, MathVariant}; use crate::model::{Numbering, Outlinable, ParLine, Refable, Supplement}; @@ -46,7 +44,7 @@ use crate::text::{FontFamily, FontList, FontWeight, LocalName, TextElem}; /// least one space lifts it into a separate block that is centered /// horizontally. For more details about math syntax, see the /// [main math page]($category/math). -#[elem(Locatable, Synthesize, Show, ShowSet, Count, LocalName, Refable, Outlinable)] +#[elem(Locatable, Synthesize, ShowSet, Count, LocalName, Refable, Outlinable)] pub struct EquationElem { /// Whether the equation is displayed as a separate block. #[default(false)] @@ -165,23 +163,6 @@ impl Synthesize for Packed<EquationElem> { } } -impl Show for Packed<EquationElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if self.block.get(styles) { - Ok(BlockElem::multi_layouter( - self.clone(), - engine.routines.layout_equation_block, - ) - .pack() - .spanned(self.span())) - } else { - Ok(InlineElem::layouter(self.clone(), engine.routines.layout_equation_inline) - .pack() - .spanned(self.span())) - } - } -} - impl ShowSet for Packed<EquationElem> { fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); diff --git a/crates/typst-library/src/model/bibliography.rs b/crates/typst-library/src/model/bibliography.rs index c44748a9..188af4da 100644 --- a/crates/typst-library/src/model/bibliography.rs +++ b/crates/typst-library/src/model/bibliography.rs @@ -2,7 +2,6 @@ use std::any::TypeId; use std::collections::HashMap; use std::ffi::OsStr; use std::fmt::{self, Debug, Formatter}; -use std::num::NonZeroUsize; use std::path::Path; use std::sync::{Arc, LazyLock}; @@ -17,7 +16,7 @@ use hayagriva::{ use indexmap::IndexMap; use smallvec::{smallvec, SmallVec}; use typst_syntax::{Span, Spanned, SyntaxMode}; -use typst_utils::{Get, ManuallyHash, NonZeroExt, PicoStr}; +use typst_utils::{ManuallyHash, PicoStr}; use crate::diag::{ bail, error, At, HintedStrResult, LoadError, LoadResult, LoadedWithin, ReportPos, @@ -26,18 +25,17 @@ use crate::diag::{ use crate::engine::{Engine, Sink}; use crate::foundations::{ elem, Bytes, CastInfo, Content, Derived, FromValue, IntoValue, Label, NativeElement, - OneOrMultiple, Packed, Reflect, Scope, Show, ShowSet, Smart, StyleChain, Styles, + OneOrMultiple, Packed, Reflect, Scope, ShowSet, Smart, StyleChain, Styles, Synthesize, Value, }; use crate::introspection::{Introspector, Locatable, Location}; use crate::layout::{ BlockBody, BlockElem, Em, GridCell, GridChild, GridElem, GridItem, HElem, PadElem, - Sides, Sizing, TrackSizings, + Sizing, TrackSizings, }; use crate::loading::{format_yaml_error, DataSource, Load, LoadSource, Loaded}; use crate::model::{ - CitationForm, CiteGroup, Destination, FootnoteElem, HeadingElem, LinkElem, ParElem, - Url, + CitationForm, CiteGroup, Destination, FootnoteElem, HeadingElem, LinkElem, Url, }; use crate::routines::Routines; use crate::text::{ @@ -88,7 +86,7 @@ use crate::World; /// /// #bibliography("works.bib") /// ``` -#[elem(Locatable, Synthesize, Show, ShowSet, LocalName)] +#[elem(Locatable, Synthesize, ShowSet, LocalName)] pub struct BibliographyElem { /// One or multiple paths to or raw bytes for Hayagriva `.yaml` and/or /// BibLaTeX `.bib` files. @@ -203,84 +201,6 @@ impl Synthesize for Packed<BibliographyElem> { } } -impl Show for Packed<BibliographyElem> { - #[typst_macros::time(name = "bibliography", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - const COLUMN_GUTTER: Em = Em::new(0.65); - const INDENT: Em = Em::new(1.5); - - let span = self.span(); - - let mut seq = vec![]; - if let Some(title) = self.title.get_ref(styles).clone().unwrap_or_else(|| { - Some(TextElem::packed(Self::local_name_in(styles)).spanned(span)) - }) { - seq.push( - HeadingElem::new(title) - .with_depth(NonZeroUsize::ONE) - .pack() - .spanned(span), - ); - } - - let works = Works::generate(engine).at(span)?; - let references = works - .references - .as_ref() - .ok_or_else(|| match self.style.get_ref(styles).source { - CslSource::Named(style) => eco_format!( - "CSL style \"{}\" is not suitable for bibliographies", - style.display_name() - ), - CslSource::Normal(..) => { - "CSL style is not suitable for bibliographies".into() - } - }) - .at(span)?; - - if references.iter().any(|(prefix, _)| prefix.is_some()) { - let row_gutter = styles.get(ParElem::spacing); - - let mut cells = vec![]; - for (prefix, reference) in references { - cells.push(GridChild::Item(GridItem::Cell( - Packed::new(GridCell::new(prefix.clone().unwrap_or_default())) - .spanned(span), - ))); - cells.push(GridChild::Item(GridItem::Cell( - Packed::new(GridCell::new(reference.clone())).spanned(span), - ))); - } - seq.push( - GridElem::new(cells) - .with_columns(TrackSizings(smallvec![Sizing::Auto; 2])) - .with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()])) - .with_row_gutter(TrackSizings(smallvec![row_gutter.into()])) - .pack() - .spanned(span), - ); - } else { - for (_, reference) in references { - let realized = reference.clone(); - let block = if works.hanging_indent { - let body = HElem::new((-INDENT).into()).pack() + realized; - let inset = Sides::default() - .with(styles.resolve(TextElem::dir).start(), Some(INDENT.into())); - BlockElem::new() - .with_body(Some(BlockBody::Content(body))) - .with_inset(inset) - } else { - BlockElem::new().with_body(Some(BlockBody::Content(realized))) - }; - - seq.push(block.pack().spanned(span)); - } - } - - Ok(Content::sequence(seq)) - } -} - impl ShowSet for Packed<BibliographyElem> { fn show_set(&self, _: StyleChain) -> Styles { const INDENT: Em = Em::new(1.0); @@ -564,7 +484,7 @@ impl IntoValue for CslSource { /// memoization) for the whole document. This setup is necessary because /// citation formatting is inherently stateful and we need access to all /// citations to do it. -pub(super) struct Works { +pub struct Works { /// Maps from the location of a citation group to its rendered content. pub citations: HashMap<Location, SourceResult<Content>>, /// Lists all references in the bibliography, with optional prefix, or diff --git a/crates/typst-library/src/model/cite.rs b/crates/typst-library/src/model/cite.rs index 19513990..b3ae3e52 100644 --- a/crates/typst-library/src/model/cite.rs +++ b/crates/typst-library/src/model/cite.rs @@ -3,8 +3,7 @@ use typst_syntax::Spanned; use crate::diag::{error, At, HintedString, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, Cast, Content, Derived, Label, Packed, Show, Smart, StyleChain, - Synthesize, + cast, elem, Cast, Content, Derived, Label, Packed, Smart, StyleChain, Synthesize, }; use crate::introspection::Locatable; use crate::model::bibliography::Works; @@ -153,16 +152,15 @@ pub enum CitationForm { /// /// This is automatically created from adjacent citations during show rule /// application. -#[elem(Locatable, Show)] +#[elem(Locatable)] pub struct CiteGroup { /// The citations. #[required] pub children: Vec<Packed<CiteElem>>, } -impl Show for Packed<CiteGroup> { - #[typst_macros::time(name = "cite", span = self.span())] - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { +impl Packed<CiteGroup> { + pub fn realize(&self, engine: &mut Engine) -> SourceResult<Content> { let location = self.location().unwrap(); let span = self.span(); Works::generate(engine) diff --git a/crates/typst-library/src/model/emph.rs b/crates/typst-library/src/model/emph.rs index 2d9cbec1..6267736b 100644 --- a/crates/typst-library/src/model/emph.rs +++ b/crates/typst-library/src/model/emph.rs @@ -1,10 +1,4 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, StyleChain, TargetElem, -}; -use crate::html::{tag, HtmlElem}; -use crate::text::{ItalicToggle, TextElem}; +use crate::foundations::{elem, Content}; /// Emphasizes content by toggling italics. /// @@ -29,24 +23,9 @@ use crate::text::{ItalicToggle, TextElem}; /// This function also has dedicated syntax: To emphasize content, simply /// enclose it in underscores (`_`). Note that this only works at word /// boundaries. To emphasize part of a word, you have to use the function. -#[elem(title = "Emphasis", keywords = ["italic"], Show)] +#[elem(title = "Emphasis", keywords = ["italic"])] pub struct EmphElem { /// The content to emphasize. #[required] pub body: Content, } - -impl Show for Packed<EmphElem> { - #[typst_macros::time(name = "emph", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let body = self.body.clone(); - Ok(if styles.get(TargetElem::target).is_html() { - HtmlElem::new(tag::em) - .with_body(Some(body)) - .pack() - .spanned(self.span()) - } else { - body.set(TextElem::emph, ItalicToggle(true)) - }) - } -} diff --git a/crates/typst-library/src/model/enum.rs b/crates/typst-library/src/model/enum.rs index 8c191658..388fb9ed 100644 --- a/crates/typst-library/src/model/enum.rs +++ b/crates/typst-library/src/model/enum.rs @@ -1,19 +1,11 @@ use std::str::FromStr; -use ecow::eco_format; use smallvec::SmallVec; -use crate::diag::{bail, SourceResult}; -use crate::engine::Engine; -use crate::foundations::{ - cast, elem, scope, Array, Content, NativeElement, Packed, Show, Smart, StyleChain, - Styles, TargetElem, -}; -use crate::html::{attr, tag, HtmlElem}; -use crate::layout::{Alignment, BlockElem, Em, HAlignment, Length, VAlignment, VElem}; -use crate::model::{ - ListItemLike, ListLike, Numbering, NumberingPattern, ParElem, ParbreakElem, -}; +use crate::diag::bail; +use crate::foundations::{cast, elem, scope, Array, Content, Packed, Smart, Styles}; +use crate::layout::{Alignment, Em, HAlignment, Length, VAlignment}; +use crate::model::{ListItemLike, ListLike, Numbering, NumberingPattern}; /// A numbered list. /// @@ -71,7 +63,7 @@ use crate::model::{ /// Enumeration items can contain multiple paragraphs and other block-level /// content. All content that is indented more than an item's marker becomes /// part of that item. -#[elem(scope, title = "Numbered List", Show)] +#[elem(scope, title = "Numbered List")] pub struct EnumElem { /// Defines the default [spacing]($enum.spacing) of the enumeration. If it /// is `{false}`, the items are spaced apart with @@ -223,51 +215,6 @@ impl EnumElem { type EnumItem; } -impl Show for Packed<EnumElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let tight = self.tight.get(styles); - - if styles.get(TargetElem::target).is_html() { - let mut elem = HtmlElem::new(tag::ol); - if self.reversed.get(styles) { - elem = elem.with_attr(attr::reversed, "reversed"); - } - if let Some(n) = self.start.get(styles).custom() { - elem = elem.with_attr(attr::start, eco_format!("{n}")); - } - let body = Content::sequence(self.children.iter().map(|item| { - let mut li = HtmlElem::new(tag::li); - if let Some(nr) = item.number.get(styles) { - li = li.with_attr(attr::value, eco_format!("{nr}")); - } - // Text in wide enums shall always turn into paragraphs. - let mut body = item.body.clone(); - if !tight { - body += ParbreakElem::shared(); - } - li.with_body(Some(body)).pack().spanned(item.span()) - })); - return Ok(elem.with_body(Some(body)).pack().spanned(self.span())); - } - - let mut realized = - BlockElem::multi_layouter(self.clone(), engine.routines.layout_enum) - .pack() - .spanned(self.span()); - - if tight { - let spacing = self - .spacing - .get(styles) - .unwrap_or_else(|| styles.get(ParElem::leading)); - let v = VElem::new(spacing.into()).with_weak(true).with_attach(true).pack(); - realized = v + realized; - } - - Ok(realized) - } -} - /// An enumeration item. #[elem(name = "item", title = "Numbered List Item")] pub struct EnumItem { diff --git a/crates/typst-library/src/model/figure.rs b/crates/typst-library/src/model/figure.rs index 7ac659a9..ac3676ee 100644 --- a/crates/typst-library/src/model/figure.rs +++ b/crates/typst-library/src/model/figure.rs @@ -9,19 +9,16 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, select_where, Content, Element, NativeElement, Packed, Selector, - Show, ShowSet, Smart, StyleChain, Styles, Synthesize, TargetElem, + ShowSet, Smart, StyleChain, Styles, Synthesize, }; -use crate::html::{tag, HtmlElem}; use crate::introspection::{ Count, Counter, CounterKey, CounterUpdate, Locatable, Location, }; use crate::layout::{ - AlignElem, Alignment, BlockBody, BlockElem, Em, HAlignment, Length, OuterVAlignment, - PlaceElem, PlacementScope, VAlignment, VElem, -}; -use crate::model::{ - Numbering, NumberingPattern, Outlinable, ParbreakElem, Refable, Supplement, + AlignElem, Alignment, BlockElem, Em, Length, OuterVAlignment, PlacementScope, + VAlignment, }; +use crate::model::{Numbering, NumberingPattern, Outlinable, Refable, Supplement}; use crate::text::{Lang, Region, TextElem}; use crate::visualize::ImageElem; @@ -104,7 +101,7 @@ use crate::visualize::ImageElem; /// caption: [I'm up here], /// ) /// ``` -#[elem(scope, Locatable, Synthesize, Count, Show, ShowSet, Refable, Outlinable)] +#[elem(scope, Locatable, Synthesize, Count, ShowSet, Refable, Outlinable)] pub struct FigureElem { /// The content of the figure. Often, an [image]. #[required] @@ -328,65 +325,6 @@ impl Synthesize for Packed<FigureElem> { } } -impl Show for Packed<FigureElem> { - #[typst_macros::time(name = "figure", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let span = self.span(); - let target = styles.get(TargetElem::target); - let mut realized = self.body.clone(); - - // Build the caption, if any. - if let Some(caption) = self.caption.get_cloned(styles) { - let (first, second) = match caption.position.get(styles) { - OuterVAlignment::Top => (caption.pack(), realized), - OuterVAlignment::Bottom => (realized, caption.pack()), - }; - let mut seq = Vec::with_capacity(3); - seq.push(first); - if !target.is_html() { - let v = VElem::new(self.gap.get(styles).into()).with_weak(true); - seq.push(v.pack().spanned(span)) - } - seq.push(second); - realized = Content::sequence(seq) - } - - // Ensure that the body is considered a paragraph. - realized += ParbreakElem::shared().clone().spanned(span); - - if target.is_html() { - return Ok(HtmlElem::new(tag::figure) - .with_body(Some(realized)) - .pack() - .spanned(span)); - } - - // Wrap the contents in a block. - realized = BlockElem::new() - .with_body(Some(BlockBody::Content(realized))) - .pack() - .spanned(span); - - // Wrap in a float. - if let Some(align) = self.placement.get(styles) { - realized = PlaceElem::new(realized) - .with_alignment(align.map(|align| HAlignment::Center + align)) - .with_scope(self.scope.get(styles)) - .with_float(true) - .pack() - .spanned(span); - } else if self.scope.get(styles) == PlacementScope::Parent { - bail!( - span, - "parent-scoped placement is only available for floating figures"; - hint: "you can enable floating placement with `figure(placement: auto, ..)`" - ); - } - - Ok(realized) - } -} - impl ShowSet for Packed<FigureElem> { fn show_set(&self, _: StyleChain) -> Styles { // Still allows breakable figures with @@ -471,7 +409,7 @@ impl Outlinable for Packed<FigureElem> { /// caption: [A rectangle], /// ) /// ``` -#[elem(name = "caption", Synthesize, Show)] +#[elem(name = "caption", Synthesize)] pub struct FigureCaption { /// The caption's position in the figure. Either `{top}` or `{bottom}`. /// @@ -559,6 +497,35 @@ pub struct FigureCaption { } impl FigureCaption { + /// Realizes the textual caption content. + pub fn realize( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Content> { + let mut realized = self.body.clone(); + + if let ( + Some(Some(mut supplement)), + Some(Some(numbering)), + Some(Some(counter)), + Some(Some(location)), + ) = ( + self.supplement.clone(), + &self.numbering, + &self.counter, + &self.figure_location, + ) { + let numbers = counter.display_at_loc(engine, *location, styles, numbering)?; + if !supplement.is_empty() { + supplement += TextElem::packed('\u{a0}'); + } + realized = supplement + numbers + self.get_separator(styles) + realized; + } + + Ok(realized) + } + /// Gets the default separator in the given language and (optionally) /// region. fn local_separator(lang: Lang, _: Option<Region>) -> &'static str { @@ -588,43 +555,6 @@ impl Synthesize for Packed<FigureCaption> { } } -impl Show for Packed<FigureCaption> { - #[typst_macros::time(name = "figure.caption", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let mut realized = self.body.clone(); - - if let ( - Some(Some(mut supplement)), - Some(Some(numbering)), - Some(Some(counter)), - Some(Some(location)), - ) = ( - self.supplement.clone(), - &self.numbering, - &self.counter, - &self.figure_location, - ) { - let numbers = counter.display_at_loc(engine, *location, styles, numbering)?; - if !supplement.is_empty() { - supplement += TextElem::packed('\u{a0}'); - } - realized = supplement + numbers + self.get_separator(styles) + realized; - } - - Ok(if styles.get(TargetElem::target).is_html() { - HtmlElem::new(tag::figcaption) - .with_body(Some(realized)) - .pack() - .spanned(self.span()) - } else { - BlockElem::new() - .with_body(Some(BlockBody::Content(realized))) - .pack() - .spanned(self.span()) - }) - } -} - cast! { FigureCaption, v: Content => v.unpack::<Self>().unwrap_or_else(Self::new), diff --git a/crates/typst-library/src/model/footnote.rs b/crates/typst-library/src/model/footnote.rs index 63a461bd..b920a8ae 100644 --- a/crates/typst-library/src/model/footnote.rs +++ b/crates/typst-library/src/model/footnote.rs @@ -3,16 +3,16 @@ use std::str::FromStr; use typst_utils::NonZeroExt; -use crate::diag::{bail, At, SourceResult, StrResult}; +use crate::diag::{bail, StrResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Content, Label, NativeElement, Packed, Show, ShowSet, Smart, - StyleChain, Styles, + cast, elem, scope, Content, Label, NativeElement, Packed, ShowSet, Smart, StyleChain, + Styles, }; -use crate::introspection::{Count, Counter, CounterUpdate, Locatable, Location}; -use crate::layout::{Abs, Em, HElem, Length, Ratio}; -use crate::model::{Destination, Numbering, NumberingPattern, ParElem}; -use crate::text::{SuperElem, TextElem, TextSize}; +use crate::introspection::{Count, CounterUpdate, Locatable, Location}; +use crate::layout::{Abs, Em, Length, Ratio}; +use crate::model::{Numbering, NumberingPattern, ParElem}; +use crate::text::{TextElem, TextSize}; use crate::visualize::{LineElem, Stroke}; /// A footnote. @@ -51,7 +51,7 @@ use crate::visualize::{LineElem, Stroke}; /// apply to the footnote's content. See [here][issue] for more information. /// /// [issue]: https://github.com/typst/typst/issues/1467#issuecomment-1588799440 -#[elem(scope, Locatable, Show, Count)] +#[elem(scope, Locatable, Count)] pub struct FootnoteElem { /// How to number footnotes. /// @@ -135,21 +135,6 @@ impl Packed<FootnoteElem> { } } -impl Show for Packed<FootnoteElem> { - #[typst_macros::time(name = "footnote", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let span = self.span(); - let loc = self.declaration_location(engine).at(span)?; - let numbering = self.numbering.get_ref(styles); - let counter = Counter::of(FootnoteElem::ELEM); - let num = counter.display_at_loc(engine, loc, styles, numbering)?; - let sup = SuperElem::new(num).pack().spanned(span); - let loc = loc.variant(1); - // Add zero-width weak spacing to make the footnote "sticky". - Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc))) - } -} - impl Count for Packed<FootnoteElem> { fn update(&self) -> Option<CounterUpdate> { (!self.is_ref()).then(|| CounterUpdate::Step(NonZeroUsize::ONE)) @@ -191,7 +176,7 @@ cast! { /// page run is a sequence of pages without an explicit pagebreak in between). /// For this reason, set and show rules for footnote entries should be defined /// before any page content, typically at the very start of the document. -#[elem(name = "entry", title = "Footnote Entry", Show, ShowSet)] +#[elem(name = "entry", title = "Footnote Entry", ShowSet)] pub struct FootnoteEntry { /// The footnote for this entry. Its location can be used to determine /// the footnote counter state. @@ -274,37 +259,6 @@ pub struct FootnoteEntry { pub indent: Length, } -impl Show for Packed<FootnoteEntry> { - #[typst_macros::time(name = "footnote.entry", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let span = self.span(); - let number_gap = Em::new(0.05); - let default = StyleChain::default(); - let numbering = self.note.numbering.get_ref(default); - let counter = Counter::of(FootnoteElem::ELEM); - let Some(loc) = self.note.location() else { - bail!( - span, "footnote entry must have a location"; - hint: "try using a query or a show rule to customize the footnote instead" - ); - }; - - let num = counter.display_at_loc(engine, loc, styles, numbering)?; - let sup = SuperElem::new(num) - .pack() - .spanned(span) - .linked(Destination::Location(loc)) - .located(loc.variant(1)); - - Ok(Content::sequence([ - HElem::new(self.indent.get(styles).into()).pack(), - sup, - HElem::new(number_gap.into()).with_weak(true).pack(), - self.note.body_content().unwrap().clone(), - ])) - } -} - impl ShowSet for Packed<FootnoteEntry> { fn show_set(&self, _: StyleChain) -> Styles { let mut out = Styles::new(); diff --git a/crates/typst-library/src/model/heading.rs b/crates/typst-library/src/model/heading.rs index d6f6d01f..0f2a1d33 100644 --- a/crates/typst-library/src/model/heading.rs +++ b/crates/typst-library/src/model/heading.rs @@ -1,21 +1,16 @@ use std::num::NonZeroUsize; -use ecow::eco_format; -use typst_utils::{Get, NonZeroExt}; +use typst_utils::NonZeroExt; -use crate::diag::{warning, SourceResult}; +use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - elem, Content, NativeElement, Packed, Resolve, Show, ShowSet, Smart, StyleChain, - Styles, Synthesize, TargetElem, + elem, Content, NativeElement, Packed, ShowSet, Smart, StyleChain, Styles, Synthesize, }; -use crate::html::{attr, tag, HtmlElem}; -use crate::introspection::{ - Count, Counter, CounterUpdate, Locatable, Locator, LocatorLink, -}; -use crate::layout::{Abs, Axes, BlockBody, BlockElem, Em, HElem, Length, Region, Sides}; +use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; +use crate::layout::{BlockElem, Em, Length}; use crate::model::{Numbering, Outlinable, Refable, Supplement}; -use crate::text::{FontWeight, LocalName, SpaceElem, TextElem, TextSize}; +use crate::text::{FontWeight, LocalName, TextElem, TextSize}; /// A section heading. /// @@ -49,7 +44,7 @@ use crate::text::{FontWeight, LocalName, SpaceElem, TextElem, TextSize}; /// one or multiple equals signs, followed by a space. The number of equals /// signs determines the heading's logical nesting depth. The `{offset}` field /// can be set to configure the starting depth. -#[elem(Locatable, Synthesize, Count, Show, ShowSet, LocalName, Refable, Outlinable)] +#[elem(Locatable, Synthesize, Count, ShowSet, LocalName, Refable, Outlinable)] pub struct HeadingElem { /// The absolute nesting depth of the heading, starting from one. If set /// to `{auto}`, it is computed from `{offset + depth}`. @@ -215,96 +210,6 @@ impl Synthesize for Packed<HeadingElem> { } } -impl Show for Packed<HeadingElem> { - #[typst_macros::time(name = "heading", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let html = styles.get(TargetElem::target).is_html(); - - const SPACING_TO_NUMBERING: Em = Em::new(0.3); - - let span = self.span(); - let mut realized = self.body.clone(); - - let hanging_indent = self.hanging_indent.get(styles); - let mut indent = match hanging_indent { - Smart::Custom(length) => length.resolve(styles), - Smart::Auto => Abs::zero(), - }; - - if let Some(numbering) = self.numbering.get_ref(styles).as_ref() { - let location = self.location().unwrap(); - let numbering = Counter::of(HeadingElem::ELEM) - .display_at_loc(engine, location, styles, numbering)? - .spanned(span); - - if hanging_indent.is_auto() && !html { - let pod = Region::new(Axes::splat(Abs::inf()), Axes::splat(false)); - - // We don't have a locator for the numbering here, so we just - // use the measurement infrastructure for now. - let link = LocatorLink::measure(location); - let size = (engine.routines.layout_frame)( - engine, - &numbering, - Locator::link(&link), - styles, - pod, - )? - .size(); - - indent = size.x + SPACING_TO_NUMBERING.resolve(styles); - } - - let spacing = if html { - SpaceElem::shared().clone() - } else { - HElem::new(SPACING_TO_NUMBERING.into()).with_weak(true).pack() - }; - - realized = numbering + spacing + realized; - } - - Ok(if html { - // HTML's h1 is closer to a title element. There should only be one. - // Meanwhile, a level 1 Typst heading is a section heading. For this - // reason, levels are offset by one: A Typst level 1 heading becomes - // a `<h2>`. - let level = self.resolve_level(styles).get(); - if level >= 6 { - engine.sink.warn(warning!(span, - "heading of level {} was transformed to \ - <div role=\"heading\" aria-level=\"{}\">, which is not \ - supported by all assistive technology", - level, level + 1; - hint: "HTML only supports <h1> to <h6>, not <h{}>", level + 1; - hint: "you may want to restructure your document so that \ - it doesn't contain deep headings")); - HtmlElem::new(tag::div) - .with_body(Some(realized)) - .with_attr(attr::role, "heading") - .with_attr(attr::aria_level, eco_format!("{}", level + 1)) - .pack() - .spanned(span) - } else { - let t = [tag::h2, tag::h3, tag::h4, tag::h5, tag::h6][level - 1]; - HtmlElem::new(t).with_body(Some(realized)).pack().spanned(span) - } - } else { - let block = if indent != Abs::zero() { - let body = HElem::new((-indent).into()).pack() + realized; - let inset = Sides::default() - .with(styles.resolve(TextElem::dir).start(), Some(indent.into())); - BlockElem::new() - .with_body(Some(BlockBody::Content(body))) - .with_inset(inset) - } else { - BlockElem::new().with_body(Some(BlockBody::Content(realized))) - }; - block.pack().spanned(span) - }) - } -} - impl ShowSet for Packed<HeadingElem> { fn show_set(&self, styles: StyleChain) -> Styles { let level = self.resolve_level(styles).get(); diff --git a/crates/typst-library/src/model/link.rs b/crates/typst-library/src/model/link.rs index 1e2c708e..c630835e 100644 --- a/crates/typst-library/src/model/link.rs +++ b/crates/typst-library/src/model/link.rs @@ -2,13 +2,10 @@ use std::ops::Deref; use ecow::{eco_format, EcoString}; -use crate::diag::{bail, warning, At, SourceResult, StrResult}; -use crate::engine::Engine; +use crate::diag::{bail, StrResult}; use crate::foundations::{ - cast, elem, Content, Label, NativeElement, Packed, Repr, Show, ShowSet, Smart, - StyleChain, Styles, TargetElem, + cast, elem, Content, Label, Packed, Repr, ShowSet, Smart, StyleChain, Styles, }; -use crate::html::{attr, tag, HtmlElem}; use crate::introspection::Location; use crate::layout::Position; use crate::text::TextElem; @@ -38,7 +35,7 @@ use crate::text::TextElem; /// # Syntax /// This function also has dedicated syntax: Text that starts with `http://` or /// `https://` is automatically turned into a link. -#[elem(Show)] +#[elem] pub struct LinkElem { /// The destination the link points to. /// @@ -103,38 +100,6 @@ impl LinkElem { } } -impl Show for Packed<LinkElem> { - #[typst_macros::time(name = "link", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let body = self.body.clone(); - - Ok(if styles.get(TargetElem::target).is_html() { - if let LinkTarget::Dest(Destination::Url(url)) = &self.dest { - HtmlElem::new(tag::a) - .with_attr(attr::href, url.clone().into_inner()) - .with_body(Some(body)) - .pack() - .spanned(self.span()) - } else { - engine.sink.warn(warning!( - self.span(), - "non-URL links are not yet supported by HTML export" - )); - body - } - } else { - match &self.dest { - LinkTarget::Dest(dest) => body.linked(dest.clone()), - LinkTarget::Label(label) => { - let elem = engine.introspector.query_label(*label).at(self.span())?; - let dest = Destination::Location(elem.location().unwrap()); - body.clone().linked(dest) - } - } - }) - } -} - impl ShowSet for Packed<LinkElem> { fn show_set(&self, _: StyleChain) -> Styles { let mut out = Styles::new(); diff --git a/crates/typst-library/src/model/list.rs b/crates/typst-library/src/model/list.rs index 5e6db1fa..660716de 100644 --- a/crates/typst-library/src/model/list.rs +++ b/crates/typst-library/src/model/list.rs @@ -3,12 +3,10 @@ use comemo::Track; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Array, Content, Context, Depth, Func, NativeElement, Packed, Show, - Smart, StyleChain, Styles, TargetElem, Value, + cast, elem, scope, Array, Content, Context, Depth, Func, NativeElement, Packed, + Smart, StyleChain, Styles, Value, }; -use crate::html::{tag, HtmlElem}; -use crate::layout::{BlockElem, Em, Length, VElem}; -use crate::model::{ParElem, ParbreakElem}; +use crate::layout::{Em, Length}; use crate::text::TextElem; /// A bullet list. @@ -42,7 +40,7 @@ use crate::text::TextElem; /// followed by a space to create a list item. A list item can contain multiple /// paragraphs and other block-level content. All content that is indented /// more than an item's marker becomes part of that item. -#[elem(scope, title = "Bullet List", Show)] +#[elem(scope, title = "Bullet List")] pub struct ListElem { /// Defines the default [spacing]($list.spacing) of the list. If it is /// `{false}`, the items are spaced apart with @@ -136,45 +134,6 @@ impl ListElem { type ListItem; } -impl Show for Packed<ListElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let tight = self.tight.get(styles); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::ul) - .with_body(Some(Content::sequence(self.children.iter().map(|item| { - // Text in wide lists shall always turn into paragraphs. - let mut body = item.body.clone(); - if !tight { - body += ParbreakElem::shared(); - } - HtmlElem::new(tag::li) - .with_body(Some(body)) - .pack() - .spanned(item.span()) - })))) - .pack() - .spanned(self.span())); - } - - let mut realized = - BlockElem::multi_layouter(self.clone(), engine.routines.layout_list) - .pack() - .spanned(self.span()); - - if tight { - let spacing = self - .spacing - .get(styles) - .unwrap_or_else(|| styles.get(ParElem::leading)); - let v = VElem::new(spacing.into()).with_weak(true).with_attach(true).pack(); - realized = v + realized; - } - - Ok(realized) - } -} - /// A bullet list item. #[elem(name = "item", title = "Bullet List Item")] pub struct ListItem { diff --git a/crates/typst-library/src/model/mod.rs b/crates/typst-library/src/model/mod.rs index 9bdbf001..a0f7e11a 100644 --- a/crates/typst-library/src/model/mod.rs +++ b/crates/typst-library/src/model/mod.rs @@ -46,23 +46,23 @@ use crate::foundations::Scope; pub fn define(global: &mut Scope) { global.start_category(crate::Category::Model); global.define_elem::<DocumentElem>(); - global.define_elem::<RefElem>(); + global.define_elem::<ParElem>(); + global.define_elem::<ParbreakElem>(); + global.define_elem::<StrongElem>(); + global.define_elem::<EmphElem>(); + global.define_elem::<ListElem>(); + global.define_elem::<EnumElem>(); + global.define_elem::<TermsElem>(); global.define_elem::<LinkElem>(); - global.define_elem::<OutlineElem>(); global.define_elem::<HeadingElem>(); global.define_elem::<FigureElem>(); - global.define_elem::<FootnoteElem>(); global.define_elem::<QuoteElem>(); + global.define_elem::<FootnoteElem>(); + global.define_elem::<OutlineElem>(); + global.define_elem::<RefElem>(); global.define_elem::<CiteElem>(); global.define_elem::<BibliographyElem>(); - global.define_elem::<EnumElem>(); - global.define_elem::<ListElem>(); - global.define_elem::<ParbreakElem>(); - global.define_elem::<ParElem>(); global.define_elem::<TableElem>(); - global.define_elem::<TermsElem>(); - global.define_elem::<EmphElem>(); - global.define_elem::<StrongElem>(); global.define_func::<numbering>(); global.reset_category(); } diff --git a/crates/typst-library/src/model/outline.rs b/crates/typst-library/src/model/outline.rs index bb061fb7..4bda02ba 100644 --- a/crates/typst-library/src/model/outline.rs +++ b/crates/typst-library/src/model/outline.rs @@ -1,7 +1,7 @@ use std::num::NonZeroUsize; use std::str::FromStr; -use comemo::{Track, Tracked}; +use comemo::Tracked; use smallvec::SmallVec; use typst_syntax::Span; use typst_utils::{Get, NonZeroExt}; @@ -10,7 +10,7 @@ use crate::diag::{bail, error, At, HintedStrResult, SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, func, scope, select_where, Args, Construct, Content, Context, Func, - LocatableSelector, NativeElement, Packed, Resolve, Show, ShowSet, Smart, StyleChain, + LocatableSelector, NativeElement, Packed, Resolve, ShowSet, Smart, StyleChain, Styles, }; use crate::introspection::{ @@ -20,8 +20,7 @@ use crate::layout::{ Abs, Axes, BlockBody, BlockElem, BoxElem, Dir, Em, Fr, HElem, Length, Region, Rel, RepeatElem, Sides, }; -use crate::math::EquationElem; -use crate::model::{Destination, HeadingElem, NumberingPattern, ParElem, Refable}; +use crate::model::{HeadingElem, NumberingPattern, ParElem, Refable}; use crate::text::{LocalName, SpaceElem, TextElem}; /// A table of contents, figures, or other elements. @@ -147,7 +146,7 @@ use crate::text::{LocalName, SpaceElem, TextElem}; /// /// [^1]: The outline of equations is the exception to this rule as it does not /// have a body and thus does not use indented layout. -#[elem(scope, keywords = ["Table of Contents", "toc"], Show, ShowSet, LocalName, Locatable)] +#[elem(scope, keywords = ["Table of Contents", "toc"], ShowSet, LocalName, Locatable)] pub struct OutlineElem { /// The title of the outline. /// @@ -249,44 +248,6 @@ impl OutlineElem { type OutlineEntry; } -impl Show for Packed<OutlineElem> { - #[typst_macros::time(name = "outline", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let span = self.span(); - - // Build the outline title. - let mut seq = vec![]; - if let Some(title) = self.title.get_cloned(styles).unwrap_or_else(|| { - Some(TextElem::packed(Self::local_name_in(styles)).spanned(span)) - }) { - seq.push( - HeadingElem::new(title) - .with_depth(NonZeroUsize::ONE) - .pack() - .spanned(span), - ); - } - - let elems = engine.introspector.query(&self.target.get_ref(styles).0); - let depth = self.depth.get(styles).unwrap_or(NonZeroUsize::MAX); - - // Build the outline entries. - for elem in elems { - let Some(outlinable) = elem.with::<dyn Outlinable>() else { - bail!(span, "cannot outline {}", elem.func().name()); - }; - - let level = outlinable.level(); - if outlinable.outlined() && level <= depth { - let entry = OutlineEntry::new(level, elem); - seq.push(entry.pack().spanned(span)); - } - } - - Ok(Content::sequence(seq)) - } -} - impl ShowSet for Packed<OutlineElem> { fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); @@ -363,7 +324,7 @@ pub trait Outlinable: Refable { /// With show-set and show rules on outline entries, you can richly customize /// the outline's appearance. See the /// [section on styling the outline]($outline/#styling-the-outline) for details. -#[elem(scope, name = "entry", title = "Outline Entry", Show)] +#[elem(scope, name = "entry", title = "Outline Entry")] pub struct OutlineEntry { /// The nesting level of this outline entry. Starts at `{1}` for top-level /// entries. @@ -408,30 +369,6 @@ pub struct OutlineEntry { pub parent: Option<Packed<OutlineElem>>, } -impl Show for Packed<OutlineEntry> { - #[typst_macros::time(name = "outline.entry", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let span = self.span(); - let context = Context::new(None, Some(styles)); - let context = context.track(); - - let prefix = self.prefix(engine, context, span)?; - let inner = self.inner(engine, context, span)?; - let block = if self.element.is::<EquationElem>() { - let body = prefix.unwrap_or_default() + inner; - BlockElem::new() - .with_body(Some(BlockBody::Content(body))) - .pack() - .spanned(span) - } else { - self.indented(engine, context, span, prefix, inner, Em::new(0.5).into())? - }; - - let loc = self.element_location().at(span)?; - Ok(block.linked(Destination::Location(loc))) - } -} - #[scope] impl OutlineEntry { /// A helper function for producing an indented entry layout: Lays out a @@ -654,7 +591,8 @@ impl OutlineEntry { .ok_or_else(|| error!("cannot outline {}", self.element.func().name())) } - fn element_location(&self) -> HintedStrResult<Location> { + /// Returns the location of the outlined element. + pub fn element_location(&self) -> HintedStrResult<Location> { let elem = &self.element; elem.location().ok_or_else(|| { if elem.can::<dyn Locatable>() && elem.can::<dyn Outlinable>() { @@ -730,8 +668,8 @@ fn query_prefix_widths( } /// Helper type for introspection-based prefix alignment. -#[elem(Construct, Locatable, Show)] -struct PrefixInfo { +#[elem(Construct, Locatable)] +pub(crate) struct PrefixInfo { /// The location of the outline this prefix is part of. This is used to /// scope prefix computations to a specific outline. #[required] @@ -753,9 +691,3 @@ impl Construct for PrefixInfo { bail!(args.span, "cannot be constructed manually"); } } - -impl Show for Packed<PrefixInfo> { - fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(Content::empty()) - } -} diff --git a/crates/typst-library/src/model/quote.rs b/crates/typst-library/src/model/quote.rs index a8cf3eae..9960b758 100644 --- a/crates/typst-library/src/model/quote.rs +++ b/crates/typst-library/src/model/quote.rs @@ -1,16 +1,13 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; +use typst_syntax::Span; + use crate::foundations::{ - cast, elem, Content, Depth, Label, NativeElement, Packed, Show, ShowSet, Smart, - StyleChain, Styles, TargetElem, + cast, elem, Content, Depth, Label, NativeElement, Packed, ShowSet, Smart, StyleChain, + Styles, }; -use crate::html::{attr, tag, HtmlElem}; use crate::introspection::Locatable; -use crate::layout::{ - Alignment, BlockBody, BlockElem, Em, HElem, PadElem, Spacing, VElem, -}; -use crate::model::{CitationForm, CiteElem, Destination, LinkElem, LinkTarget}; -use crate::text::{SmartQuoteElem, SmartQuotes, SpaceElem, TextElem}; +use crate::layout::{BlockElem, Em, PadElem}; +use crate::model::{CitationForm, CiteElem}; +use crate::text::{SmartQuotes, SpaceElem, TextElem}; /// Displays a quote alongside an optional attribution. /// @@ -44,7 +41,7 @@ use crate::text::{SmartQuoteElem, SmartQuotes, SpaceElem, TextElem}; /// flame of Udûn. Go back to the Shadow! You cannot pass. /// ] /// ``` -#[elem(Locatable, ShowSet, Show)] +#[elem(Locatable, ShowSet)] pub struct QuoteElem { /// Whether this is a block quote. /// @@ -62,7 +59,7 @@ pub struct QuoteElem { /// Ich bin ein Berliner. /// ] /// ``` - block: bool, + pub block: bool, /// Whether double quotes should be added around this quote. /// @@ -88,7 +85,7 @@ pub struct QuoteElem { /// translate the quote: /// #quote[I am a Berliner.] /// ``` - quotes: Smart<bool>, + pub quotes: Smart<bool>, /// The attribution of this quote, usually the author or source. Can be a /// label pointing to a bibliography entry or any content. By default only @@ -123,17 +120,36 @@ pub struct QuoteElem { /// /// #bibliography("works.bib", style: "apa") /// ``` - attribution: Option<Attribution>, + pub attribution: Option<Attribution>, /// The quote. #[required] - body: Content, + pub body: Content, /// The nesting depth. #[internal] #[fold] #[ghost] - depth: Depth, + pub depth: Depth, +} + +impl QuoteElem { + /// Quotes the body content with the appropriate quotes based on the current + /// styles and surroundings. + pub fn quoted(body: Content, styles: StyleChain<'_>) -> Content { + let quotes = SmartQuotes::get_in(styles); + + // Alternate between single and double quotes. + let Depth(depth) = styles.get(QuoteElem::depth); + let double = depth % 2 == 0; + + Content::sequence([ + TextElem::packed(quotes.open(double)), + body, + TextElem::packed(quotes.close(double)), + ]) + .set(QuoteElem::depth, Depth(1)) + } } /// Attribution for a [quote](QuoteElem). @@ -143,6 +159,23 @@ pub enum Attribution { Label(Label), } +impl Attribution { + /// Realize as an em dash followed by text or a citation. + pub fn realize(&self, span: Span) -> Content { + Content::sequence([ + TextElem::packed('—'), + SpaceElem::shared().clone(), + match self { + Attribution::Content(content) => content.clone(), + Attribution::Label(label) => CiteElem::new(*label) + .with_form(Some(CitationForm::Prose)) + .pack() + .spanned(span), + }, + ]) + } +} + cast! { Attribution, self => match self { @@ -153,96 +186,6 @@ cast! { label: Label => Self::Label(label), } -impl Show for Packed<QuoteElem> { - #[typst_macros::time(name = "quote", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let mut realized = self.body.clone(); - let block = self.block.get(styles); - let html = styles.get(TargetElem::target).is_html(); - - if self.quotes.get(styles).unwrap_or(!block) { - let quotes = SmartQuotes::get( - styles.get_ref(SmartQuoteElem::quotes), - styles.get(TextElem::lang), - styles.get(TextElem::region), - styles.get(SmartQuoteElem::alternative), - ); - - // Alternate between single and double quotes. - let Depth(depth) = styles.get(QuoteElem::depth); - let double = depth % 2 == 0; - - if !html { - // Add zero-width weak spacing to make the quotes "sticky". - let hole = HElem::hole().pack(); - realized = Content::sequence([hole.clone(), realized, hole]); - } - realized = Content::sequence([ - TextElem::packed(quotes.open(double)), - realized, - TextElem::packed(quotes.close(double)), - ]) - .set(QuoteElem::depth, Depth(1)); - } - - let attribution = self.attribution.get_ref(styles); - - if block { - realized = if html { - let mut elem = HtmlElem::new(tag::blockquote).with_body(Some(realized)); - if let Some(Attribution::Content(attribution)) = attribution { - if let Some(link) = attribution.to_packed::<LinkElem>() { - if let LinkTarget::Dest(Destination::Url(url)) = &link.dest { - elem = elem.with_attr(attr::cite, url.clone().into_inner()); - } - } - } - elem.pack() - } else { - BlockElem::new().with_body(Some(BlockBody::Content(realized))).pack() - } - .spanned(self.span()); - - if let Some(attribution) = attribution { - let attribution = match attribution { - Attribution::Content(content) => content.clone(), - Attribution::Label(label) => CiteElem::new(*label) - .with_form(Some(CitationForm::Prose)) - .pack() - .spanned(self.span()), - }; - let attribution = Content::sequence([ - TextElem::packed('—'), - SpaceElem::shared().clone(), - attribution, - ]); - - if html { - realized += attribution; - } else { - // Bring the attribution a bit closer to the quote. - let gap = Spacing::Rel(Em::new(0.9).into()); - let v = VElem::new(gap).with_weak(true).pack(); - realized += v; - realized += BlockElem::new() - .with_body(Some(BlockBody::Content(attribution))) - .pack() - .aligned(Alignment::END); - } - } - - if !html { - realized = PadElem::new(realized).pack(); - } - } else if let Some(Attribution::Label(label)) = attribution { - realized += SpaceElem::shared().clone() - + CiteElem::new(*label).pack().spanned(self.span()); - } - - Ok(realized) - } -} - impl ShowSet for Packed<QuoteElem> { fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); diff --git a/crates/typst-library/src/model/reference.rs b/crates/typst-library/src/model/reference.rs index 2d04a97a..4877409f 100644 --- a/crates/typst-library/src/model/reference.rs +++ b/crates/typst-library/src/model/reference.rs @@ -5,7 +5,7 @@ use crate::diag::{bail, At, Hint, SourceResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, Cast, Content, Context, Func, IntoValue, Label, NativeElement, Packed, - Repr, Show, Smart, StyleChain, Synthesize, + Repr, Smart, StyleChain, Synthesize, }; use crate::introspection::{Counter, CounterKey, Locatable}; use crate::math::EquationElem; @@ -134,7 +134,7 @@ use crate::text::TextElem; /// In @beginning we prove @pythagoras. /// $ a^2 + b^2 = c^2 $ <pythagoras> /// ``` -#[elem(title = "Reference", Synthesize, Locatable, Show)] +#[elem(title = "Reference", Synthesize, Locatable)] pub struct RefElem { /// The target label that should be referenced. /// @@ -220,9 +220,13 @@ impl Synthesize for Packed<RefElem> { } } -impl Show for Packed<RefElem> { - #[typst_macros::time(name = "ref", span = self.span())] - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { +impl Packed<RefElem> { + /// Realize as a linked, textual reference. + pub fn realize( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Content> { let elem = engine.introspector.query_label(self.target); let span = self.span(); @@ -242,7 +246,7 @@ impl Show for Packed<RefElem> { .at(span)?; let supplement = engine.introspector.page_supplement(loc); - return show_reference( + return realize_reference( self, engine, styles, @@ -306,7 +310,7 @@ impl Show for Packed<RefElem> { )) .at(span)?; - show_reference( + realize_reference( self, engine, styles, @@ -319,7 +323,7 @@ impl Show for Packed<RefElem> { } /// Show a reference. -fn show_reference( +fn realize_reference( reference: &Packed<RefElem>, engine: &mut Engine, styles: StyleChain, diff --git a/crates/typst-library/src/model/strong.rs b/crates/typst-library/src/model/strong.rs index 08cf4839..7751c95b 100644 --- a/crates/typst-library/src/model/strong.rs +++ b/crates/typst-library/src/model/strong.rs @@ -1,10 +1,4 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, StyleChain, TargetElem, -}; -use crate::html::{tag, HtmlElem}; -use crate::text::{TextElem, WeightDelta}; +use crate::foundations::{elem, Content}; /// Strongly emphasizes content by increasing the font weight. /// @@ -24,7 +18,7 @@ use crate::text::{TextElem, WeightDelta}; /// simply enclose it in stars/asterisks (`*`). Note that this only works at /// word boundaries. To strongly emphasize part of a word, you have to use the /// function. -#[elem(title = "Strong Emphasis", keywords = ["bold", "weight"], Show)] +#[elem(title = "Strong Emphasis", keywords = ["bold", "weight"])] pub struct StrongElem { /// The delta to apply on the font weight. /// @@ -39,18 +33,3 @@ pub struct StrongElem { #[required] pub body: Content, } - -impl Show for Packed<StrongElem> { - #[typst_macros::time(name = "strong", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let body = self.body.clone(); - Ok(if styles.get(TargetElem::target).is_html() { - HtmlElem::new(tag::strong) - .with_body(Some(body)) - .pack() - .spanned(self.span()) - } else { - body.set(TextElem::delta, WeightDelta(self.delta.get(styles))) - }) - } -} diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs index 72c5acc5..e46efc81 100644 --- a/crates/typst-library/src/model/table.rs +++ b/crates/typst-library/src/model/table.rs @@ -3,19 +3,11 @@ use std::sync::Arc; use typst_utils::NonZeroExt; -use crate::diag::{bail, HintedStrResult, HintedString, SourceResult}; -use crate::engine::Engine; -use crate::foundations::{ - cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain, - TargetElem, -}; -use crate::html::{attr, tag, HtmlAttrs, HtmlElem, HtmlTag}; -use crate::introspection::Locator; -use crate::layout::grid::resolve::{table_to_cellgrid, Cell, CellGrid, Entry}; +use crate::diag::{bail, HintedStrResult, HintedString}; +use crate::foundations::{cast, elem, scope, Content, Packed, Smart}; use crate::layout::{ - show_grid_cell, Abs, Alignment, BlockElem, Celled, GridCell, GridFooter, GridHLine, - GridHeader, GridVLine, Length, OuterHAlignment, OuterVAlignment, Rel, Sides, - TrackSizings, + Abs, Alignment, Celled, GridCell, GridFooter, GridHLine, GridHeader, GridVLine, + Length, OuterHAlignment, OuterVAlignment, Rel, Sides, TrackSizings, }; use crate::model::Figurable; use crate::text::LocalName; @@ -121,7 +113,7 @@ use crate::visualize::{Paint, Stroke}; /// [Robert], b, a, b, /// ) /// ``` -#[elem(scope, Show, LocalName, Figurable)] +#[elem(scope, LocalName, Figurable)] pub struct TableElem { /// The column sizes. See the [grid documentation]($grid) for more /// information on track sizing. @@ -255,113 +247,6 @@ impl TableElem { type TableFooter; } -fn show_cell_html(tag: HtmlTag, cell: &Cell, styles: StyleChain) -> Content { - let cell = cell.body.clone(); - let Some(cell) = cell.to_packed::<TableCell>() else { return cell }; - let mut attrs = HtmlAttrs::default(); - let span = |n: NonZeroUsize| (n != NonZeroUsize::MIN).then(|| n.to_string()); - if let Some(colspan) = span(cell.colspan.get(styles)) { - attrs.push(attr::colspan, colspan); - } - if let Some(rowspan) = span(cell.rowspan.get(styles)) { - attrs.push(attr::rowspan, rowspan); - } - HtmlElem::new(tag) - .with_body(Some(cell.body.clone())) - .with_attrs(attrs) - .pack() - .spanned(cell.span()) -} - -fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { - let elem = |tag, body| HtmlElem::new(tag).with_body(Some(body)).pack(); - let mut rows: Vec<_> = grid.entries.chunks(grid.non_gutter_column_count()).collect(); - - let tr = |tag, row: &[Entry]| { - let row = row - .iter() - .flat_map(|entry| entry.as_cell()) - .map(|cell| show_cell_html(tag, cell, styles)); - elem(tag::tr, Content::sequence(row)) - }; - - // TODO(subfooters): similarly to headers, take consecutive footers from - // the end for 'tfoot'. - let footer = grid.footer.map(|ft| { - let rows = rows.drain(ft.start..); - elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row)))) - }); - - // Store all consecutive headers at the start in 'thead'. All remaining - // headers are just 'th' rows across the table body. - let mut consecutive_header_end = 0; - let first_mid_table_header = grid - .headers - .iter() - .take_while(|hd| { - let is_consecutive = hd.range.start == consecutive_header_end; - consecutive_header_end = hd.range.end; - - is_consecutive - }) - .count(); - - let (y_offset, header) = if first_mid_table_header > 0 { - let removed_header_rows = - grid.headers.get(first_mid_table_header - 1).unwrap().range.end; - let rows = rows.drain(..removed_header_rows); - - ( - removed_header_rows, - Some(elem(tag::thead, Content::sequence(rows.map(|row| tr(tag::th, row))))), - ) - } else { - (0, None) - }; - - // TODO: Consider improving accessibility properties of multi-level headers - // inside tables in the future, e.g. indicating which columns they are - // relative to and so on. See also: - // https://www.w3.org/WAI/tutorials/tables/multi-level/ - let mut next_header = first_mid_table_header; - let mut body = - Content::sequence(rows.into_iter().enumerate().map(|(relative_y, row)| { - let y = relative_y + y_offset; - if let Some(current_header) = - grid.headers.get(next_header).filter(|h| h.range.contains(&y)) - { - if y + 1 == current_header.range.end { - next_header += 1; - } - - tr(tag::th, row) - } else { - tr(tag::td, row) - } - })); - - if header.is_some() || footer.is_some() { - body = elem(tag::tbody, body); - } - - let content = header.into_iter().chain(core::iter::once(body)).chain(footer); - elem(tag::table, Content::sequence(content)) -} - -impl Show for Packed<TableElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(if styles.get(TargetElem::target).is_html() { - // TODO: This is a hack, it is not clear whether the locator is actually used by HTML. - // How can we find out whether locator is actually used? - let locator = Locator::root(); - show_cellgrid_html(table_to_cellgrid(self, engine, locator, styles)?, styles) - } else { - BlockElem::multi_layouter(self.clone(), engine.routines.layout_table).pack() - } - .spanned(self.span())) - } -} - impl LocalName for Packed<TableElem> { const KEY: &'static str = "table"; } @@ -761,7 +646,7 @@ pub struct TableVLine { /// [Vikram], [49], [Perseverance], /// ) /// ``` -#[elem(name = "cell", title = "Table Cell", Show)] +#[elem(name = "cell", title = "Table Cell")] pub struct TableCell { /// The cell's body. #[required] @@ -808,12 +693,6 @@ cast! { v: Content => v.into(), } -impl Show for Packed<TableCell> { - fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - show_grid_cell(self.body.clone(), self.inset.get(styles), self.align.get(styles)) - } -} - impl Default for Packed<TableCell> { fn default() -> Self { Packed::new( diff --git a/crates/typst-library/src/model/terms.rs b/crates/typst-library/src/model/terms.rs index 280c2d67..71b1bad6 100644 --- a/crates/typst-library/src/model/terms.rs +++ b/crates/typst-library/src/model/terms.rs @@ -1,15 +1,9 @@ -use typst_utils::{Get, Numeric}; - -use crate::diag::{bail, SourceResult}; -use crate::engine::Engine; +use crate::diag::bail; use crate::foundations::{ - cast, elem, scope, Array, Content, NativeElement, Packed, Show, Smart, StyleChain, - Styles, TargetElem, + cast, elem, scope, Array, Content, NativeElement, Packed, Smart, Styles, }; -use crate::html::{tag, HtmlElem}; -use crate::layout::{Em, HElem, Length, Sides, StackChild, StackElem, VElem}; -use crate::model::{ListItemLike, ListLike, ParElem, ParbreakElem}; -use crate::text::TextElem; +use crate::layout::{Em, HElem, Length}; +use crate::model::{ListItemLike, ListLike}; /// A list of terms and their descriptions. /// @@ -27,7 +21,7 @@ use crate::text::TextElem; /// # Syntax /// This function also has dedicated syntax: Starting a line with a slash, /// followed by a term, a colon and a description creates a term list item. -#[elem(scope, title = "Term List", Show)] +#[elem(scope, title = "Term List")] pub struct TermsElem { /// Defines the default [spacing]($terms.spacing) of the term list. If it is /// `{false}`, the items are spaced apart with @@ -117,94 +111,6 @@ impl TermsElem { type TermItem; } -impl Show for Packed<TermsElem> { - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let span = self.span(); - let tight = self.tight.get(styles); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::dl) - .with_body(Some(Content::sequence(self.children.iter().flat_map( - |item| { - // Text in wide term lists shall always turn into paragraphs. - let mut description = item.description.clone(); - if !tight { - description += ParbreakElem::shared(); - } - - [ - HtmlElem::new(tag::dt) - .with_body(Some(item.term.clone())) - .pack() - .spanned(item.term.span()), - HtmlElem::new(tag::dd) - .with_body(Some(description)) - .pack() - .spanned(item.description.span()), - ] - }, - )))) - .pack()); - } - - let separator = self.separator.get_ref(styles); - let indent = self.indent.get(styles); - let hanging_indent = self.hanging_indent.get(styles); - let gutter = self.spacing.get(styles).unwrap_or_else(|| { - if tight { - styles.get(ParElem::leading) - } else { - styles.get(ParElem::spacing) - } - }); - - let pad = hanging_indent + indent; - let unpad = (!hanging_indent.is_zero()) - .then(|| HElem::new((-hanging_indent).into()).pack().spanned(span)); - - let mut children = vec![]; - for child in self.children.iter() { - let mut seq = vec![]; - seq.extend(unpad.clone()); - seq.push(child.term.clone().strong()); - seq.push((*separator).clone()); - seq.push(child.description.clone()); - - // Text in wide term lists shall always turn into paragraphs. - if !tight { - seq.push(ParbreakElem::shared().clone()); - } - - children.push(StackChild::Block(Content::sequence(seq))); - } - - let padding = - Sides::default().with(styles.resolve(TextElem::dir).start(), pad.into()); - - let mut realized = StackElem::new(children) - .with_spacing(Some(gutter.into())) - .pack() - .spanned(span) - .padded(padding) - .set(TermsElem::within, true); - - if tight { - let spacing = self - .spacing - .get(styles) - .unwrap_or_else(|| styles.get(ParElem::leading)); - let v = VElem::new(spacing.into()) - .with_weak(true) - .with_attach(true) - .pack() - .spanned(span); - realized = v + realized; - } - - Ok(realized) - } -} - /// A term list item. #[elem(name = "item", title = "Term List Item")] pub struct TermItem { diff --git a/crates/typst-library/src/pdf/embed.rs b/crates/typst-library/src/pdf/embed.rs index 0f93f95a..3aba8562 100644 --- a/crates/typst-library/src/pdf/embed.rs +++ b/crates/typst-library/src/pdf/embed.rs @@ -1,12 +1,8 @@ use ecow::EcoString; -use typst_library::foundations::Target; use typst_syntax::Spanned; -use crate::diag::{warning, At, SourceResult}; -use crate::engine::Engine; -use crate::foundations::{ - elem, Bytes, Cast, Content, Derived, Packed, Show, StyleChain, TargetElem, -}; +use crate::diag::At; +use crate::foundations::{elem, Bytes, Cast, Derived}; use crate::introspection::Locatable; use crate::World; @@ -33,7 +29,7 @@ use crate::World; /// - This element is ignored if exporting to a format other than PDF. /// - File embeddings are not currently supported for PDF/A-2, even if the /// embedded file conforms to PDF/A-1 or PDF/A-2. -#[elem(Show, Locatable)] +#[elem(Locatable)] pub struct EmbedElem { /// The [path]($syntax/#paths) of the file to be embedded. /// @@ -77,17 +73,6 @@ pub struct EmbedElem { pub description: Option<EcoString>, } -impl Show for Packed<EmbedElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target) == Target::Html { - engine - .sink - .warn(warning!(self.span(), "embed was ignored during HTML export")); - } - Ok(Content::empty()) - } -} - /// The relationship of an embedded file with the document. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] pub enum EmbeddedFileRelationship { diff --git a/crates/typst-library/src/routines.rs b/crates/typst-library/src/routines.rs index 59ce8328..4bf8d60c 100644 --- a/crates/typst-library/src/routines.rs +++ b/crates/typst-library/src/routines.rs @@ -1,7 +1,4 @@ -#![allow(unused)] - use std::hash::{Hash, Hasher}; -use std::num::NonZeroUsize; use comemo::{Tracked, TrackedMut}; use typst_syntax::{Span, SyntaxMode}; @@ -10,20 +7,12 @@ use typst_utils::LazyHash; use crate::diag::SourceResult; use crate::engine::{Engine, Route, Sink, Traced}; use crate::foundations::{ - Args, Cast, Closure, Content, Context, Func, Packed, Scope, StyleChain, Styles, Value, + Args, Closure, Content, Context, Func, NativeRuleMap, Scope, StyleChain, Styles, + Value, }; use crate::introspection::{Introspector, Locator, SplitLocator}; -use crate::layout::{ - Abs, BoxElem, ColumnsElem, Fragment, Frame, GridElem, InlineItem, MoveElem, PadElem, - PagedDocument, Region, Regions, Rel, RepeatElem, RotateElem, ScaleElem, Size, - SkewElem, StackElem, -}; -use crate::math::EquationElem; -use crate::model::{DocumentInfo, EnumElem, ListElem, TableElem}; -use crate::visualize::{ - CircleElem, CurveElem, EllipseElem, ImageElem, LineElem, PathElem, PolygonElem, - RectElem, SquareElem, -}; +use crate::layout::{Frame, Region}; +use crate::model::DocumentInfo; use crate::World; /// Defines the `Routines` struct. @@ -38,6 +27,8 @@ macro_rules! routines { /// This is essentially dynamic linking and done to allow for crate /// splitting. pub struct Routines { + /// Native show rules. + pub rules: NativeRuleMap, $( $(#[$attr])* pub $name: $(for<$($time),*>)? fn ($($args)*) -> $ret @@ -86,15 +77,6 @@ routines! { styles: StyleChain<'a>, ) -> SourceResult<Vec<Pair<'a>>> - /// Lays out content into multiple regions. - fn layout_fragment( - engine: &mut Engine, - content: &Content, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - /// Lays out content into a single region, producing a single frame. fn layout_frame( engine: &mut Engine, @@ -103,213 +85,6 @@ routines! { styles: StyleChain, region: Region, ) -> SourceResult<Frame> - - /// Lays out a [`ListElem`]. - fn layout_list( - elem: &Packed<ListElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - - /// Lays out an [`EnumElem`]. - fn layout_enum( - elem: &Packed<EnumElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - - /// Lays out a [`GridElem`]. - fn layout_grid( - elem: &Packed<GridElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - - /// Lays out a [`TableElem`]. - fn layout_table( - elem: &Packed<TableElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - - /// Lays out a [`StackElem`]. - fn layout_stack( - elem: &Packed<StackElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - - /// Lays out a [`ColumnsElem`]. - fn layout_columns( - elem: &Packed<ColumnsElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - - /// Lays out a [`MoveElem`]. - fn layout_move( - elem: &Packed<MoveElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`RotateElem`]. - fn layout_rotate( - elem: &Packed<RotateElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`ScaleElem`]. - fn layout_scale( - elem: &Packed<ScaleElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`SkewElem`]. - fn layout_skew( - elem: &Packed<SkewElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`RepeatElem`]. - fn layout_repeat( - elem: &Packed<RepeatElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`PadElem`]. - fn layout_pad( - elem: &Packed<PadElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> - - /// Lays out a [`LineElem`]. - fn layout_line( - elem: &Packed<LineElem>, - _: &mut Engine, - _: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`CurveElem`]. - fn layout_curve( - elem: &Packed<CurveElem>, - _: &mut Engine, - _: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`PathElem`]. - fn layout_path( - elem: &Packed<PathElem>, - _: &mut Engine, - _: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`PolygonElem`]. - fn layout_polygon( - elem: &Packed<PolygonElem>, - _: &mut Engine, - _: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`RectElem`]. - fn layout_rect( - elem: &Packed<RectElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`SquareElem`]. - fn layout_square( - elem: &Packed<SquareElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`EllipseElem`]. - fn layout_ellipse( - elem: &Packed<EllipseElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out a [`CircleElem`]. - fn layout_circle( - elem: &Packed<CircleElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out an [`ImageElem`]. - fn layout_image( - elem: &Packed<ImageElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Region, - ) -> SourceResult<Frame> - - /// Lays out an [`EquationElem`] in a paragraph. - fn layout_equation_inline( - elem: &Packed<EquationElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - region: Size, - ) -> SourceResult<Vec<InlineItem>> - - /// Lays out an [`EquationElem`] in a flow. - fn layout_equation_block( - elem: &Packed<EquationElem>, - engine: &mut Engine, - locator: Locator, - styles: StyleChain, - regions: Regions, - ) -> SourceResult<Fragment> } /// Defines what kind of realization we are performing. diff --git a/crates/typst-library/src/text/deco.rs b/crates/typst-library/src/text/deco.rs index 8c1d5634..f7d5c33b 100644 --- a/crates/typst-library/src/text/deco.rs +++ b/crates/typst-library/src/text/deco.rs @@ -1,13 +1,6 @@ -use smallvec::smallvec; - -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, Smart, StyleChain, TargetElem, -}; -use crate::html::{attr, tag, HtmlElem}; +use crate::foundations::{elem, Content, Smart}; use crate::layout::{Abs, Corners, Length, Rel, Sides}; -use crate::text::{BottomEdge, BottomEdgeMetric, TextElem, TopEdge, TopEdgeMetric}; +use crate::text::{BottomEdge, BottomEdgeMetric, TopEdge, TopEdgeMetric}; use crate::visualize::{Color, FixedStroke, Paint, Stroke}; /// Underlines text. @@ -16,7 +9,7 @@ use crate::visualize::{Color, FixedStroke, Paint, Stroke}; /// ```example /// This is #underline[important]. /// ``` -#[elem(Show)] +#[elem] pub struct UnderlineElem { /// How to [stroke] the line. /// @@ -78,41 +71,13 @@ pub struct UnderlineElem { pub body: Content, } -impl Show for Packed<UnderlineElem> { - #[typst_macros::time(name = "underline", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - // Note: In modern HTML, `<u>` is not the underline element, but - // rather an "Unarticulated Annotation" element (see HTML spec - // 4.5.22). Using `text-decoration` instead is recommended by MDN. - return Ok(HtmlElem::new(tag::span) - .with_attr(attr::style, "text-decoration: underline") - .with_body(Some(self.body.clone())) - .pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - line: DecoLine::Underline { - stroke: self.stroke.resolve(styles).unwrap_or_default(), - offset: self.offset.resolve(styles), - evade: self.evade.get(styles), - background: self.background.get(styles), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// Adds a line over text. /// /// # Example /// ```example /// #overline[A line over text.] /// ``` -#[elem(Show)] +#[elem] pub struct OverlineElem { /// How to [stroke] the line. /// @@ -180,38 +145,13 @@ pub struct OverlineElem { pub body: Content, } -impl Show for Packed<OverlineElem> { - #[typst_macros::time(name = "overline", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::span) - .with_attr(attr::style, "text-decoration: overline") - .with_body(Some(self.body.clone())) - .pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - line: DecoLine::Overline { - stroke: self.stroke.resolve(styles).unwrap_or_default(), - offset: self.offset.resolve(styles), - evade: self.evade.get(styles), - background: self.background.get(styles), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// Strikes through text. /// /// # Example /// ```example /// This is #strike[not] relevant. /// ``` -#[elem(title = "Strikethrough", Show)] +#[elem(title = "Strikethrough")] pub struct StrikeElem { /// How to [stroke] the line. /// @@ -264,35 +204,13 @@ pub struct StrikeElem { pub body: Content, } -impl Show for Packed<StrikeElem> { - #[typst_macros::time(name = "strike", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::s).with_body(Some(self.body.clone())).pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - // Note that we do not support evade option for strikethrough. - line: DecoLine::Strikethrough { - stroke: self.stroke.resolve(styles).unwrap_or_default(), - offset: self.offset.resolve(styles), - background: self.background.get(styles), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// Highlights text with a background color. /// /// # Example /// ```example /// This is #highlight[important]. /// ``` -#[elem(Show)] +#[elem] pub struct HighlightElem { /// The color to highlight the text with. /// @@ -363,35 +281,6 @@ pub struct HighlightElem { pub body: Content, } -impl Show for Packed<HighlightElem> { - #[typst_macros::time(name = "highlight", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::mark) - .with_body(Some(self.body.clone())) - .pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - line: DecoLine::Highlight { - fill: self.fill.get_cloned(styles), - stroke: self - .stroke - .resolve(styles) - .unwrap_or_default() - .map(|stroke| stroke.map(Stroke::unwrap_or_default)), - top_edge: self.top_edge.get(styles), - bottom_edge: self.bottom_edge.get(styles), - radius: self.radius.resolve(styles).unwrap_or_default(), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// A text decoration. /// /// Can be positioned over, under, or on top of text, or highlight the text with diff --git a/crates/typst-library/src/text/raw.rs b/crates/typst-library/src/text/raw.rs index 67038163..8cddfbfb 100644 --- a/crates/typst-library/src/text/raw.rs +++ b/crates/typst-library/src/text/raw.rs @@ -16,14 +16,13 @@ use crate::diag::{ }; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Bytes, Content, Derived, NativeElement, OneOrMultiple, Packed, - PlainText, Show, ShowSet, Smart, StyleChain, Styles, Synthesize, TargetElem, + cast, elem, scope, Bytes, Content, Derived, OneOrMultiple, Packed, PlainText, + ShowSet, Smart, StyleChain, Styles, Synthesize, }; -use crate::html::{tag, HtmlElem}; -use crate::layout::{BlockBody, BlockElem, Em, HAlignment}; +use crate::layout::{Em, HAlignment}; use crate::loading::{DataSource, Load}; use crate::model::{Figurable, ParElem}; -use crate::text::{FontFamily, FontList, LinebreakElem, LocalName, TextElem, TextSize}; +use crate::text::{FontFamily, FontList, LocalName, TextElem, TextSize}; use crate::visualize::Color; use crate::World; @@ -78,7 +77,6 @@ use crate::World; scope, title = "Raw Text / Code", Synthesize, - Show, ShowSet, LocalName, Figurable, @@ -429,46 +427,6 @@ impl Packed<RawElem> { } } -impl Show for Packed<RawElem> { - #[typst_macros::time(name = "raw", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let lines = self.lines.as_deref().unwrap_or_default(); - - let mut seq = EcoVec::with_capacity((2 * lines.len()).saturating_sub(1)); - for (i, line) in lines.iter().enumerate() { - if i != 0 { - seq.push(LinebreakElem::shared().clone()); - } - - seq.push(line.clone().pack()); - } - - let mut realized = Content::sequence(seq); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(if self.block.get(styles) { - tag::pre - } else { - tag::code - }) - .with_body(Some(realized)) - .pack() - .spanned(self.span())); - } - - if self.block.get(styles) { - // Align the text before inserting it into the block. - realized = realized.aligned(self.align.get(styles).into()); - realized = BlockElem::new() - .with_body(Some(BlockBody::Content(realized))) - .pack() - .spanned(self.span()); - } - - Ok(realized) - } -} - impl ShowSet for Packed<RawElem> { fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); @@ -634,7 +592,7 @@ fn format_theme_error(error: syntect::LoadingError) -> LoadError { /// It allows you to access various properties of the line, such as the line /// number, the raw non-highlighted text, the highlighted text, and whether it /// is the first or last line of the raw block. -#[elem(name = "line", title = "Raw Text / Code Line", Show, PlainText)] +#[elem(name = "line", title = "Raw Text / Code Line", PlainText)] pub struct RawLine { /// The line number of the raw line inside of the raw block, starts at 1. #[required] @@ -653,13 +611,6 @@ pub struct RawLine { pub body: Content, } -impl Show for Packed<RawLine> { - #[typst_macros::time(name = "raw.line", span = self.span())] - fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { - Ok(self.body.clone()) - } -} - impl PlainText for Packed<RawLine> { fn plain_text(&self, text: &mut EcoString) { text.push_str(&self.text); diff --git a/crates/typst-library/src/text/shift.rs b/crates/typst-library/src/text/shift.rs index 1a05d8f9..87ccae63 100644 --- a/crates/typst-library/src/text/shift.rs +++ b/crates/typst-library/src/text/shift.rs @@ -1,13 +1,8 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, Smart, StyleChain, TargetElem, -}; -use crate::html::{tag, HtmlElem}; -use crate::layout::{Em, Length}; -use crate::text::{FontMetrics, TextElem, TextSize}; use ttf_parser::Tag; -use typst_library::text::ScriptMetrics; + +use crate::foundations::{elem, Content, Smart}; +use crate::layout::{Em, Length}; +use crate::text::{FontMetrics, ScriptMetrics, TextSize}; /// Renders text in subscript. /// @@ -17,7 +12,7 @@ use typst_library::text::ScriptMetrics; /// ```example /// Revenue#sub[yearly] /// ``` -#[elem(title = "Subscript", Show)] +#[elem(title = "Subscript")] pub struct SubElem { /// Whether to create artificial subscripts by lowering and scaling down /// regular glyphs. @@ -64,29 +59,6 @@ pub struct SubElem { pub body: Content, } -impl Show for Packed<SubElem> { - #[typst_macros::time(name = "sub", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let body = self.body.clone(); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::sub) - .with_body(Some(body)) - .pack() - .spanned(self.span())); - } - - show_script( - styles, - body, - self.typographic.get(styles), - self.baseline.get(styles), - self.size.get(styles), - ScriptKind::Sub, - ) - } -} - /// Renders text in superscript. /// /// The text is rendered smaller and its baseline is raised. @@ -95,7 +67,7 @@ impl Show for Packed<SubElem> { /// ```example /// 1#super[st] try! /// ``` -#[elem(title = "Superscript", Show)] +#[elem(title = "Superscript")] pub struct SuperElem { /// Whether to create artificial superscripts by raising and scaling down /// regular glyphs. @@ -146,49 +118,6 @@ pub struct SuperElem { pub body: Content, } -impl Show for Packed<SuperElem> { - #[typst_macros::time(name = "super", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let body = self.body.clone(); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::sup) - .with_body(Some(body)) - .pack() - .spanned(self.span())); - } - - show_script( - styles, - body, - self.typographic.get(styles), - self.baseline.get(styles), - self.size.get(styles), - ScriptKind::Super, - ) - } -} - -fn show_script( - styles: StyleChain, - body: Content, - typographic: bool, - baseline: Smart<Length>, - size: Smart<TextSize>, - kind: ScriptKind, -) -> SourceResult<Content> { - let font_size = styles.resolve(TextElem::size); - Ok(body.set( - TextElem::shift_settings, - Some(ShiftSettings { - typographic, - shift: baseline.map(|l| -Em::from_length(l, font_size)), - size: size.map(|t| Em::from_length(t.0, font_size)), - kind, - }), - )) -} - /// Configuration values for sub- or superscript text. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct ShiftSettings { diff --git a/crates/typst-library/src/text/smallcaps.rs b/crates/typst-library/src/text/smallcaps.rs index 1c283893..199222fe 100644 --- a/crates/typst-library/src/text/smallcaps.rs +++ b/crates/typst-library/src/text/smallcaps.rs @@ -1,7 +1,4 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, Packed, Show, StyleChain}; -use crate::text::TextElem; +use crate::foundations::{elem, Content}; /// Displays text in small capitals. /// @@ -43,7 +40,7 @@ use crate::text::TextElem; /// = Introduction /// #lorem(40) /// ``` -#[elem(title = "Small Capitals", Show)] +#[elem(title = "Small Capitals")] pub struct SmallcapsElem { /// Whether to turn uppercase letters into small capitals as well. /// @@ -61,15 +58,6 @@ pub struct SmallcapsElem { pub body: Content, } -impl Show for Packed<SmallcapsElem> { - #[typst_macros::time(name = "smallcaps", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let sc = - if self.all.get(styles) { Smallcaps::All } else { Smallcaps::Minuscules }; - Ok(self.body.clone().set(TextElem::smallcaps, Some(sc))) - } -} - /// What becomes small capitals. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Smallcaps { diff --git a/crates/typst-library/src/text/smartquote.rs b/crates/typst-library/src/text/smartquote.rs index 24787d06..375b1cf0 100644 --- a/crates/typst-library/src/text/smartquote.rs +++ b/crates/typst-library/src/text/smartquote.rs @@ -5,9 +5,10 @@ use unicode_segmentation::UnicodeSegmentation; use crate::diag::{bail, HintedStrResult, StrResult}; use crate::foundations::{ array, cast, dict, elem, Array, Dict, FromValue, Packed, PlainText, Smart, Str, + StyleChain, }; use crate::layout::Dir; -use crate::text::{Lang, Region}; +use crate::text::{Lang, Region, TextElem}; /// A language-aware quote that reacts to its context. /// @@ -200,6 +201,16 @@ pub struct SmartQuotes<'s> { } impl<'s> SmartQuotes<'s> { + /// Retrieve the smart quotes as configured by the current styles. + pub fn get_in(styles: StyleChain<'s>) -> Self { + Self::get( + styles.get_ref(SmartQuoteElem::quotes), + styles.get(TextElem::lang), + styles.get(TextElem::region), + styles.get(SmartQuoteElem::alternative), + ) + } + /// Create a new `Quotes` struct with the given quotes, optionally falling /// back to the defaults for a language and region. /// diff --git a/crates/typst-library/src/visualize/curve.rs b/crates/typst-library/src/visualize/curve.rs index 587f0d4a..15ae48c6 100644 --- a/crates/typst-library/src/visualize/curve.rs +++ b/crates/typst-library/src/visualize/curve.rs @@ -2,12 +2,9 @@ use kurbo::ParamCurveExtrema; use typst_macros::{scope, Cast}; use typst_utils::Numeric; -use crate::diag::{bail, HintedStrResult, HintedString, SourceResult}; -use crate::engine::Engine; -use crate::foundations::{ - cast, elem, Content, NativeElement, Packed, Show, Smart, StyleChain, -}; -use crate::layout::{Abs, Axes, BlockElem, Length, Point, Rel, Size}; +use crate::diag::{bail, HintedStrResult, HintedString}; +use crate::foundations::{cast, elem, Content, Packed, Smart}; +use crate::layout::{Abs, Axes, Length, Point, Rel, Size}; use crate::visualize::{FillRule, Paint, Stroke}; use super::FixedStroke; @@ -42,7 +39,7 @@ use super::FixedStroke; /// curve.close(), /// ) /// ``` -#[elem(scope, Show)] +#[elem(scope)] pub struct CurveElem { /// How to fill the curve. /// @@ -95,14 +92,6 @@ pub struct CurveElem { pub components: Vec<CurveComponent>, } -impl Show for Packed<CurveElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_curve) - .pack() - .spanned(self.span())) - } -} - #[scope] impl CurveElem { #[elem] diff --git a/crates/typst-library/src/visualize/image/mod.rs b/crates/typst-library/src/visualize/image/mod.rs index 48a14f0e..95021b81 100644 --- a/crates/typst-library/src/visualize/image/mod.rs +++ b/crates/typst-library/src/visualize/image/mod.rs @@ -15,13 +15,11 @@ use ecow::EcoString; use typst_syntax::{Span, Spanned}; use typst_utils::LazyHash; -use crate::diag::{SourceResult, StrResult}; -use crate::engine::Engine; +use crate::diag::StrResult; use crate::foundations::{ - cast, elem, func, scope, Bytes, Cast, Content, Derived, NativeElement, Packed, Show, - Smart, StyleChain, + cast, elem, func, scope, Bytes, Cast, Content, Derived, NativeElement, Packed, Smart, }; -use crate::layout::{BlockElem, Length, Rel, Sizing}; +use crate::layout::{Length, Rel, Sizing}; use crate::loading::{DataSource, Load, LoadSource, Loaded, Readable}; use crate::model::Figurable; use crate::text::LocalName; @@ -44,7 +42,7 @@ use crate::text::LocalName; /// ], /// ) /// ``` -#[elem(scope, Show, LocalName, Figurable)] +#[elem(scope, LocalName, Figurable)] pub struct ImageElem { /// A [path]($syntax/#paths) to an image file or raw bytes making up an /// image in one of the supported [formats]($image.format). @@ -219,16 +217,6 @@ impl ImageElem { } } -impl Show for Packed<ImageElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_image) - .with_width(self.width.get(styles)) - .with_height(self.height.get(styles)) - .pack() - .spanned(self.span())) - } -} - impl LocalName for Packed<ImageElem> { const KEY: &'static str = "figure"; } diff --git a/crates/typst-library/src/visualize/line.rs b/crates/typst-library/src/visualize/line.rs index d058b926..7eecfc91 100644 --- a/crates/typst-library/src/visualize/line.rs +++ b/crates/typst-library/src/visualize/line.rs @@ -1,7 +1,5 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, NativeElement, Packed, Show, StyleChain}; -use crate::layout::{Abs, Angle, Axes, BlockElem, Length, Rel}; +use crate::foundations::elem; +use crate::layout::{Abs, Angle, Axes, Length, Rel}; use crate::visualize::Stroke; /// A line from one point to another. @@ -17,7 +15,7 @@ use crate::visualize::Stroke; /// stroke: 2pt + maroon, /// ) /// ``` -#[elem(Show)] +#[elem] pub struct LineElem { /// The start point of the line. /// @@ -50,11 +48,3 @@ pub struct LineElem { #[fold] pub stroke: Stroke, } - -impl Show for Packed<LineElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_line) - .pack() - .spanned(self.span())) - } -} diff --git a/crates/typst-library/src/visualize/path.rs b/crates/typst-library/src/visualize/path.rs index e19e091d..bd8aea02 100644 --- a/crates/typst-library/src/visualize/path.rs +++ b/crates/typst-library/src/visualize/path.rs @@ -1,11 +1,7 @@ use self::PathVertex::{AllControlPoints, MirroredControlPoint, Vertex}; -use crate::diag::{bail, SourceResult}; -use crate::engine::Engine; -use crate::foundations::{ - array, cast, elem, Array, Content, NativeElement, Packed, Reflect, Show, Smart, - StyleChain, -}; -use crate::layout::{Axes, BlockElem, Length, Rel}; +use crate::diag::bail; +use crate::foundations::{array, cast, elem, Array, Reflect, Smart}; +use crate::layout::{Axes, Length, Rel}; use crate::visualize::{FillRule, Paint, Stroke}; /// A path through a list of points, connected by Bézier curves. @@ -21,7 +17,7 @@ use crate::visualize::{FillRule, Paint, Stroke}; /// ((50%, 0pt), (40pt, 0pt)), /// ) /// ``` -#[elem(Show)] +#[elem] pub struct PathElem { /// How to fill the path. /// @@ -83,14 +79,6 @@ pub struct PathElem { pub vertices: Vec<PathVertex>, } -impl Show for Packed<PathElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_path) - .pack() - .spanned(self.span())) - } -} - /// A component used for path creation. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum PathVertex { diff --git a/crates/typst-library/src/visualize/polygon.rs b/crates/typst-library/src/visualize/polygon.rs index d75e1a65..db75a267 100644 --- a/crates/typst-library/src/visualize/polygon.rs +++ b/crates/typst-library/src/visualize/polygon.rs @@ -2,12 +2,8 @@ use std::f64::consts::PI; use typst_syntax::Span; -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, func, scope, Content, NativeElement, Packed, Show, Smart, StyleChain, -}; -use crate::layout::{Axes, BlockElem, Em, Length, Rel}; +use crate::foundations::{elem, func, scope, Content, NativeElement, Smart}; +use crate::layout::{Axes, Em, Length, Rel}; use crate::visualize::{FillRule, Paint, Stroke}; /// A closed polygon. @@ -25,7 +21,7 @@ use crate::visualize::{FillRule, Paint, Stroke}; /// (0%, 2cm), /// ) /// ``` -#[elem(scope, Show)] +#[elem(scope)] pub struct PolygonElem { /// How to fill the polygon. /// @@ -124,11 +120,3 @@ impl PolygonElem { elem.pack().spanned(span) } } - -impl Show for Packed<PolygonElem> { - fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_polygon) - .pack() - .spanned(self.span())) - } -} diff --git a/crates/typst-library/src/visualize/shape.rs b/crates/typst-library/src/visualize/shape.rs index f21bf93e..fc7b8748 100644 --- a/crates/typst-library/src/visualize/shape.rs +++ b/crates/typst-library/src/visualize/shape.rs @@ -1,9 +1,5 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, Cast, Content, NativeElement, Packed, Show, Smart, StyleChain, -}; -use crate::layout::{Abs, BlockElem, Corners, Length, Point, Rel, Sides, Size, Sizing}; +use crate::foundations::{elem, Cast, Content, Smart}; +use crate::layout::{Abs, Corners, Length, Point, Rel, Sides, Size, Sizing}; use crate::visualize::{Curve, FixedStroke, Paint, Stroke}; /// A rectangle with optional content. @@ -19,7 +15,7 @@ use crate::visualize::{Curve, FixedStroke, Paint, Stroke}; /// to fit the content. /// ] /// ``` -#[elem(title = "Rectangle", Show)] +#[elem(title = "Rectangle")] pub struct RectElem { /// The rectangle's width, relative to its parent container. pub width: Smart<Rel<Length>>, @@ -122,16 +118,6 @@ pub struct RectElem { pub body: Option<Content>, } -impl Show for Packed<RectElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_rect) - .with_width(self.width.get(styles)) - .with_height(self.height.get(styles)) - .pack() - .spanned(self.span())) - } -} - /// A square with optional content. /// /// # Example @@ -145,7 +131,7 @@ impl Show for Packed<RectElem> { /// sized to fit. /// ] /// ``` -#[elem(Show)] +#[elem] pub struct SquareElem { /// The square's side length. This is mutually exclusive with `width` and /// `height`. @@ -209,16 +195,6 @@ pub struct SquareElem { pub body: Option<Content>, } -impl Show for Packed<SquareElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_square) - .with_width(self.width.get(styles)) - .with_height(self.height.get(styles)) - .pack() - .spanned(self.span())) - } -} - /// An ellipse with optional content. /// /// # Example @@ -233,7 +209,7 @@ impl Show for Packed<SquareElem> { /// to fit the content. /// ] /// ``` -#[elem(Show)] +#[elem] pub struct EllipseElem { /// The ellipse's width, relative to its parent container. pub width: Smart<Rel<Length>>, @@ -269,16 +245,6 @@ pub struct EllipseElem { pub body: Option<Content>, } -impl Show for Packed<EllipseElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_ellipse) - .with_width(self.width.get(styles)) - .with_height(self.height.get(styles)) - .pack() - .spanned(self.span())) - } -} - /// A circle with optional content. /// /// # Example @@ -293,7 +259,7 @@ impl Show for Packed<EllipseElem> { /// sized to fit. /// ] /// ``` -#[elem(Show)] +#[elem] pub struct CircleElem { /// The circle's radius. This is mutually exclusive with `width` and /// `height`. @@ -354,16 +320,6 @@ pub struct CircleElem { pub body: Option<Content>, } -impl Show for Packed<CircleElem> { - fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - Ok(BlockElem::single_layouter(self.clone(), engine.routines.layout_circle) - .with_width(self.width.get(styles)) - .with_height(self.height.get(styles)) - .pack() - .spanned(self.span())) - } -} - /// A geometric shape with optional fill and stroke. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct Shape { |
