summaryrefslogtreecommitdiff
path: root/crates/typst-library
diff options
context:
space:
mode:
authorSébastien d'Herbais de Thun <sebastien.d.herbais@gmail.com>2023-11-06 21:37:50 +0100
committerGitHub <noreply@github.com>2023-11-06 21:37:50 +0100
commitc0f6d2004afebfa9412ba0c2d598ef8287197c42 (patch)
tree4bb034ca671e7d1982a306f5aecfc4f78a01841d /crates/typst-library
parent8fd546760c7c425398f0114997c8085a481d8d2a (diff)
Content rework 2 - Electric Boogaloo (#2504)
Diffstat (limited to 'crates/typst-library')
-rw-r--r--crates/typst-library/Cargo.toml2
-rw-r--r--crates/typst-library/src/compute/data.rs1
-rw-r--r--crates/typst-library/src/layout/align.rs5
-rw-r--r--crates/typst-library/src/layout/enum.rs8
-rw-r--r--crates/typst-library/src/layout/flow.rs10
-rw-r--r--crates/typst-library/src/layout/grid.rs24
-rw-r--r--crates/typst-library/src/layout/hide.rs4
-rw-r--r--crates/typst-library/src/layout/list.rs8
-rw-r--r--crates/typst-library/src/layout/mod.rs49
-rw-r--r--crates/typst-library/src/layout/page.rs41
-rw-r--r--crates/typst-library/src/layout/par.rs62
-rw-r--r--crates/typst-library/src/layout/place.rs5
-rw-r--r--crates/typst-library/src/layout/spacing.rs6
-rw-r--r--crates/typst-library/src/layout/stack.rs6
-rw-r--r--crates/typst-library/src/layout/table.rs32
-rw-r--r--crates/typst-library/src/layout/terms.rs11
-rw-r--r--crates/typst-library/src/math/accent.rs7
-rw-r--r--crates/typst-library/src/math/attach.rs8
-rw-r--r--crates/typst-library/src/math/cancel.rs3
-rw-r--r--crates/typst-library/src/math/class.rs6
-rw-r--r--crates/typst-library/src/math/ctx.rs3
-rw-r--r--crates/typst-library/src/math/frac.rs4
-rw-r--r--crates/typst-library/src/math/fragment.rs2
-rw-r--r--crates/typst-library/src/math/lr.rs2
-rw-r--r--crates/typst-library/src/math/matrix.rs36
-rw-r--r--crates/typst-library/src/math/mod.rs14
-rw-r--r--crates/typst-library/src/math/op.rs2
-rw-r--r--crates/typst-library/src/math/root.rs2
-rw-r--r--crates/typst-library/src/math/style.rs4
-rw-r--r--crates/typst-library/src/math/underover.rs12
-rw-r--r--crates/typst-library/src/meta/bibliography.rs66
-rw-r--r--crates/typst-library/src/meta/cite.rs2
-rw-r--r--crates/typst-library/src/meta/context.rs2
-rw-r--r--crates/typst-library/src/meta/counter.rs18
-rw-r--r--crates/typst-library/src/meta/document.rs10
-rw-r--r--crates/typst-library/src/meta/figure.rs78
-rw-r--r--crates/typst-library/src/meta/footnote.rs22
-rw-r--r--crates/typst-library/src/meta/heading.rs26
-rw-r--r--crates/typst-library/src/meta/link.rs8
-rw-r--r--crates/typst-library/src/meta/mod.rs18
-rw-r--r--crates/typst-library/src/meta/outline.rs35
-rw-r--r--crates/typst-library/src/meta/reference.rs26
-rw-r--r--crates/typst-library/src/meta/state.rs6
-rw-r--r--crates/typst-library/src/prelude.rs10
-rw-r--r--crates/typst-library/src/shared/behave.rs12
-rw-r--r--crates/typst-library/src/shared/ext.rs6
-rw-r--r--crates/typst-library/src/text/deco.rs8
-rw-r--r--crates/typst-library/src/text/misc.rs15
-rw-r--r--crates/typst-library/src/text/mod.rs21
-rw-r--r--crates/typst-library/src/text/quote.rs13
-rw-r--r--crates/typst-library/src/text/quotes.rs1
-rw-r--r--crates/typst-library/src/text/raw.rs79
-rw-r--r--crates/typst-library/src/text/shaping.rs17
-rw-r--r--crates/typst-library/src/text/shift.rs6
-rw-r--r--crates/typst-library/src/visualize/image.rs9
-rw-r--r--crates/typst-library/src/visualize/path.rs2
56 files changed, 493 insertions, 402 deletions
diff --git a/crates/typst-library/Cargo.toml b/crates/typst-library/Cargo.toml
index b348596b..f4fce351 100644
--- a/crates/typst-library/Cargo.toml
+++ b/crates/typst-library/Cargo.toml
@@ -40,7 +40,7 @@ roxmltree = "0.18"
rustybuzz = "0.10"
serde_json = "1"
serde_yaml = "0.9"
-smallvec = "1.10"
+smallvec = { version = "1.11.1", features = ["union", "const_generics", "const_new"] }
syntect = { version = "5", default-features = false, features = ["parsing", "regex-fancy", "plist-load", "yaml-load"] }
time = { version = "0.3.20", features = ["formatting"] }
toml = { version = "0.8" }
diff --git a/crates/typst-library/src/compute/data.rs b/crates/typst-library/src/compute/data.rs
index dadf0bed..e4767ebf 100644
--- a/crates/typst-library/src/compute/data.rs
+++ b/crates/typst-library/src/compute/data.rs
@@ -66,6 +66,7 @@ pub enum Encoding {
}
/// A value that can be read from a file.
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum Readable {
/// A decoded string.
Str(Str),
diff --git a/crates/typst-library/src/layout/align.rs b/crates/typst-library/src/layout/align.rs
index f080f677..9c18266d 100644
--- a/crates/typst-library/src/layout/align.rs
+++ b/crates/typst-library/src/layout/align.rs
@@ -38,6 +38,9 @@ pub struct AlignElem {
impl Show for AlignElem {
#[tracing::instrument(name = "AlignElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(Self::set_alignment(self.alignment(styles))))
+ Ok(self
+ .body()
+ .clone()
+ .styled(Self::set_alignment(self.alignment(styles))))
}
}
diff --git a/crates/typst-library/src/layout/enum.rs b/crates/typst-library/src/layout/enum.rs
index 436aacb9..8c491dca 100644
--- a/crates/typst-library/src/layout/enum.rs
+++ b/crates/typst-library/src/layout/enum.rs
@@ -107,6 +107,7 @@ pub struct EnumElem {
/// + Numbering!
/// ```
#[default(Numbering::Pattern(NumberingPattern::from_str("1.").unwrap()))]
+ #[borrowed]
pub numbering: Numbering,
/// Which number to start the enumeration with.
@@ -215,7 +216,7 @@ impl Layout for EnumElem {
ParElem::leading_in(styles).into()
} else {
self.spacing(styles)
- .unwrap_or_else(|| BlockElem::below_in(styles).amount())
+ .unwrap_or_else(|| *BlockElem::below_in(styles).amount())
};
let mut cells = vec![];
@@ -238,7 +239,7 @@ impl Layout for EnumElem {
parents.pop();
content
} else {
- match &numbering {
+ match numbering {
Numbering::Pattern(pattern) => {
TextElem::packed(pattern.apply_kth(parents.len(), number))
}
@@ -254,7 +255,7 @@ impl Layout for EnumElem {
cells.push(Content::empty());
cells.push(resolved);
cells.push(Content::empty());
- cells.push(item.body().styled(Self::set_parents(Parent(number))));
+ cells.push(item.body().clone().styled(Self::set_parents(Parent(number))));
number = number.saturating_add(1);
}
@@ -301,6 +302,7 @@ cast! {
v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())),
}
+#[derive(Debug, Clone, Copy, PartialEq, Hash)]
struct Parent(usize);
cast! {
diff --git a/crates/typst-library/src/layout/flow.rs b/crates/typst-library/src/layout/flow.rs
index 1feee4b8..5c795c81 100644
--- a/crates/typst-library/src/layout/flow.rs
+++ b/crates/typst-library/src/layout/flow.rs
@@ -1,5 +1,7 @@
use std::mem;
+use comemo::Prehashed;
+
use super::{
AlignElem, BlockElem, ColbreakElem, ColumnsElem, ParElem, PlaceElem, Spacing, VElem,
};
@@ -18,7 +20,7 @@ use crate::visualize::{
pub struct FlowElem {
/// The children that will be arranges into a flow.
#[variadic]
- pub children: Vec<Content>,
+ pub children: Vec<Prehashed<Content>>,
}
impl Layout for FlowElem {
@@ -37,7 +39,7 @@ impl Layout for FlowElem {
}
let mut layouter = FlowLayouter::new(regions, styles);
- for mut child in &self.children() {
+ for mut child in self.children().iter().map(|c| &**c) {
let outer = styles;
let mut styles = styles;
if let Some((elem, map)) = child.to_styled() {
@@ -199,7 +201,7 @@ impl<'a> FlowLayouter<'a> {
rel.resolve(styles).relative_to(self.initial.y),
v.weakness(styles) > 0,
),
- Spacing::Fr(fr) => FlowItem::Fractional(fr),
+ Spacing::Fr(fr) => FlowItem::Fractional(*fr),
},
)
}
@@ -701,7 +703,7 @@ fn find_footnotes(notes: &mut Vec<FootnoteElem>, frame: &Frame) {
match item {
FrameItem::Group(group) => find_footnotes(notes, &group.frame),
FrameItem::Meta(Meta::Elem(content), _)
- if !notes.iter().any(|note| note.0.location() == content.location()) =>
+ if !notes.iter().any(|note| note.location() == content.location()) =>
{
let Some(footnote) = content.to::<FootnoteElem>() else { continue };
notes.push(footnote.clone());
diff --git a/crates/typst-library/src/layout/grid.rs b/crates/typst-library/src/layout/grid.rs
index 8d015782..b29adeb9 100644
--- a/crates/typst-library/src/layout/grid.rs
+++ b/crates/typst-library/src/layout/grid.rs
@@ -1,3 +1,5 @@
+use smallvec::{smallvec, SmallVec};
+
use crate::prelude::*;
use crate::text::TextElem;
@@ -66,12 +68,14 @@ pub struct GridElem {
/// with that many `{auto}`-sized columns. Note that opposed to rows and
/// gutters, providing a single track size will only ever create a single
/// column.
+ #[borrowed]
pub columns: TrackSizings,
/// The row sizes.
///
/// If there are more cells than fit the defined rows, the last row is
/// repeated until there are no more cells.
+ #[borrowed]
pub rows: TrackSizings,
/// The gaps between rows & columns.
@@ -85,10 +89,12 @@ pub struct GridElem {
let gutter = args.named("gutter")?;
args.named("column-gutter")?.or_else(|| gutter.clone())
)]
+ #[borrowed]
pub column_gutter: TrackSizings,
/// The gaps between rows. Takes precedence over `gutter`.
#[parse(args.named("row-gutter")?.or_else(|| gutter.clone()))]
+ #[borrowed]
pub row_gutter: TrackSizings,
/// The contents of the grid cells.
@@ -106,12 +112,16 @@ impl Layout for GridElem {
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
+ let columns = self.columns(styles);
+ let rows = self.rows(styles);
+ let column_gutter = self.column_gutter(styles);
+ let row_gutter = self.row_gutter(styles);
+
// Prepare grid layout by unifying content and gutter tracks.
- let cells = self.children();
let layouter = GridLayouter::new(
- Axes::new(&self.columns(styles).0, &self.rows(styles).0),
- Axes::new(&self.column_gutter(styles).0, &self.row_gutter(styles).0),
- &cells,
+ Axes::new(&columns.0, &rows.0),
+ Axes::new(&column_gutter.0, &row_gutter.0),
+ &self.children,
regions,
styles,
self.span(),
@@ -124,13 +134,13 @@ impl Layout for GridElem {
/// Track sizing definitions.
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
-pub struct TrackSizings(pub Vec<Sizing>);
+pub struct TrackSizings(pub SmallVec<[Sizing; 4]>);
cast! {
TrackSizings,
self => self.0.into_value(),
- sizing: Sizing => Self(vec![sizing]),
- count: NonZeroUsize => Self(vec![Sizing::Auto; count.get()]),
+ sizing: Sizing => Self(smallvec![sizing]),
+ count: NonZeroUsize => Self(smallvec![Sizing::Auto; count.get()]),
values: Array => Self(values.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
}
diff --git a/crates/typst-library/src/layout/hide.rs b/crates/typst-library/src/layout/hide.rs
index 7f17a7d7..af3d0631 100644
--- a/crates/typst-library/src/layout/hide.rs
+++ b/crates/typst-library/src/layout/hide.rs
@@ -1,3 +1,5 @@
+use smallvec::smallvec;
+
use crate::prelude::*;
/// Hides content without affecting layout.
@@ -22,6 +24,6 @@ pub struct HideElem {
impl Show for HideElem {
#[tracing::instrument(name = "HideElem::show", skip(self))]
fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(MetaElem::set_data(vec![Meta::Hide])))
+ Ok(self.body().clone().styled(MetaElem::set_data(smallvec![Meta::Hide])))
}
}
diff --git a/crates/typst-library/src/layout/list.rs b/crates/typst-library/src/layout/list.rs
index 34e0e6fb..18c89a24 100644
--- a/crates/typst-library/src/layout/list.rs
+++ b/crates/typst-library/src/layout/list.rs
@@ -77,6 +77,7 @@ pub struct ListElem {
/// - Items
/// - Items
/// ```
+ #[borrowed]
#[default(ListMarker::Content(vec![TextElem::packed('•')]))]
pub marker: ListMarker,
@@ -133,7 +134,7 @@ impl Layout for ListElem {
ParElem::leading_in(styles).into()
} else {
self.spacing(styles)
- .unwrap_or_else(|| BlockElem::below_in(styles).amount())
+ .unwrap_or_else(|| *BlockElem::below_in(styles).amount())
};
let depth = self.depth(styles);
@@ -148,7 +149,7 @@ impl Layout for ListElem {
cells.push(Content::empty());
cells.push(marker.clone());
cells.push(Content::empty());
- cells.push(item.body().styled(Self::set_depth(Depth)));
+ cells.push(item.body().clone().styled(Self::set_depth(Depth)));
}
let layouter = GridLayouter::new(
@@ -183,7 +184,7 @@ cast! {
}
/// A list's marker.
-#[derive(Debug, Clone, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum ListMarker {
Content(Vec<Content>),
Func(Func),
@@ -221,6 +222,7 @@ cast! {
v: Func => Self::Func(v),
}
+#[derive(Debug, Clone, Copy, PartialEq, Hash)]
struct Depth;
cast! {
diff --git a/crates/typst-library/src/layout/mod.rs b/crates/typst-library/src/layout/mod.rs
index 1c7c2610..d31f6841 100644
--- a/crates/typst-library/src/layout/mod.rs
+++ b/crates/typst-library/src/layout/mod.rs
@@ -46,6 +46,7 @@ pub use self::table::*;
pub use self::terms::*;
pub use self::transform::*;
+use std::borrow::Cow;
use std::mem;
use typed_arena::Arena;
@@ -242,16 +243,16 @@ fn realize_root<'a>(
scratch: &'a Scratch<'a>,
content: &'a Content,
styles: StyleChain<'a>,
-) -> SourceResult<(Content, StyleChain<'a>)> {
+) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> {
if content.can::<dyn LayoutRoot>() && !applicable(content, styles) {
- return Ok((content.clone(), styles));
+ return Ok((Cow::Borrowed(content), styles));
}
let mut builder = Builder::new(vt, scratch, true);
builder.accept(content, styles)?;
builder.interrupt_page(Some(styles), true)?;
let (pages, shared) = builder.doc.unwrap().pages.finish();
- Ok((DocumentElem::new(pages.to_vec()).pack(), shared))
+ Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack()), shared))
}
/// Realize into an element that is capable of block-level layout.
@@ -261,7 +262,7 @@ fn realize_block<'a>(
scratch: &'a Scratch<'a>,
content: &'a Content,
styles: StyleChain<'a>,
-) -> SourceResult<(Content, StyleChain<'a>)> {
+) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> {
// These elements implement `Layout` but still require a flow for
// proper layout.
if content.can::<dyn Layout>()
@@ -277,14 +278,14 @@ fn realize_block<'a>(
&& !content.is::<PlaceElem>()
&& !applicable(content, styles)
{
- return Ok((content.clone(), styles));
+ return Ok((Cow::Borrowed(content), styles));
}
let mut builder = Builder::new(vt, scratch, false);
builder.accept(content, styles)?;
builder.interrupt_par()?;
let (children, shared) = builder.flow.0.finish();
- Ok((FlowElem::new(children.to_vec()).pack(), shared))
+ Ok((Cow::Owned(FlowElem::new(children.to_vec()).pack()), shared))
}
/// Builds a document or a flow element from content.
@@ -509,7 +510,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
/// Accepts pagebreaks and pages.
struct DocBuilder<'a> {
/// The page runs built so far.
- pages: StyleVecBuilder<'a, Content>,
+ pages: StyleVecBuilder<'a, Cow<'a, Content>>,
/// Whether to keep a following page even if it is empty.
keep_next: bool,
/// Whether the next page should be cleared to an even or odd number.
@@ -517,7 +518,7 @@ struct DocBuilder<'a> {
}
impl<'a> DocBuilder<'a> {
- fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool {
+ fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool {
if let Some(pagebreak) = content.to::<PagebreakElem>() {
self.keep_next = !pagebreak.weak(styles);
self.clear_next = pagebreak.to(styles);
@@ -528,9 +529,9 @@ impl<'a> DocBuilder<'a> {
let elem = if let Some(clear_to) = self.clear_next.take() {
let mut page = page.clone();
page.push_clear_to(Some(clear_to));
- page.pack()
+ Cow::Owned(page.pack())
} else {
- content.clone()
+ Cow::Borrowed(content)
};
self.pages.push(elem, styles);
@@ -571,7 +572,7 @@ impl<'a> FlowBuilder<'a> {
|| content.is::<MetaElem>()
|| content.is::<PlaceElem>()
{
- self.0.push(content.clone(), styles);
+ self.0.push(Cow::Borrowed(content), styles);
return true;
}
@@ -589,7 +590,7 @@ impl<'a> FlowBuilder<'a> {
if !last_was_parbreak && is_tight_list {
let leading = ParElem::leading_in(styles);
let spacing = VElem::list_attach(leading.into());
- self.0.push(spacing.pack(), styles);
+ self.0.push(Cow::Owned(spacing.pack()), styles);
}
let (above, below) = if let Some(block) = content.to::<BlockElem>() {
@@ -598,9 +599,9 @@ impl<'a> FlowBuilder<'a> {
(BlockElem::above_in(styles), BlockElem::below_in(styles))
};
- self.0.push(above.pack(), styles);
- self.0.push(content.clone(), styles);
- self.0.push(below.pack(), styles);
+ self.0.push(Cow::Owned(above.pack()), styles);
+ self.0.push(Cow::Borrowed(content), styles);
+ self.0.push(Cow::Owned(below.pack()), styles);
return true;
}
@@ -616,7 +617,7 @@ impl<'a> ParBuilder<'a> {
fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool {
if content.is::<MetaElem>() {
if self.0.has_strong_elements(false) {
- self.0.push(content.clone(), styles);
+ self.0.push(Cow::Borrowed(content), styles);
return true;
}
} else if content.is::<SpaceElem>()
@@ -627,7 +628,7 @@ impl<'a> ParBuilder<'a> {
|| content.to::<EquationElem>().map_or(false, |elem| !elem.block(styles))
|| content.is::<BoxElem>()
{
- self.0.push(content.clone(), styles);
+ self.0.push(Cow::Borrowed(content), styles);
return true;
}
@@ -643,7 +644,7 @@ impl<'a> ParBuilder<'a> {
/// Accepts list / enum items, spaces, paragraph breaks.
struct ListBuilder<'a> {
/// The list items collected so far.
- items: StyleVecBuilder<'a, Content>,
+ items: StyleVecBuilder<'a, Cow<'a, Content>>,
/// Whether the list contains no paragraph breaks.
tight: bool,
/// Trailing content for which it is unclear whether it is part of the list.
@@ -668,7 +669,7 @@ impl<'a> ListBuilder<'a> {
.next()
.map_or(true, |first| first.func() == content.func())
{
- self.items.push(content.clone(), styles);
+ self.items.push(Cow::Borrowed(content), styles);
self.tight &= self.staged.drain(..).all(|(t, _)| !t.is::<ParbreakElem>());
return true;
}
@@ -685,7 +686,8 @@ impl<'a> ListBuilder<'a> {
.iter()
.map(|(item, local)| {
let item = item.to::<ListItem>().unwrap();
- item.clone().with_body(item.body().styled_with_map(local.clone()))
+ item.clone()
+ .with_body(item.body().clone().styled_with_map(local.clone()))
})
.collect::<Vec<_>>(),
)
@@ -697,7 +699,8 @@ impl<'a> ListBuilder<'a> {
.iter()
.map(|(item, local)| {
let item = item.to::<EnumItem>().unwrap();
- item.clone().with_body(item.body().styled_with_map(local.clone()))
+ item.clone()
+ .with_body(item.body().clone().styled_with_map(local.clone()))
})
.collect::<Vec<_>>(),
)
@@ -710,9 +713,9 @@ impl<'a> ListBuilder<'a> {
.map(|(item, local)| {
let item = item.to::<TermItem>().unwrap();
item.clone()
- .with_term(item.term().styled_with_map(local.clone()))
+ .with_term(item.term().clone().styled_with_map(local.clone()))
.with_description(
- item.description().styled_with_map(local.clone()),
+ item.description().clone().styled_with_map(local.clone()),
)
})
.collect::<Vec<_>>(),
diff --git a/crates/typst-library/src/layout/page.rs b/crates/typst-library/src/layout/page.rs
index 495b390d..5f8f90c1 100644
--- a/crates/typst-library/src/layout/page.rs
+++ b/crates/typst-library/src/layout/page.rs
@@ -1,3 +1,4 @@
+use std::borrow::Cow;
use std::ptr;
use std::str::FromStr;
@@ -172,6 +173,7 @@ pub struct PageElem {
/// #set text(fill: rgb("fdfdfd"))
/// *Dark mode enabled.*
/// ```
+ #[borrowed]
pub fill: Option<Paint>,
/// How to [number]($numbering) the pages.
@@ -188,6 +190,7 @@ pub struct PageElem {
///
/// #lorem(48)
/// ```
+ #[borrowed]
pub numbering: Option<Numbering>,
/// The alignment of the page numbering.
@@ -233,6 +236,7 @@ pub struct PageElem {
///
/// #lorem(19)
/// ```
+ #[borrowed]
pub header: Option<Content>,
/// The amount the header is raised into the top margin.
@@ -263,6 +267,7 @@ pub struct PageElem {
///
/// #lorem(48)
/// ```
+ #[borrowed]
pub footer: Option<Content>,
/// The amount the footer is lowered into the bottom margin.
@@ -286,6 +291,7 @@ pub struct PageElem {
/// In the year 2023, we plan to take
/// over the world (of typesetting).
/// ```
+ #[borrowed]
pub background: Option<Content>,
/// Content in the page's foreground.
@@ -299,6 +305,7 @@ pub struct PageElem {
/// "Weak Reject" because they did
/// not understand our approach...
/// ```
+ #[borrowed]
pub foreground: Option<Content>,
/// The contents of the page(s).
@@ -364,7 +371,7 @@ impl PageElem {
});
// Realize columns.
- let mut child = self.body();
+ let mut child = self.body().clone();
let columns = self.columns(styles);
if columns.get() > 1 {
child = ColumnsElem::new(child).with_count(columns).pack();
@@ -388,25 +395,25 @@ impl PageElem {
}
let fill = self.fill(styles);
- let foreground = self.foreground(styles);
- let background = self.background(styles);
+ let foreground = Cow::Borrowed(self.foreground(styles));
+ let background = Cow::Borrowed(self.background(styles));
let header_ascent = self.header_ascent(styles);
let footer_descent = self.footer_descent(styles);
let numbering = self.numbering(styles);
let numbering_meta = Meta::PageNumbering(numbering.clone().into_value());
let number_align = self.number_align(styles);
- let mut header = self.header(styles);
- let mut footer = self.footer(styles);
+ let mut header = Cow::Borrowed(self.header(styles));
+ let mut footer = Cow::Borrowed(self.footer(styles));
// Construct the numbering (for header or footer).
- let numbering_marginal = numbering.clone().map(|numbering| {
- let both = match &numbering {
+ let numbering_marginal = Cow::Owned(numbering.as_ref().map(|numbering| {
+ let both = match numbering {
Numbering::Pattern(pattern) => pattern.pieces() >= 2,
Numbering::Func(_) => true,
};
let mut counter =
- Counter::new(CounterKey::Page).display(Some(numbering), both);
+ Counter::new(CounterKey::Page).display(Some(numbering.clone()), both);
// We interpret the Y alignment as selecting header or footer
// and then ignore it for aligning the actual number.
@@ -415,12 +422,12 @@ impl PageElem {
}
counter
- });
+ }));
if matches!(number_align.y(), Some(VAlign::Top)) {
- header = header.or(numbering_marginal);
+ header = if header.is_some() { header } else { numbering_marginal };
} else {
- footer = footer.or(numbering_marginal);
+ footer = if footer.is_some() { footer } else { numbering_marginal };
}
// Post-process pages.
@@ -455,7 +462,7 @@ impl PageElem {
] {
tracing::info!("Layouting {name}");
- let Some(content) = marginal else { continue };
+ let Some(content) = &**marginal else { continue };
let (pos, area, align);
if ptr::eq(marginal, &header) {
@@ -488,14 +495,14 @@ impl PageElem {
}
}
- if let Some(fill) = &fill {
+ if let Some(fill) = fill {
frame.fill(fill.clone());
}
page_counter.visit(vt, frame)?;
// Add a PDF page label if there is a numbering.
- if let Some(num) = &numbering {
+ if let Some(num) = numbering {
if let Some(page_label) = num.apply_pdf(page_counter.logical()) {
frame.push_positionless_meta(Meta::PdfPageLabel(page_label));
}
@@ -657,10 +664,10 @@ pub enum Marginal {
impl Marginal {
/// Resolve the marginal based on the page number.
- pub fn resolve(&self, vt: &mut Vt, page: usize) -> SourceResult<Content> {
+ pub fn resolve(&self, vt: &mut Vt, page: usize) -> SourceResult<Cow<'_, Content>> {
Ok(match self {
- Self::Content(content) => content.clone(),
- Self::Func(func) => func.call_vt(vt, [page])?.display(),
+ Self::Content(content) => Cow::Borrowed(content),
+ Self::Func(func) => Cow::Owned(func.call_vt(vt, [page])?.display()),
})
}
}
diff --git a/crates/typst-library/src/layout/par.rs b/crates/typst-library/src/layout/par.rs
index 10f78ef2..b3d5fb3e 100644
--- a/crates/typst-library/src/layout/par.rs
+++ b/crates/typst-library/src/layout/par.rs
@@ -1,3 +1,4 @@
+use comemo::Prehashed;
use typst::eval::Tracer;
use typst::model::DelayedErrors;
use unicode_bidi::{BidiInfo, Level as BidiLevel};
@@ -104,7 +105,7 @@ pub struct ParElem {
/// The paragraph's children.
#[internal]
#[variadic]
- pub children: Vec<Content>,
+ pub children: Vec<Prehashed<Content>>,
}
impl Construct for ParElem {
@@ -158,12 +159,12 @@ impl ParElem {
let children = par.children();
// Collect all text into one string for BiDi analysis.
- let (text, segments, spans) = collect(&children, &styles, consecutive)?;
+ let (text, segments, spans) = collect(children, &styles, consecutive)?;
// Perform BiDi analysis and then prepare paragraph layout by building a
// representation on which we can do line breaking without layouting
// each and every line from scratch.
- let p = prepare(&mut vt, &children, &text, segments, spans, styles, region)?;
+ let p = prepare(&mut vt, children, &text, segments, spans, styles, region)?;
// Break the paragraph into lines.
let lines = linebreak(&vt, &p, region.x - p.hang);
@@ -246,8 +247,6 @@ pub(crate) struct Preparation<'a> {
pub items: Vec<Item<'a>>,
/// The span mapper.
pub spans: SpanMapper,
- /// The styles shared by all children.
- pub styles: StyleChain<'a>,
/// Whether to hyphenate if it's the same for all children.
pub hyphenate: Option<bool>,
/// The text language if it's the same for all children.
@@ -258,8 +257,16 @@ pub(crate) struct Preparation<'a> {
pub justify: bool,
/// The paragraph's hanging indent.
pub hang: Abs,
- /// The CJK-latin spacing.
+ /// Whether to add spacing between CJK and Latin characters.
pub cjk_latin_spacing: bool,
+ /// Whether font fallback is enabled for this paragraph.
+ pub fallback: bool,
+ /// The leading of the paragraph.
+ pub leading: Abs,
+ /// How to determine line breaks.
+ pub linebreaks: Smart<Linebreaks>,
+ /// The text size.
+ pub size: Abs,
}
impl<'a> Preparation<'a> {
@@ -525,15 +532,15 @@ impl<'a> Line<'a> {
/// string-level preprocessing like case transformations.
#[allow(clippy::type_complexity)]
fn collect<'a>(
- children: &'a [Content],
+ children: &'a [Prehashed<Content>],
styles: &'a StyleChain<'a>,
consecutive: bool,
) -> SourceResult<(String, Vec<(Segment<'a>, StyleChain<'a>)>, SpanMapper)> {
let mut full = String::new();
let mut quoter = Quoter::new();
- let mut segments = vec![];
+ let mut segments = Vec::with_capacity(2 + children.len());
let mut spans = SpanMapper::new();
- let mut iter = children.iter().peekable();
+ let mut iter = children.iter().map(|c| &**c).peekable();
let first_line_indent = ParElem::first_line_indent_in(*styles);
if !first_line_indent.is_zero()
@@ -565,9 +572,9 @@ fn collect<'a>(
} else if let Some(elem) = child.to::<TextElem>() {
let prev = full.len();
if let Some(case) = TextElem::case_in(styles) {
- full.push_str(&case.apply(&elem.text()));
+ full.push_str(&case.apply(elem.text()));
} else {
- full.push_str(&elem.text());
+ full.push_str(elem.text());
}
Segment::Text(full.len() - prev)
} else if let Some(elem) = child.to::<HElem>() {
@@ -576,7 +583,7 @@ fn collect<'a>(
}
full.push(SPACING_REPLACE);
- Segment::Spacing(elem.amount())
+ Segment::Spacing(*elem.amount())
} else if let Some(elem) = child.to::<LinebreakElem>() {
let c = if elem.justify(styles) { '\u{2028}' } else { '\n' };
full.push(c);
@@ -588,7 +595,7 @@ fn collect<'a>(
let lang = TextElem::lang_in(styles);
let region = TextElem::region_in(styles);
let quotes = Quotes::new(
- &quotes,
+ quotes,
lang,
region,
SmartquoteElem::alternative_in(styles),
@@ -656,7 +663,7 @@ fn collect<'a>(
/// contained inline-level content.
fn prepare<'a>(
vt: &mut Vt,
- children: &'a [Content],
+ children: &'a [Prehashed<Content>],
text: &'a str,
segments: Vec<(Segment<'a>, StyleChain<'a>)>,
spans: SpanMapper,
@@ -674,7 +681,7 @@ fn prepare<'a>(
);
let mut cursor = 0;
- let mut items = vec![];
+ let mut items = Vec::with_capacity(segments.len());
// Shape / layout the children and collect them into items.
for (segment, styles) in segments {
@@ -727,13 +734,16 @@ fn prepare<'a>(
bidi,
items,
spans,
- styles,
hyphenate: shared_get(styles, children, TextElem::hyphenate_in),
lang: shared_get(styles, children, TextElem::lang_in),
align: AlignElem::alignment_in(styles).resolve(styles).x,
justify: ParElem::justify_in(styles),
hang: ParElem::hanging_indent_in(styles),
cjk_latin_spacing,
+ fallback: TextElem::fallback_in(styles),
+ leading: ParElem::leading_in(styles),
+ linebreaks: ParElem::linebreaks_in(styles),
+ size: TextElem::size_in(styles),
})
}
@@ -852,7 +862,7 @@ fn is_compatible(a: Script, b: Script) -> bool {
/// paragraph.
fn shared_get<T: PartialEq>(
styles: StyleChain<'_>,
- children: &[Content],
+ children: &[Prehashed<Content>],
getter: fn(StyleChain) -> T,
) -> Option<T> {
let value = getter(styles);
@@ -865,8 +875,8 @@ fn shared_get<T: PartialEq>(
/// Find suitable linebreaks.
fn linebreak<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> {
- let linebreaks = ParElem::linebreaks_in(p.styles).unwrap_or_else(|| {
- if ParElem::justify_in(p.styles) {
+ let linebreaks = p.linebreaks.unwrap_or_else(|| {
+ if p.justify {
Linebreaks::Optimized
} else {
Linebreaks::Simple
@@ -883,7 +893,7 @@ fn linebreak<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> {
/// lines greedily, always taking the longest possible line. This may lead to
/// very unbalanced line, but is fast and simple.
fn linebreak_simple<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> {
- let mut lines = vec![];
+ let mut lines = Vec::with_capacity(16);
let mut start = 0;
let mut last = None;
@@ -964,8 +974,8 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L
line: line(vt, p, 0..0, Breakpoint::Mandatory),
}];
- let em = TextElem::size_in(p.styles);
-
+ let em = p.size;
+ let mut lines = Vec::with_capacity(16);
breakpoints(p, |end, breakpoint| {
let k = table.len();
let eof = end == p.bidi.text.len();
@@ -1071,7 +1081,6 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L
});
// Retrace the best path.
- let mut lines = vec![];
let mut idx = table.len() - 1;
while idx != 0 {
table.truncate(idx + 1);
@@ -1151,7 +1160,7 @@ fn line<'a>(
if hyphen || start < range.end || before.is_empty() {
let mut reshaped = shaped.reshape(vt, &p.spans, start..range.end);
if hyphen || shy {
- reshaped.push_hyphen(vt, TextElem::fallback_in(p.styles));
+ reshaped.push_hyphen(vt, p.fallback);
}
if let Some(last_glyph) = reshaped.glyphs.last() {
@@ -1287,11 +1296,10 @@ fn finalize(
.collect::<SourceResult<_>>()?;
// Prevent orphans.
- let leading = ParElem::leading_in(p.styles);
if frames.len() >= 2 && !frames[1].is_empty() {
let second = frames.remove(1);
let first = &mut frames[0];
- merge(first, second, leading);
+ merge(first, second, p.leading);
}
// Prevent widows.
@@ -1299,7 +1307,7 @@ fn finalize(
if len >= 2 && !frames[len - 2].is_empty() {
let second = frames.pop().unwrap();
let first = frames.last_mut().unwrap();
- merge(first, second, leading);
+ merge(first, second, p.leading);
}
Ok(Fragment::frames(frames))
diff --git a/crates/typst-library/src/layout/place.rs b/crates/typst-library/src/layout/place.rs
index 64cbd9a8..c8e83383 100644
--- a/crates/typst-library/src/layout/place.rs
+++ b/crates/typst-library/src/layout/place.rs
@@ -106,7 +106,10 @@ impl Layout for PlaceElem {
.at(self.span());
}
- let child = self.body().aligned(alignment.unwrap_or_else(|| Align::CENTER));
+ let child = self
+ .body()
+ .clone()
+ .aligned(alignment.unwrap_or_else(|| Align::CENTER));
let pod = Regions::one(base, Axes::splat(false));
let frame = child.layout(vt, styles, pod)?.into_frame();
diff --git a/crates/typst-library/src/layout/spacing.rs b/crates/typst-library/src/layout/spacing.rs
index 37f1ed35..88b6e2cd 100644
--- a/crates/typst-library/src/layout/spacing.rs
+++ b/crates/typst-library/src/layout/spacing.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
use crate::prelude::*;
/// Inserts horizontal spacing into a paragraph.
@@ -71,7 +73,7 @@ impl Behave for HElem {
fn larger(
&self,
- prev: &(Content, Behaviour, StyleChain),
+ prev: &(Cow<Content>, Behaviour, StyleChain),
styles: StyleChain,
) -> bool {
let Some(other) = prev.0.to::<Self>() else { return false };
@@ -173,7 +175,7 @@ impl Behave for VElem {
fn larger(
&self,
- prev: &(Content, Behaviour, StyleChain),
+ prev: &(Cow<Content>, Behaviour, StyleChain),
styles: StyleChain,
) -> bool {
let Some(other) = prev.0.to::<Self>() else { return false };
diff --git a/crates/typst-library/src/layout/stack.rs b/crates/typst-library/src/layout/stack.rs
index 398341b2..50d1c862 100644
--- a/crates/typst-library/src/layout/stack.rs
+++ b/crates/typst-library/src/layout/stack.rs
@@ -60,7 +60,7 @@ impl Layout for StackElem {
for child in self.children() {
match child {
StackChild::Spacing(kind) => {
- layouter.layout_spacing(kind);
+ layouter.layout_spacing(*kind);
deferred = None;
}
StackChild::Block(block) => {
@@ -68,7 +68,7 @@ impl Layout for StackElem {
layouter.layout_spacing(kind);
}
- layouter.layout_block(vt, &block, styles)?;
+ layouter.layout_block(vt, block, styles)?;
deferred = spacing;
}
}
@@ -79,7 +79,7 @@ impl Layout for StackElem {
}
/// A child of a stack element.
-#[derive(Hash)]
+#[derive(Clone, PartialEq, Hash)]
pub enum StackChild {
/// Spacing between other children.
Spacing(Spacing),
diff --git a/crates/typst-library/src/layout/table.rs b/crates/typst-library/src/layout/table.rs
index 056b63a2..9e7da071 100644
--- a/crates/typst-library/src/layout/table.rs
+++ b/crates/typst-library/src/layout/table.rs
@@ -1,7 +1,7 @@
use typst::eval::{CastInfo, Reflect};
use crate::layout::{AlignElem, GridLayouter, TrackSizings};
-use crate::meta::{Figurable, LocalName};
+use crate::meta::Figurable;
use crate::prelude::*;
/// A table of items.
@@ -38,10 +38,12 @@ use crate::prelude::*;
pub struct TableElem {
/// The column sizes. See the [grid documentation]($grid) for more
/// information on track sizing.
+ #[borrowed]
pub columns: TrackSizings,
/// The row sizes. See the [grid documentation]($grid) for more information
/// on track sizing.
+ #[borrowed]
pub rows: TrackSizings,
/// The gaps between rows & columns. See the [grid documentation]($grid) for
@@ -51,6 +53,7 @@ pub struct TableElem {
/// The gaps between columns. Takes precedence over `gutter`. See the
/// [grid documentation]($grid) for more information on gutters.
+ #[borrowed]
#[parse(
let gutter = args.named("gutter")?;
args.named("column-gutter")?.or_else(|| gutter.clone())
@@ -60,6 +63,7 @@ pub struct TableElem {
/// The gaps between rows. Takes precedence over `gutter`. See the
/// [grid documentation]($grid) for more information on gutters.
#[parse(args.named("row-gutter")?.or_else(|| gutter.clone()))]
+ #[borrowed]
pub row_gutter: TrackSizings,
/// How to fill the cells.
@@ -82,6 +86,7 @@ pub struct TableElem {
/// [Profit:], [500 €], [1000 €], [1500 €],
/// )
/// ```
+ #[borrowed]
pub fill: Celled<Option<Paint>>,
/// How to align the cells' content.
@@ -99,6 +104,7 @@ pub struct TableElem {
/// [A], [B], [C],
/// )
/// ```
+ #[borrowed]
pub align: Celled<Smart<Align>>,
/// How to [stroke]($stroke) the cells.
@@ -151,16 +157,20 @@ impl Layout for TableElem {
) -> SourceResult<Fragment> {
let inset = self.inset(styles);
let align = self.align(styles);
+ let columns = self.columns(styles);
+ let rows = self.rows(styles);
+ let column_gutter = self.column_gutter(styles);
+ let row_gutter = self.row_gutter(styles);
- let tracks = Axes::new(self.columns(styles).0, self.rows(styles).0);
- let gutter = Axes::new(self.column_gutter(styles).0, self.row_gutter(styles).0);
+ let tracks = Axes::new(columns.0.as_slice(), rows.0.as_slice());
+ let gutter = Axes::new(column_gutter.0.as_slice(), row_gutter.0.as_slice());
let cols = tracks.x.len().max(1);
let cells: Vec<_> = self
.children()
- .into_iter()
+ .iter()
.enumerate()
.map(|(i, child)| {
- let mut child = child.padded(inset);
+ let mut child = child.clone().padded(inset);
let x = i % cols;
let y = i / cols;
@@ -176,14 +186,8 @@ impl Layout for TableElem {
let stroke = self.stroke(styles).map(Stroke::unwrap_or_default);
// Prepare grid layout by unifying content and gutter tracks.
- let layouter = GridLayouter::new(
- tracks.as_deref(),
- gutter.as_deref(),
- &cells,
- regions,
- styles,
- self.span(),
- );
+ let layouter =
+ GridLayouter::new(tracks, gutter, &cells, regions, styles, self.span());
// Measure the columns and layout the grid row-by-row.
let mut layout = layouter.layout(vt)?;
@@ -321,7 +325,7 @@ impl<T: FromValue> FromValue for Celled<T> {
}
impl LocalName for TableElem {
- fn local_name(&self, lang: Lang, _: Option<Region>) -> &'static str {
+ fn local_name(lang: Lang, _: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Tabel",
Lang::ARABIC => "جدول",
diff --git a/crates/typst-library/src/layout/terms.rs b/crates/typst-library/src/layout/terms.rs
index 07f17bb0..d4262118 100644
--- a/crates/typst-library/src/layout/terms.rs
+++ b/crates/typst-library/src/layout/terms.rs
@@ -55,6 +55,7 @@ pub struct TermsElem {
/// / Colon: A nice separator symbol.
/// ```
#[default(HElem::new(Em::new(0.6).into()).with_weak(true).pack())]
+ #[borrowed]
pub separator: Content,
/// The indentation of each item.
@@ -114,20 +115,20 @@ impl Layout for TermsElem {
ParElem::leading_in(styles).into()
} else {
self.spacing(styles)
- .unwrap_or_else(|| BlockElem::below_in(styles).amount())
+ .unwrap_or_else(|| *BlockElem::below_in(styles).amount())
};
let mut seq = vec![];
- for (i, child) in self.children().into_iter().enumerate() {
+ for (i, child) in self.children().iter().enumerate() {
if i > 0 {
seq.push(VElem::new(gutter).with_weakness(1).pack());
}
if !indent.is_zero() {
seq.push(HElem::new(indent.into()).pack());
}
- seq.push(child.term().strong());
- seq.push(separator.clone());
- seq.push(child.description());
+ seq.push(child.term().clone().strong());
+ seq.push((*separator).clone());
+ seq.push(child.description().clone());
}
Content::sequence(seq)
diff --git a/crates/typst-library/src/math/accent.rs b/crates/typst-library/src/math/accent.rs
index a542111b..bedc5635 100644
--- a/crates/typst-library/src/math/accent.rs
+++ b/crates/typst-library/src/math/accent.rs
@@ -52,7 +52,7 @@ impl LayoutMath for AccentElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
ctx.style(ctx.style.with_cramped(true));
- let base = ctx.layout_fragment(&self.base())?;
+ let base = ctx.layout_fragment(self.base())?;
ctx.unstyle();
// Preserve class to preserve automatic spacing.
@@ -67,7 +67,7 @@ impl LayoutMath for AccentElem {
// Forcing the accent to be at least as large as the base makes it too
// wide in many case.
let Accent(c) = self.accent();
- let glyph = GlyphFragment::new(ctx, c, self.span());
+ let glyph = GlyphFragment::new(ctx, *c, self.span());
let short_fall = ACCENT_SHORT_FALL.scaled(ctx);
let variant = glyph.stretch_horizontal(ctx, base.width(), short_fall);
let accent = variant.frame;
@@ -116,6 +116,7 @@ fn attachment(ctx: &MathContext, id: GlyphId, italics_correction: Abs) -> Abs {
}
/// An accent character.
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Accent(char);
impl Accent {
@@ -130,7 +131,7 @@ cast! {
self => self.0.into_value(),
v: char => Self::new(v),
v: Content => match v.to::<TextElem>() {
- Some(elem) => Value::Str(elem.text().into()).cast()?,
+ Some(elem) => Value::Str(elem.text().clone().into()).cast()?,
None => bail!("expected text"),
},
}
diff --git a/crates/typst-library/src/math/attach.rs b/crates/typst-library/src/math/attach.rs
index 5d1e477e..3e6b69f2 100644
--- a/crates/typst-library/src/math/attach.rs
+++ b/crates/typst-library/src/math/attach.rs
@@ -50,7 +50,7 @@ impl LayoutMath for AttachElem {
.transpose()
};
- let base = ctx.layout_fragment(&self.base())?;
+ let base = ctx.layout_fragment(self.base())?;
ctx.style(ctx.style.for_superscript());
let tl = layout_attachment(ctx, Self::tl)?;
@@ -91,7 +91,7 @@ pub struct PrimesElem {
impl LayoutMath for PrimesElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- match self.count() {
+ match *self.count() {
count @ 1..=4 => {
let f = ctx.layout_fragment(&TextElem::packed(match count {
1 => '′',
@@ -137,7 +137,7 @@ pub struct ScriptsElem {
impl LayoutMath for ScriptsElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- let mut fragment = ctx.layout_fragment(&self.body())?;
+ let mut fragment = ctx.layout_fragment(self.body())?;
fragment.set_limits(Limits::Never);
ctx.push(fragment);
Ok(())
@@ -166,7 +166,7 @@ pub struct LimitsElem {
impl LayoutMath for LimitsElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- let mut fragment = ctx.layout_fragment(&self.body())?;
+ let mut fragment = ctx.layout_fragment(self.body())?;
fragment.set_limits(if self.inline(ctx.styles()) {
Limits::Always
} else {
diff --git a/crates/typst-library/src/math/cancel.rs b/crates/typst-library/src/math/cancel.rs
index d521149e..16e4067a 100644
--- a/crates/typst-library/src/math/cancel.rs
+++ b/crates/typst-library/src/math/cancel.rs
@@ -97,7 +97,7 @@ pub struct CancelElem {
impl LayoutMath for CancelElem {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- let body = ctx.layout_fragment(&self.body())?;
+ let body = ctx.layout_fragment(self.body())?;
// Use the same math class as the body, in order to preserve automatic spacing around it.
let body_class = body.class().unwrap_or(MathClass::Special);
let mut body = body.into_frame();
@@ -146,6 +146,7 @@ impl LayoutMath for CancelElem {
}
/// Defines the cancel line.
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum CancelAngle {
Angle(Angle),
Func(Func),
diff --git a/crates/typst-library/src/math/class.rs b/crates/typst-library/src/math/class.rs
index fc8a6c79..d2c5192d 100644
--- a/crates/typst-library/src/math/class.rs
+++ b/crates/typst-library/src/math/class.rs
@@ -27,11 +27,11 @@ pub struct ClassElem {
impl LayoutMath for ClassElem {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- ctx.style(ctx.style.with_class(self.class()));
- let mut fragment = ctx.layout_fragment(&self.body())?;
+ ctx.style(ctx.style.with_class(*self.class()));
+ let mut fragment = ctx.layout_fragment(self.body())?;
ctx.unstyle();
- fragment.set_class(self.class());
+ fragment.set_class(*self.class());
ctx.push(fragment);
Ok(())
}
diff --git a/crates/typst-library/src/math/ctx.rs b/crates/typst-library/src/math/ctx.rs
index 59ba057f..2637921c 100644
--- a/crates/typst-library/src/math/ctx.rs
+++ b/crates/typst-library/src/math/ctx.rs
@@ -1,3 +1,4 @@
+use comemo::Prehashed;
use ttf_parser::gsub::SubstitutionSubtable;
use ttf_parser::math::MathValue;
use typst::font::{FontStyle, FontWeight};
@@ -251,7 +252,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
// because it will be placed somewhere probably not at the left margin
// it will overflow. So emulate an `hbox` instead and allow the paragraph
// to extend as far as needed.
- let frame = ParElem::new(vec![elem])
+ let frame = ParElem::new(vec![Prehashed::new(elem)])
.layout(
self.vt,
self.outer.chain(&self.local),
diff --git a/crates/typst-library/src/math/frac.rs b/crates/typst-library/src/math/frac.rs
index ee582775..bd8d86bf 100644
--- a/crates/typst-library/src/math/frac.rs
+++ b/crates/typst-library/src/math/frac.rs
@@ -29,7 +29,7 @@ pub struct FracElem {
impl LayoutMath for FracElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- layout(ctx, &self.num(), &[self.denom()], false, self.span())
+ layout(ctx, self.num(), std::slice::from_ref(self.denom()), false, self.span())
}
}
@@ -62,7 +62,7 @@ pub struct BinomElem {
impl LayoutMath for BinomElem {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- layout(ctx, &self.upper(), &self.lower(), true, self.span())
+ layout(ctx, self.upper(), self.lower(), true, self.span())
}
}
diff --git a/crates/typst-library/src/math/fragment.rs b/crates/typst-library/src/math/fragment.rs
index 71d8d237..a40ed2bf 100644
--- a/crates/typst-library/src/math/fragment.rs
+++ b/crates/typst-library/src/math/fragment.rs
@@ -196,7 +196,7 @@ pub struct GlyphFragment {
pub font_size: Abs,
pub class: Option<MathClass>,
pub span: Span,
- pub meta: Vec<Meta>,
+ pub meta: SmallVec<[Meta; 1]>,
pub limits: Limits,
}
diff --git a/crates/typst-library/src/math/lr.rs b/crates/typst-library/src/math/lr.rs
index 16696f2e..39143620 100644
--- a/crates/typst-library/src/math/lr.rs
+++ b/crates/typst-library/src/math/lr.rs
@@ -37,7 +37,7 @@ impl LayoutMath for LrElem {
}
}
- let mut fragments = ctx.layout_fragments(&body)?;
+ let mut fragments = ctx.layout_fragments(body)?;
let axis = scaled!(ctx, axis_height);
let max_extent = fragments
.iter()
diff --git a/crates/typst-library/src/math/matrix.rs b/crates/typst-library/src/math/matrix.rs
index 333a5706..b54da5d6 100644
--- a/crates/typst-library/src/math/matrix.rs
+++ b/crates/typst-library/src/math/matrix.rs
@@ -49,7 +49,7 @@ impl LayoutMath for VecElem {
let delim = self.delim(ctx.styles());
let frame = layout_vec_body(
ctx,
- &self.children(),
+ self.children(),
FixedAlign::Center,
self.gap(ctx.styles()),
)?;
@@ -233,7 +233,7 @@ impl LayoutMath for MatElem {
let delim = self.delim(ctx.styles());
let frame = layout_mat_body(
ctx,
- &rows,
+ rows,
augment,
Axes::new(self.column_gap(ctx.styles()), self.row_gap(ctx.styles())),
self.span(),
@@ -303,7 +303,7 @@ impl LayoutMath for CasesElem {
let delim = self.delim(ctx.styles());
let frame = layout_vec_body(
ctx,
- &self.children(),
+ self.children(),
FixedAlign::Start,
self.gap(ctx.styles()),
)?;
@@ -562,7 +562,7 @@ fn layout_delimiters(
/// Parameters specifying how augmentation lines
/// should be drawn on a matrix.
-#[derive(Default, Clone, Hash)]
+#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct Augment<T: Numeric = Length> {
pub hline: Offsets,
pub vline: Offsets,
@@ -573,7 +573,7 @@ impl Augment<Abs> {
fn stroke_or(&self, fallback: FixedStroke) -> FixedStroke {
match &self.stroke {
Smart::Custom(v) => v.clone().unwrap_or(fallback),
- _ => fallback,
+ Smart::Auto => fallback,
}
}
}
@@ -594,7 +594,13 @@ impl Fold for Augment<Abs> {
type Output = Augment<Abs>;
fn fold(mut self, outer: Self::Output) -> Self::Output {
- self.stroke = self.stroke.fold(outer.stroke);
+ // Special case for handling `auto` strokes in subsequent `Augment`.
+ if self.stroke.is_auto() && outer.stroke.is_custom() {
+ self.stroke = outer.stroke;
+ } else {
+ self.stroke = self.stroke.fold(outer.stroke);
+ }
+
self
}
}
@@ -602,19 +608,22 @@ impl Fold for Augment<Abs> {
cast! {
Augment,
self => {
- let stroke = self.stroke.unwrap_or_default();
+ // if the stroke is auto and there is only one vertical line,
+ if self.stroke.is_auto() && self.hline.0.is_empty() && self.vline.0.len() == 1 {
+ return self.vline.0[0].into_value();
+ }
let d = dict! {
"hline" => self.hline.into_value(),
"vline" => self.vline.into_value(),
- "stroke" => stroke.into_value()
+ "stroke" => self.stroke.into_value()
};
d.into_value()
},
v: isize => Augment {
hline: Offsets::default(),
- vline: Offsets(vec![v]),
+ vline: Offsets(smallvec![v]),
stroke: Smart::Auto,
},
mut dict: Dict => {
@@ -636,14 +645,13 @@ cast! {
self => self.into_value(),
}
-/// The offsets at which augmentation lines
-/// should be drawn on a matrix.
-#[derive(Debug, Default, Clone, Hash)]
-pub struct Offsets(Vec<isize>);
+/// The offsets at which augmentation lines should be drawn on a matrix.
+#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
+pub struct Offsets(SmallVec<[isize; 1]>);
cast! {
Offsets,
self => self.0.into_value(),
- v: isize => Self(vec![v]),
+ v: isize => Self(smallvec![v]),
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
}
diff --git a/crates/typst-library/src/math/mod.rs b/crates/typst-library/src/math/mod.rs
index 26ab10c6..a4d44d00 100644
--- a/crates/typst-library/src/math/mod.rs
+++ b/crates/typst-library/src/math/mod.rs
@@ -32,6 +32,8 @@ pub use self::root::*;
pub use self::style::*;
pub use self::underover::*;
+use std::borrow::Cow;
+
use ttf_parser::{GlyphId, Rect};
use typst::eval::{Module, Scope};
use typst::font::{Font, FontWeight};
@@ -46,7 +48,7 @@ use self::spacing::*;
use crate::layout::{AlignElem, BoxElem, HElem, ParElem, Spacing};
use crate::meta::Supplement;
use crate::meta::{
- Count, Counter, CounterUpdate, LocalName, Numbering, Outlinable, Refable,
+ Count, Counter, CounterUpdate, LocalNameIn, Numbering, Outlinable, Refable,
};
use crate::prelude::*;
use crate::shared::BehavedBuilder;
@@ -182,7 +184,7 @@ impl Synthesize for EquationElem {
fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> {
// Resolve the supplement.
let supplement = match self.supplement(styles) {
- Smart::Auto => TextElem::packed(self.local_name_in(styles)),
+ Smart::Auto => TextElem::packed(Self::local_name_in(styles)),
Smart::Custom(None) => Content::empty(),
Smart::Custom(Some(supplement)) => supplement.resolve(vt, [self.clone()])?,
};
@@ -236,7 +238,7 @@ impl Layout for EquationElem {
let variant = variant(styles);
let world = vt.world;
let Some(font) = families(styles).find_map(|family| {
- let id = world.book().select(family.as_str(), variant)?;
+ let id = world.book().select(family, variant)?;
let font = world.font(id)?;
let _ = font.ttf().tables().math?.constants?;
Some(font)
@@ -312,7 +314,7 @@ impl Count for EquationElem {
}
impl LocalName for EquationElem {
- fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str {
+ fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Ekuacion",
Lang::ARABIC => "معادلة",
@@ -381,7 +383,7 @@ impl Outlinable for EquationElem {
let numbers = self
.counter()
- .at(vt, self.0.location().unwrap())?
+ .at(vt, self.location().unwrap())?
.display(vt, &numbering)?;
Ok(Some(supplement + numbers))
@@ -419,7 +421,7 @@ impl LayoutMath for Content {
if self.is_sequence() {
let mut bb = BehavedBuilder::new();
self.sequence_recursive_for_each(&mut |child: &Content| {
- bb.push(child.clone(), StyleChain::default())
+ bb.push(Cow::Owned(child.clone()), StyleChain::default())
});
for (child, _) in bb.finish().0.iter() {
diff --git a/crates/typst-library/src/math/op.rs b/crates/typst-library/src/math/op.rs
index 152efdf5..b4c36002 100644
--- a/crates/typst-library/src/math/op.rs
+++ b/crates/typst-library/src/math/op.rs
@@ -32,7 +32,7 @@ impl LayoutMath for OpElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let fragment =
- ctx.layout_text(&TextElem::new(self.text()).spanned(self.span()))?;
+ ctx.layout_text(&TextElem::new(self.text().clone()).spanned(self.span()))?;
ctx.push(
FrameFragment::new(ctx, fragment.into_frame())
.with_class(MathClass::Large)
diff --git a/crates/typst-library/src/math/root.rs b/crates/typst-library/src/math/root.rs
index 49ceb75f..13c5c147 100644
--- a/crates/typst-library/src/math/root.rs
+++ b/crates/typst-library/src/math/root.rs
@@ -32,7 +32,7 @@ pub struct RootElem {
impl LayoutMath for RootElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- layout(ctx, self.index(ctx.styles()).as_ref(), &self.radicand(), self.span())
+ layout(ctx, self.index(ctx.styles()).as_ref(), self.radicand(), self.span())
}
}
diff --git a/crates/typst-library/src/math/style.rs b/crates/typst-library/src/math/style.rs
index 4d80a235..774fadac 100644
--- a/crates/typst-library/src/math/style.rs
+++ b/crates/typst-library/src/math/style.rs
@@ -344,7 +344,7 @@ impl MathStyle {
/// The size of elements in an equation.
///
/// See the TeXbook p. 141.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Cast)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Cast, Hash)]
pub enum MathSize {
/// Second-level sub- and superscripts.
ScriptScript,
@@ -367,7 +367,7 @@ impl MathSize {
}
/// A mathematical style variant, as defined by Unicode.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Cast)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Cast, Hash)]
pub enum MathVariant {
Serif,
Sans,
diff --git a/crates/typst-library/src/math/underover.rs b/crates/typst-library/src/math/underover.rs
index 5d010c28..aeb83061 100644
--- a/crates/typst-library/src/math/underover.rs
+++ b/crates/typst-library/src/math/underover.rs
@@ -24,7 +24,7 @@ pub struct UnderlineElem {
impl LayoutMath for UnderlineElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- layout_underoverline(ctx, &self.body(), self.span(), LineKind::Under)
+ layout_underoverline(ctx, self.body(), self.span(), LineKind::Under)
}
}
@@ -43,7 +43,7 @@ pub struct OverlineElem {
impl LayoutMath for OverlineElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- layout_underoverline(ctx, &self.body(), self.span(), LineKind::Over)
+ layout_underoverline(ctx, self.body(), self.span(), LineKind::Over)
}
}
@@ -130,7 +130,7 @@ impl LayoutMath for UnderbraceElem {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
ctx,
- &self.body(),
+ self.body(),
&self.annotation(ctx.styles()),
'⏟',
BRACE_GAP,
@@ -161,7 +161,7 @@ impl LayoutMath for OverbraceElem {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
ctx,
- &self.body(),
+ self.body(),
&self.annotation(ctx.styles()),
'⏞',
BRACE_GAP,
@@ -192,7 +192,7 @@ impl LayoutMath for UnderbracketElem {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
ctx,
- &self.body(),
+ self.body(),
&self.annotation(ctx.styles()),
'⎵',
BRACKET_GAP,
@@ -223,7 +223,7 @@ impl LayoutMath for OverbracketElem {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
ctx,
- &self.body(),
+ self.body(),
&self.annotation(ctx.styles()),
'⎴',
BRACKET_GAP,
diff --git a/crates/typst-library/src/meta/bibliography.rs b/crates/typst-library/src/meta/bibliography.rs
index d429d343..342135ec 100644
--- a/crates/typst-library/src/meta/bibliography.rs
+++ b/crates/typst-library/src/meta/bibliography.rs
@@ -19,13 +19,13 @@ use typed_arena::Arena;
use typst::diag::FileError;
use typst::eval::{eval_string, Bytes, CastInfo, EvalMode, Reflect};
use typst::font::FontStyle;
-use typst::util::option_eq;
+use typst::util::{option_eq, PicoStr};
use super::{CitationForm, CiteGroup, LocalName};
use crate::layout::{
BlockElem, GridElem, HElem, PadElem, ParElem, Sizing, TrackSizings, VElem,
};
-use crate::meta::{FootnoteElem, HeadingElem};
+use crate::meta::{FootnoteElem, HeadingElem, LocalNameIn};
use crate::prelude::*;
use crate::text::{Delta, SubElem, SuperElem, TextElem};
@@ -130,7 +130,7 @@ pub struct BibliographyElem {
}
/// A list of bibliography file paths.
-#[derive(Debug, Default, Clone, Hash)]
+#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct BibPaths(Vec<EcoString>);
cast! {
@@ -153,11 +153,12 @@ impl BibliographyElem {
bail!("multiple bibliographies are not yet supported");
}
- Ok(elem.to::<Self>().unwrap().clone())
+ Ok(elem.to::<Self>().cloned().unwrap())
}
/// Whether the bibliography contains the given key.
- pub fn has(vt: &Vt, key: &str) -> bool {
+ pub fn has(vt: &Vt, key: impl Into<PicoStr>) -> bool {
+ let key = key.into();
vt.introspector
.query(&Self::elem().select())
.iter()
@@ -199,14 +200,9 @@ impl Show for BibliographyElem {
let mut seq = vec![];
if let Some(title) = self.title(styles) {
- let title =
- title.unwrap_or_else(|| {
- TextElem::packed(self.local_name(
- TextElem::lang_in(styles),
- TextElem::region_in(styles),
- ))
- .spanned(self.span())
- });
+ let title = title.unwrap_or_else(|| {
+ TextElem::packed(Self::local_name_in(styles)).spanned(self.span())
+ });
seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack());
}
@@ -220,7 +216,7 @@ impl Show for BibliographyElem {
.ok_or("CSL style is not suitable for bibliographies")
.at(span)?;
- let row_gutter = BlockElem::below_in(styles).amount();
+ let row_gutter = *BlockElem::below_in(styles).amount();
if references.iter().any(|(prefix, _)| prefix.is_some()) {
let mut cells = vec![];
for (prefix, reference) in references {
@@ -231,9 +227,9 @@ impl Show for BibliographyElem {
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
seq.push(
GridElem::new(cells)
- .with_columns(TrackSizings(vec![Sizing::Auto; 2]))
- .with_column_gutter(TrackSizings(vec![COLUMN_GUTTER.into()]))
- .with_row_gutter(TrackSizings(vec![row_gutter.into()]))
+ .with_columns(TrackSizings(smallvec![Sizing::Auto; 2]))
+ .with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()]))
+ .with_row_gutter(TrackSizings(smallvec![(row_gutter).into()]))
.pack(),
);
} else {
@@ -263,7 +259,7 @@ impl Finalize for BibliographyElem {
}
impl LocalName for BibliographyElem {
- fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str {
+ fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Bibliografi",
Lang::ARABIC => "المراجع",
@@ -300,7 +296,7 @@ impl LocalName for BibliographyElem {
#[ty]
#[derive(Debug, Clone, PartialEq)]
pub struct Bibliography {
- map: Arc<IndexMap<EcoString, hayagriva::Entry>>,
+ map: Arc<IndexMap<PicoStr, hayagriva::Entry>>,
hash: u128,
}
@@ -371,8 +367,8 @@ impl Bibliography {
})
}
- fn has(&self, key: &str) -> bool {
- self.map.contains_key(key)
+ fn has(&self, key: impl Into<PicoStr>) -> bool {
+ self.map.contains_key(&key.into())
}
fn entries(&self) -> impl Iterator<Item = &hayagriva::Entry> {
@@ -645,7 +641,7 @@ impl<'a> Generator<'a> {
let mut driver = BibliographyDriver::new();
for elem in &self.groups {
let group = elem.to::<CiteGroup>().unwrap();
- let location = group.0.location().unwrap();
+ let location = group.location().unwrap();
let children = group.children();
// Groups should never be empty.
@@ -657,12 +653,13 @@ impl<'a> Generator<'a> {
let mut normal = true;
// Create infos and items for each child in the group.
- for child in &children {
- let key = child.key();
- let Some(entry) = database.map.get(&key.0) else {
+ for child in children {
+ let key = *child.key();
+ let Some(entry) = database.map.get(&key.into_inner()) else {
errors.push(error!(
child.span(),
- "key `{}` does not exist in the bibliography", key.0
+ "key `{}` does not exist in the bibliography",
+ key.as_str()
));
continue;
};
@@ -714,13 +711,13 @@ impl<'a> Generator<'a> {
driver.citation(CitationRequest::new(
items,
style,
- Some(locale(first.lang(), first.region())),
+ Some(locale(*first.lang(), *first.region())),
&LOCALES,
None,
));
}
- let locale = locale(self.bibliography.lang(), self.bibliography.region());
+ let locale = locale(*self.bibliography.lang(), *self.bibliography.region());
// Add hidden items for everything if we should print the whole
// bibliography.
@@ -761,7 +758,7 @@ impl<'a> Generator<'a> {
// so that we can link there.
let mut links = HashMap::new();
if let Some(bibliography) = &rendered.bibliography {
- let location = self.bibliography.0.location().unwrap();
+ let location = self.bibliography.location().unwrap();
for (k, item) in bibliography.items.iter().enumerate() {
links.insert(item.key.as_str(), location.variant(k + 1));
}
@@ -770,8 +767,7 @@ impl<'a> Generator<'a> {
let mut output = std::mem::take(&mut self.failures);
for (info, citation) in self.infos.iter().zip(&rendered.citations) {
let supplement = |i: usize| info.subinfos.get(i)?.supplement.clone();
- let link =
- |i: usize| links.get(info.subinfos.get(i)?.key.0.as_str()).copied();
+ let link = |i: usize| links.get(info.subinfos.get(i)?.key.as_str()).copied();
let renderer = ElemRenderer {
world: self.world,
@@ -811,13 +807,13 @@ impl<'a> Generator<'a> {
let mut first_occurances = HashMap::new();
for info in &self.infos {
for subinfo in &info.subinfos {
- let key = subinfo.key.0.as_str();
+ let key = subinfo.key.as_str();
first_occurances.entry(key).or_insert(info.location);
}
}
// The location of the bibliography.
- let location = self.bibliography.0.location().unwrap();
+ let location = self.bibliography.location().unwrap();
let mut output = vec![];
for (k, item) in rendered.items.iter().enumerate() {
@@ -918,8 +914,8 @@ impl ElemRenderer<'_> {
if let Some(prefix) = suf_prefix {
const COLUMN_GUTTER: Em = Em::new(0.65);
content = GridElem::new(vec![prefix, content])
- .with_columns(TrackSizings(vec![Sizing::Auto; 2]))
- .with_column_gutter(TrackSizings(vec![COLUMN_GUTTER.into()]))
+ .with_columns(TrackSizings(smallvec![Sizing::Auto; 2]))
+ .with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()]))
.pack();
}
diff --git a/crates/typst-library/src/meta/cite.rs b/crates/typst-library/src/meta/cite.rs
index 2e3c4155..a61523d8 100644
--- a/crates/typst-library/src/meta/cite.rs
+++ b/crates/typst-library/src/meta/cite.rs
@@ -141,7 +141,7 @@ impl Show for CiteGroup {
#[tracing::instrument(name = "CiteGroup::show", skip(self, vt))]
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
Ok(vt.delayed(|vt| {
- let location = self.0.location().unwrap();
+ let location = self.location().unwrap();
let span = self.span();
Works::generate(vt.world, vt.introspector)
.at(span)?
diff --git a/crates/typst-library/src/meta/context.rs b/crates/typst-library/src/meta/context.rs
index 3a82a925..59b35577 100644
--- a/crates/typst-library/src/meta/context.rs
+++ b/crates/typst-library/src/meta/context.rs
@@ -37,7 +37,7 @@ impl Show for LocateElem {
#[tracing::instrument(name = "LocateElem::show", skip(self, vt))]
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
Ok(vt.delayed(|vt| {
- let location = self.0.location().unwrap();
+ let location = self.location().unwrap();
Ok(self.func().call_vt(vt, [location])?.display())
}))
}
diff --git a/crates/typst-library/src/meta/counter.rs b/crates/typst-library/src/meta/counter.rs
index 1ad0bff1..45041a38 100644
--- a/crates/typst-library/src/meta/counter.rs
+++ b/crates/typst-library/src/meta/counter.rs
@@ -284,9 +284,9 @@ impl Counter {
}
if let Some(update) = match elem.to::<UpdateElem>() {
- Some(elem) => Some(elem.update()),
+ Some(elem) => Some(elem.update().clone()),
None => match elem.with::<dyn Count>() {
- Some(countable) => countable.update(),
+ Some(countable) => countable.update().clone(),
None => Some(CounterUpdate::Step(NonZeroUsize::ONE)),
},
} {
@@ -301,8 +301,7 @@ impl Counter {
/// The selector relevant for this counter's updates.
fn selector(&self) -> Selector {
- let mut selector =
- Selector::Elem(UpdateElem::elem(), Some(dict! { "key" => self.0.clone() }));
+ let mut selector = select_where!(UpdateElem, Key => self.0.clone());
if let CounterKey::Selector(key) = &self.0 {
selector = Selector::Or(eco_vec![selector, key.clone()]);
@@ -613,17 +612,18 @@ impl Show for DisplayElem {
#[tracing::instrument(name = "DisplayElem::show", skip_all)]
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
Ok(vt.delayed(|vt| {
- let location = self.0.location().unwrap();
+ let location = self.location().unwrap();
let counter = self.counter();
let numbering = self
.numbering()
+ .clone()
.or_else(|| {
let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else {
return None;
};
if func == HeadingElem::elem() {
- HeadingElem::numbering_in(styles)
+ HeadingElem::numbering_in(styles).clone()
} else if func == FigureElem::elem() {
FigureElem::numbering_in(styles)
} else if func == EquationElem::elem() {
@@ -634,7 +634,7 @@ impl Show for DisplayElem {
})
.unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into());
- let state = if self.both() {
+ let state = if *self.both() {
counter.both(vt, location)?
} else {
counter.at(vt, location)?
@@ -695,9 +695,9 @@ impl ManualPageCounter {
FrameItem::Group(group) => self.visit(vt, &group.frame)?,
FrameItem::Meta(Meta::Elem(elem), _) => {
let Some(elem) = elem.to::<UpdateElem>() else { continue };
- if elem.key() == CounterKey::Page {
+ if *elem.key() == CounterKey::Page {
let mut state = CounterState(smallvec![self.logical]);
- state.update(vt, elem.update())?;
+ state.update(vt, elem.update().clone())?;
self.logical = state.first();
}
}
diff --git a/crates/typst-library/src/meta/document.rs b/crates/typst-library/src/meta/document.rs
index 55c365ac..f6ff6812 100644
--- a/crates/typst-library/src/meta/document.rs
+++ b/crates/typst-library/src/meta/document.rs
@@ -1,3 +1,4 @@
+use comemo::Prehashed;
use typst::eval::Datetime;
use crate::layout::{LayoutRoot, PageElem};
@@ -43,9 +44,8 @@ pub struct DocumentElem {
pub date: Smart<Option<Datetime>>,
/// The page runs.
- #[internal]
#[variadic]
- pub children: Vec<Content>,
+ pub children: Vec<Prehashed<Content>>,
}
impl Construct for DocumentElem {
@@ -64,7 +64,7 @@ impl LayoutRoot for DocumentElem {
let mut page_counter = ManualPageCounter::new();
let children = self.children();
- let mut iter = children.iter().peekable();
+ let mut iter = children.iter().map(|c| &**c).peekable();
while let Some(mut child) = iter.next() {
let outer = styles;
@@ -99,7 +99,7 @@ impl LayoutRoot for DocumentElem {
}
/// A list of authors.
-#[derive(Debug, Default, Clone, Hash)]
+#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct Author(Vec<EcoString>);
cast! {
@@ -110,7 +110,7 @@ cast! {
}
/// A list of keywords.
-#[derive(Debug, Default, Clone, Hash)]
+#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct Keywords(Vec<EcoString>);
cast! {
diff --git a/crates/typst-library/src/meta/figure.rs b/crates/typst-library/src/meta/figure.rs
index 990c9860..bfcc9b44 100644
--- a/crates/typst-library/src/meta/figure.rs
+++ b/crates/typst-library/src/meta/figure.rs
@@ -1,9 +1,8 @@
+use std::borrow::Cow;
use std::str::FromStr;
use typst::util::option_eq;
-use super::{
- Count, Counter, CounterKey, CounterUpdate, LocalName, Numbering, NumberingPattern,
-};
+use super::{Count, Counter, CounterKey, CounterUpdate, Numbering, NumberingPattern};
use crate::layout::{BlockElem, PlaceElem, VElem};
use crate::meta::{Outlinable, Refable, Supplement};
use crate::prelude::*;
@@ -170,6 +169,7 @@ pub struct FigureElem {
/// kind: "foo",
/// )
/// ```
+ #[borrowed]
pub supplement: Smart<Option<Supplement>>,
/// How to number the figure. Accepts a
@@ -212,25 +212,21 @@ impl Synthesize for FigureElem {
let kind = self.kind(styles).unwrap_or_else(|| {
self.body()
.query_first(Selector::can::<dyn Figurable>())
- .cloned()
.map(|elem| FigureKind::Elem(elem.func()))
.unwrap_or_else(|| FigureKind::Elem(ImageElem::elem()))
});
// Resolve the supplement.
- let supplement = match self.supplement(styles) {
+ let supplement = match self.supplement(styles).as_ref() {
Smart::Auto => {
// Default to the local name for the kind, if available.
let name = match &kind {
- FigureKind::Elem(func) => {
- let empty = Content::new(*func);
- empty.with::<dyn LocalName>().map(|c| {
- TextElem::packed(c.local_name(
- TextElem::lang_in(styles),
- TextElem::region_in(styles),
- ))
- })
- }
+ FigureKind::Elem(func) => func
+ .local_name(
+ TextElem::lang_in(styles),
+ TextElem::region_in(styles),
+ )
+ .map(TextElem::packed),
FigureKind::Name(_) => None,
};
@@ -245,24 +241,21 @@ impl Synthesize for FigureElem {
// Resolve the supplement with the first descendant of the kind or
// just the body, if none was found.
let descendant = match kind {
- FigureKind::Elem(func) => {
- self.body().query_first(Selector::Elem(func, None)).cloned()
- }
+ FigureKind::Elem(func) => self
+ .body()
+ .query_first(Selector::Elem(func, None))
+ .map(Cow::Owned),
FigureKind::Name(_) => None,
};
- let target = descendant.unwrap_or_else(|| self.body());
+ let target = descendant.unwrap_or_else(|| Cow::Borrowed(self.body()));
Some(supplement.resolve(vt, [target])?)
}
};
// Construct the figure's counter.
- let counter = Counter::new(CounterKey::Selector(Selector::Elem(
- Self::elem(),
- Some(dict! {
- "kind" => kind.clone(),
- }),
- )));
+ let counter =
+ Counter::new(CounterKey::Selector(select_where!(Self, Kind => kind.clone())));
// Fill the figure's caption.
let mut caption = self.caption(styles);
@@ -271,7 +264,7 @@ impl Synthesize for FigureElem {
caption.push_supplement(supplement.clone());
caption.push_numbering(numbering.clone());
caption.push_counter(Some(counter.clone()));
- caption.push_location(self.0.location());
+ caption.push_figure_location(self.location());
}
self.push_placement(self.placement(styles));
@@ -289,7 +282,7 @@ impl Synthesize for FigureElem {
impl Show for FigureElem {
#[tracing::instrument(name = "FigureElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- let mut realized = self.body();
+ let mut realized = self.body().clone();
// Build the caption, if any.
if let Some(caption) = self.caption(styles) {
@@ -339,14 +332,15 @@ impl Count for FigureElem {
impl Refable for FigureElem {
fn supplement(&self) -> Content {
// After synthesis, this should always be custom content.
- match self.supplement(StyleChain::default()) {
- Smart::Custom(Some(Supplement::Content(content))) => content,
+ let default = StyleChain::default();
+ match self.supplement(default).as_ref() {
+ Smart::Custom(Some(Supplement::Content(content))) => content.clone(),
_ => Content::empty(),
}
}
fn counter(&self) -> Counter {
- self.counter().unwrap_or_else(|| Counter::of(Self::elem()))
+ self.counter().clone().unwrap_or_else(|| Counter::of(Self::elem()))
}
fn numbering(&self) -> Option<Numbering> {
@@ -364,17 +358,17 @@ impl Outlinable for FigureElem {
return Ok(None);
};
- let mut realized = caption.body();
+ let mut realized = caption.body().clone();
if let (
Smart::Custom(Some(Supplement::Content(mut supplement))),
Some(counter),
Some(numbering),
) = (
- self.supplement(StyleChain::default()),
+ self.supplement(StyleChain::default()).clone(),
self.counter(),
self.numbering(StyleChain::default()),
) {
- let location = self.0.location().unwrap();
+ let location = self.location().unwrap();
let numbers = counter.at(vt, location)?.display(vt, &numbering)?;
if !supplement.is_empty() {
@@ -497,8 +491,9 @@ pub struct FigureCaption {
pub counter: Option<Counter>,
/// The figure's location.
+ #[internal]
#[synthesized]
- pub location: Option<Location>,
+ pub figure_location: Option<Location>,
}
impl FigureCaption {
@@ -542,12 +537,15 @@ impl Synthesize for FigureCaption {
impl Show for FigureCaption {
#[tracing::instrument(name = "FigureCaption::show", skip_all)]
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- let mut realized = self.body();
+ let mut realized = self.body().clone();
- if let (Some(mut supplement), Some(numbering), Some(counter), Some(location)) =
- (self.supplement(), self.numbering(), self.counter(), self.location())
- {
- let numbers = counter.at(vt, location)?.display(vt, &numbering)?;
+ if let (Some(mut supplement), Some(numbering), Some(counter), Some(location)) = (
+ self.supplement().clone(),
+ self.numbering(),
+ self.counter(),
+ self.figure_location(),
+ ) {
+ let numbers = counter.at(vt, *location)?.display(vt, numbering)?;
if !supplement.is_empty() {
supplement += TextElem::packed('\u{a0}');
}
@@ -564,7 +562,7 @@ cast! {
}
/// The `kind` parameter of a [`FigureElem`].
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum FigureKind {
/// The kind is an element function.
Elem(Element),
@@ -585,4 +583,4 @@ cast! {
/// An element that can be auto-detected in a figure.
///
/// This trait is used to determine the type of a figure.
-pub trait Figurable: LocalName {}
+pub trait Figurable {}
diff --git a/crates/typst-library/src/meta/footnote.rs b/crates/typst-library/src/meta/footnote.rs
index a8f0b4dd..4306f833 100644
--- a/crates/typst-library/src/meta/footnote.rs
+++ b/crates/typst-library/src/meta/footnote.rs
@@ -59,6 +59,7 @@ pub struct FootnoteElem {
/// #footnote[Star],
/// #footnote[Dagger]
/// ```
+ #[borrowed]
#[default(Numbering::Pattern(NumberingPattern::from_str("1").unwrap()))]
pub numbering: Numbering,
@@ -91,7 +92,7 @@ impl FootnoteElem {
}
/// Returns the content of the body of this footnote if it is not a ref.
- pub fn body_content(&self) -> Option<Content> {
+ pub fn body_content(&self) -> Option<&Content> {
match self.body() {
FootnoteBody::Content(content) => Some(content),
_ => None,
@@ -102,20 +103,20 @@ impl FootnoteElem {
pub fn declaration_location(&self, vt: &Vt) -> StrResult<Location> {
match self.body() {
FootnoteBody::Reference(label) => {
- let element: Prehashed<Content> = vt.introspector.query_label(&label)?;
+ let element: Prehashed<Content> = vt.introspector.query_label(*label)?;
let footnote = element
.to::<FootnoteElem>()
.ok_or("referenced element should be a footnote")?;
footnote.declaration_location(vt)
}
- _ => Ok(self.0.location().unwrap()),
+ _ => Ok(self.location().unwrap()),
}
}
}
impl Synthesize for FootnoteElem {
fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> {
- self.push_numbering(self.numbering(styles));
+ self.push_numbering(self.numbering(styles).clone());
Ok(())
}
}
@@ -127,7 +128,7 @@ impl Show for FootnoteElem {
let loc = self.declaration_location(vt).at(self.span())?;
let numbering = self.numbering(styles);
let counter = Counter::of(Self::elem());
- let num = counter.at(vt, loc)?.display(vt, &numbering)?;
+ let num = counter.at(vt, loc)?.display(vt, numbering)?;
let sup = SuperElem::new(num).pack();
let loc = loc.variant(1);
// Add zero-width weak spacing to make the footnote "sticky".
@@ -144,7 +145,7 @@ impl Count for FootnoteElem {
/// The body of a footnote can be either some content or a label referencing
/// another footnote.
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum FootnoteBody {
Content(Content),
Reference(Label),
@@ -266,10 +267,11 @@ impl Show for FootnoteEntry {
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
let note = self.note();
let number_gap = Em::new(0.05);
- let numbering = note.numbering(StyleChain::default());
+ let default = StyleChain::default();
+ let numbering = note.numbering(default);
let counter = Counter::of(FootnoteElem::elem());
- let loc = note.0.location().unwrap();
- let num = counter.at(vt, loc)?.display(vt, &numbering)?;
+ let loc = note.location().unwrap();
+ let num = counter.at(vt, loc)?.display(vt, numbering)?;
let sup = SuperElem::new(num)
.pack()
.linked(Destination::Location(loc))
@@ -278,7 +280,7 @@ impl Show for FootnoteEntry {
HElem::new(self.indent(styles).into()).pack(),
sup,
HElem::new(number_gap.into()).with_weak(true).pack(),
- note.body_content().unwrap(),
+ note.body_content().unwrap().clone(),
]))
}
}
diff --git a/crates/typst-library/src/meta/heading.rs b/crates/typst-library/src/meta/heading.rs
index 34af8238..1a2f4dd0 100644
--- a/crates/typst-library/src/meta/heading.rs
+++ b/crates/typst-library/src/meta/heading.rs
@@ -3,7 +3,7 @@ use typst::util::option_eq;
use super::{Counter, CounterUpdate, LocalName, Numbering, Outlinable, Refable};
use crate::layout::{BlockElem, HElem, VElem};
-use crate::meta::{Count, Supplement};
+use crate::meta::{Count, LocalNameIn, Supplement};
use crate::prelude::*;
use crate::text::{SpaceElem, TextElem, TextSize};
@@ -54,6 +54,7 @@ pub struct HeadingElem {
/// == A subsection
/// === A sub-subsection
/// ```
+ #[borrowed]
pub numbering: Option<Numbering>,
/// A supplement for the heading.
@@ -124,13 +125,13 @@ impl Synthesize for HeadingElem {
fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> {
// Resolve the supplement.
let supplement = match self.supplement(styles) {
- Smart::Auto => TextElem::packed(self.local_name_in(styles)),
+ Smart::Auto => TextElem::packed(Self::local_name_in(styles)),
Smart::Custom(None) => Content::empty(),
Smart::Custom(Some(supplement)) => supplement.resolve(vt, [self.clone()])?,
};
self.push_level(self.level(styles));
- self.push_numbering(self.numbering(styles));
+ self.push_numbering(self.numbering(styles).clone());
self.push_supplement(Smart::Custom(Some(Supplement::Content(supplement))));
self.push_outlined(self.outlined(styles));
self.push_bookmarked(self.bookmarked(styles));
@@ -142,10 +143,10 @@ impl Synthesize for HeadingElem {
impl Show for HeadingElem {
#[tracing::instrument(name = "HeadingElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- let mut realized = self.body();
- if let Some(numbering) = self.numbering(styles) {
+ let mut realized = self.body().clone();
+ if let Some(numbering) = self.numbering(styles).as_ref() {
realized = Counter::of(Self::elem())
- .display(Some(numbering), false)
+ .display(Some(numbering.clone()), false)
.spanned(self.span())
+ HElem::new(Em::new(0.3).into()).with_weak(true).pack()
+ realized;
@@ -204,7 +205,7 @@ impl Refable for HeadingElem {
}
fn numbering(&self) -> Option<Numbering> {
- self.numbering(StyleChain::default())
+ self.numbering(StyleChain::default()).clone()
}
}
@@ -214,11 +215,12 @@ impl Outlinable for HeadingElem {
return Ok(None);
}
- let mut content = self.body();
- if let Some(numbering) = self.numbering(StyleChain::default()) {
+ let mut content = self.body().clone();
+ let default = StyleChain::default();
+ if let Some(numbering) = self.numbering(default).as_ref() {
let numbers = Counter::of(Self::elem())
- .at(vt, self.0.location().unwrap())?
- .display(vt, &numbering)?;
+ .at(vt, self.location().unwrap())?
+ .display(vt, numbering)?;
content = numbers + SpaceElem::new().pack() + content;
};
@@ -231,7 +233,7 @@ impl Outlinable for HeadingElem {
}
impl LocalName for HeadingElem {
- fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str {
+ fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Kapitull",
Lang::ARABIC => "الفصل",
diff --git a/crates/typst-library/src/meta/link.rs b/crates/typst-library/src/meta/link.rs
index 7b68b186..74857f1b 100644
--- a/crates/typst-library/src/meta/link.rs
+++ b/crates/typst-library/src/meta/link.rs
@@ -84,12 +84,12 @@ impl LinkElem {
impl Show for LinkElem {
#[tracing::instrument(name = "LinkElem::show", skip(self, vt))]
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
- let body = self.body();
+ let body = self.body().clone();
let linked = match self.dest() {
- LinkTarget::Dest(dest) => body.linked(dest),
+ LinkTarget::Dest(dest) => body.linked(dest.clone()),
LinkTarget::Label(label) => vt
.delayed(|vt| {
- let elem = vt.introspector.query_label(&label).at(self.span())?;
+ let elem = vt.introspector.query_label(*label).at(self.span())?;
let dest = Destination::Location(elem.location().unwrap());
Ok(Some(body.clone().linked(dest)))
})
@@ -110,7 +110,7 @@ fn body_from_url(url: &EcoString) -> Content {
}
/// A target where a link can go.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum LinkTarget {
Dest(Destination),
Label(Label),
diff --git a/crates/typst-library/src/meta/mod.rs b/crates/typst-library/src/meta/mod.rs
index 1019864f..ffe861ab 100644
--- a/crates/typst-library/src/meta/mod.rs
+++ b/crates/typst-library/src/meta/mod.rs
@@ -62,13 +62,15 @@ pub(super) fn define(global: &mut Scope) {
global.define_func::<query>();
}
-/// The named with which an element is referenced.
-pub trait LocalName {
- /// Get the name in the given language and (optionally) region.
- fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str;
-
- /// Resolve the local name with a style chain.
- fn local_name_in(&self, styles: StyleChain) -> &'static str {
- self.local_name(TextElem::lang_in(styles), TextElem::region_in(styles))
+/// An element that has a local name.
+pub trait LocalNameIn: LocalName {
+ /// Gets the local name from the style chain.
+ fn local_name_in(styles: StyleChain) -> &'static str
+ where
+ Self: Sized,
+ {
+ Self::local_name(TextElem::lang_in(styles), TextElem::region_in(styles))
}
}
+
+impl<T: LocalName> LocalNameIn for T {}
diff --git a/crates/typst-library/src/meta/outline.rs b/crates/typst-library/src/meta/outline.rs
index 9266ba2b..e7332ab3 100644
--- a/crates/typst-library/src/meta/outline.rs
+++ b/crates/typst-library/src/meta/outline.rs
@@ -6,6 +6,7 @@ use super::{
Counter, CounterKey, HeadingElem, LocalName, Numbering, NumberingPattern, Refable,
};
use crate::layout::{BoxElem, HElem, HideElem, ParbreakElem, RepeatElem, Spacing};
+use crate::meta::LocalNameIn;
use crate::prelude::*;
use crate::text::{LinebreakElem, SpaceElem, TextElem};
@@ -88,10 +89,8 @@ pub struct OutlineElem {
/// caption: [Experiment results],
/// )
/// ```
- #[default(LocatableSelector(Selector::Elem(
- HeadingElem::elem(),
- Some(dict! { "outlined" => true })
- )))]
+ #[default(LocatableSelector(select_where!(HeadingElem, Outlined => true)))]
+ #[borrowed]
pub target: LocatableSelector,
/// The maximum level up to which elements are included in the outline. When
@@ -161,6 +160,7 @@ pub struct OutlineElem {
/// #lorem(10)
/// ```
#[default(None)]
+ #[borrowed]
pub indent: Option<Smart<OutlineIndent>>,
/// Content to fill the space between the title and the page number. Can be
@@ -187,14 +187,9 @@ impl Show for OutlineElem {
let mut seq = vec![ParbreakElem::new().pack()];
// Build the outline title.
if let Some(title) = self.title(styles) {
- let title =
- title.unwrap_or_else(|| {
- TextElem::packed(self.local_name(
- TextElem::lang_in(styles),
- TextElem::region_in(styles),
- ))
- .spanned(self.span())
- });
+ let title = title.unwrap_or_else(|| {
+ TextElem::packed(Self::local_name_in(styles)).spanned(self.span())
+ });
seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack());
}
@@ -217,7 +212,7 @@ impl Show for OutlineElem {
};
let level = entry.level();
- if depth < level {
+ if depth < *level {
continue;
}
@@ -226,12 +221,12 @@ impl Show for OutlineElem {
while ancestors
.last()
.and_then(|ancestor| ancestor.with::<dyn Outlinable>())
- .map_or(false, |last| last.level() >= level)
+ .map_or(false, |last| last.level() >= *level)
{
ancestors.pop();
}
- OutlineIndent::apply(&indent, vt, &ancestors, &mut seq, self.span())?;
+ OutlineIndent::apply(indent, vt, &ancestors, &mut seq, self.span())?;
// Add the overridable outline entry, followed by a line break.
seq.push(entry.pack());
@@ -255,7 +250,7 @@ impl Finalize for OutlineElem {
}
impl LocalName for OutlineElem {
- fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str {
+ fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Përmbajtja",
Lang::ARABIC => "المحتويات",
@@ -301,7 +296,7 @@ pub trait Outlinable: Refable {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum OutlineIndent {
Bool(bool),
Rel(Rel<Length>),
@@ -497,14 +492,14 @@ impl Show for OutlineEntry {
};
// The body text remains overridable.
- seq.push(self.body().linked(Destination::Location(location)));
+ seq.push(self.body().clone().linked(Destination::Location(location)));
// Add filler symbols between the section name and page number.
if let Some(filler) = self.fill() {
seq.push(SpaceElem::new().pack());
seq.push(
BoxElem::new()
- .with_body(Some(filler))
+ .with_body(Some(filler.clone()))
.with_width(Fr::one().into())
.pack(),
);
@@ -514,7 +509,7 @@ impl Show for OutlineEntry {
}
// Add the page number.
- let page = self.page().linked(Destination::Location(location));
+ let page = self.page().clone().linked(Destination::Location(location));
seq.push(page);
Ok(Content::sequence(seq))
diff --git a/crates/typst-library/src/meta/reference.rs b/crates/typst-library/src/meta/reference.rs
index 12e13929..3a463c80 100644
--- a/crates/typst-library/src/meta/reference.rs
+++ b/crates/typst-library/src/meta/reference.rs
@@ -115,6 +115,7 @@ pub struct RefElem {
/// in @intro[Part], it is done
/// manually.
/// ```
+ #[borrowed]
pub supplement: Smart<Option<Supplement>>,
/// A synthesized citation.
@@ -132,9 +133,9 @@ impl Synthesize for RefElem {
self.push_citation(Some(citation));
self.push_element(None);
- let target = self.target();
- if !BibliographyElem::has(vt, &target.0) {
- if let Ok(elem) = vt.introspector.query_label(&target) {
+ let target = *self.target();
+ if !BibliographyElem::has(vt, target) {
+ if let Ok(elem) = vt.introspector.query_label(target) {
self.push_element(Some(elem.into_inner()));
return Ok(());
}
@@ -148,22 +149,22 @@ impl Show for RefElem {
#[tracing::instrument(name = "RefElem::show", skip_all)]
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
Ok(vt.delayed(|vt| {
- let target = self.target();
- let elem = vt.introspector.query_label(&self.target());
+ let target = *self.target();
+ let elem = vt.introspector.query_label(target);
let span = self.span();
- if BibliographyElem::has(vt, &target.0) {
+ if BibliographyElem::has(vt, target) {
if elem.is_ok() {
bail!(span, "label occurs in the document and its bibliography");
}
- return Ok(self.to_citation(vt, styles)?.pack().spanned(span));
+ return Ok(self.to_citation(vt, styles)?.spanned(span).pack());
}
let elem = elem.at(span)?;
if elem.func() == FootnoteElem::elem() {
- return Ok(FootnoteElem::with_label(target).pack().spanned(span));
+ return Ok(FootnoteElem::with_label(target).spanned(span).pack());
}
let refable = elem
@@ -204,7 +205,7 @@ impl Show for RefElem {
.at(vt, elem.location().unwrap())?
.display(vt, &numbering.trimmed())?;
- let supplement = match self.supplement(styles) {
+ let supplement = match self.supplement(styles).as_ref() {
Smart::Auto => refable.supplement(),
Smart::Custom(None) => Content::empty(),
Smart::Custom(Some(supplement)) => {
@@ -225,10 +226,10 @@ impl Show for RefElem {
impl RefElem {
/// Turn the reference into a citation.
pub fn to_citation(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<CiteElem> {
- let mut elem = CiteElem::new(self.target());
- elem.0.set_location(self.0.location().unwrap());
+ let mut elem = CiteElem::new(*self.target());
+ elem.set_location(self.location().unwrap());
elem.synthesize(vt, styles)?;
- elem.push_supplement(match self.supplement(styles) {
+ elem.push_supplement(match self.supplement(styles).clone() {
Smart::Custom(Some(Supplement::Content(content))) => Some(content),
_ => None,
});
@@ -238,6 +239,7 @@ impl RefElem {
}
/// Additional content for a reference.
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum Supplement {
Content(Content),
Func(Func),
diff --git a/crates/typst-library/src/meta/state.rs b/crates/typst-library/src/meta/state.rs
index 137b754e..4f04628f 100644
--- a/crates/typst-library/src/meta/state.rs
+++ b/crates/typst-library/src/meta/state.rs
@@ -233,7 +233,7 @@ impl State {
for elem in introspector.query(&self.selector()) {
let elem = elem.to::<UpdateElem>().unwrap();
match elem.update() {
- StateUpdate::Set(value) => state = value,
+ StateUpdate::Set(value) => state = value.clone(),
StateUpdate::Func(func) => state = func.call_vt(&mut vt, [state])?,
}
stops.push(state.clone());
@@ -244,7 +244,7 @@ impl State {
/// The selector for this state's updates.
fn selector(&self) -> Selector {
- Selector::Elem(UpdateElem::elem(), Some(dict! { "key" => self.key.clone() }))
+ select_where!(UpdateElem, Key => self.key.clone())
}
}
@@ -383,7 +383,7 @@ impl Show for DisplayElem {
#[tracing::instrument(name = "DisplayElem::show", skip(self, vt))]
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
Ok(vt.delayed(|vt| {
- let location = self.0.location().unwrap();
+ let location = self.location().unwrap();
let value = self.state().at(vt, location)?;
Ok(match self.func() {
Some(func) => func.call_vt(vt, [value])?.display(),
diff --git a/crates/typst-library/src/prelude.rs b/crates/typst-library/src/prelude.rs
index 329cbf61..e3163e0f 100644
--- a/crates/typst-library/src/prelude.rs
+++ b/crates/typst-library/src/prelude.rs
@@ -10,6 +10,8 @@ pub use comemo::{Track, Tracked, TrackedMut};
#[doc(no_inline)]
pub use ecow::{eco_format, EcoString};
#[doc(no_inline)]
+pub use smallvec::{smallvec, SmallVec};
+#[doc(no_inline)]
pub use typst::diag::{bail, error, At, Hint, SourceResult, StrResult};
#[doc(no_inline)]
pub use typst::doc::*;
@@ -22,10 +24,10 @@ pub use typst::eval::{
pub use typst::geom::*;
#[doc(no_inline)]
pub use typst::model::{
- elem, Behave, Behaviour, Construct, Content, Element, Finalize, Fold, Introspector,
- Label, Locatable, LocatableSelector, Location, Locator, MetaElem, NativeElement,
- PlainText, Resolve, Selector, Set, Show, StyleChain, StyleVec, Styles, Synthesize,
- Unlabellable, Vt,
+ elem, select_where, Behave, Behaviour, Construct, Content, Element, ElementFields,
+ Finalize, Fold, Introspector, Label, LocalName, Locatable, LocatableSelector,
+ Location, Locator, MetaElem, NativeElement, PlainText, Resolve, Selector, Set, Show,
+ StyleChain, StyleVec, Styles, Synthesize, Unlabellable, Vt,
};
#[doc(no_inline)]
pub use typst::syntax::{FileId, Span, Spanned};
diff --git a/crates/typst-library/src/shared/behave.rs b/crates/typst-library/src/shared/behave.rs
index f97e3fbc..e152fbb5 100644
--- a/crates/typst-library/src/shared/behave.rs
+++ b/crates/typst-library/src/shared/behave.rs
@@ -1,16 +1,18 @@
//! Element interaction.
+use std::borrow::Cow;
+
use typst::model::{Behave, Behaviour, Content, StyleChain, StyleVec, StyleVecBuilder};
/// A wrapper around a [`StyleVecBuilder`] that allows elements to interact.
#[derive(Debug)]
pub struct BehavedBuilder<'a> {
/// The internal builder.
- builder: StyleVecBuilder<'a, Content>,
+ builder: StyleVecBuilder<'a, Cow<'a, Content>>,
/// Staged weak and ignorant elements that we can't yet commit to the
/// builder. The option is `Some(_)` for weak elements and `None` for
/// ignorant elements.
- staged: Vec<(Content, Behaviour, StyleChain<'a>)>,
+ staged: Vec<(Cow<'a, Content>, Behaviour, StyleChain<'a>)>,
/// What the last non-ignorant item was.
last: Behaviour,
}
@@ -41,7 +43,7 @@ impl<'a> BehavedBuilder<'a> {
}
/// Push an item into the sequence.
- pub fn push(&mut self, elem: Content, styles: StyleChain<'a>) {
+ pub fn push(&mut self, elem: Cow<'a, Content>, styles: StyleChain<'a>) {
let interaction = elem
.with::<dyn Behave>()
.map_or(Behaviour::Supportive, Behave::behaviour);
@@ -81,12 +83,12 @@ impl<'a> BehavedBuilder<'a> {
}
/// Iterate over the contained elements.
- pub fn elems(&self) -> impl DoubleEndedIterator<Item = &Content> {
+ pub fn elems(&self) -> impl DoubleEndedIterator<Item = &Cow<'a, Content>> {
self.builder.elems().chain(self.staged.iter().map(|(item, ..)| item))
}
/// Return the finish style vec and the common prefix chain.
- pub fn finish(mut self) -> (StyleVec<Content>, StyleChain<'a>) {
+ pub fn finish(mut self) -> (StyleVec<Cow<'a, Content>>, StyleChain<'a>) {
self.flush(false);
self.builder.finish()
}
diff --git a/crates/typst-library/src/shared/ext.rs b/crates/typst-library/src/shared/ext.rs
index e6431423..60614820 100644
--- a/crates/typst-library/src/shared/ext.rs
+++ b/crates/typst-library/src/shared/ext.rs
@@ -47,13 +47,13 @@ impl ContentExt for Content {
}
fn linked(self, dest: Destination) -> Self {
- self.styled(MetaElem::set_data(vec![Meta::Link(dest)]))
+ self.styled(MetaElem::set_data(smallvec![Meta::Link(dest)]))
}
fn backlinked(self, loc: Location) -> Self {
let mut backlink = Content::empty();
backlink.set_location(loc);
- self.styled(MetaElem::set_data(vec![Meta::Elem(backlink)]))
+ self.styled(MetaElem::set_data(smallvec![Meta::Elem(backlink)]))
}
fn aligned(self, align: Align) -> Self {
@@ -85,7 +85,7 @@ impl StylesExt for Styles {
fn set_family(&mut self, preferred: FontFamily, existing: StyleChain) {
self.set(TextElem::set_font(FontList(
std::iter::once(preferred)
- .chain(TextElem::font_in(existing))
+ .chain(TextElem::font_in(existing).into_iter().cloned())
.collect(),
)));
}
diff --git a/crates/typst-library/src/text/deco.rs b/crates/typst-library/src/text/deco.rs
index 136dfad8..d8167788 100644
--- a/crates/typst-library/src/text/deco.rs
+++ b/crates/typst-library/src/text/deco.rs
@@ -78,7 +78,7 @@ pub struct UnderlineElem {
impl Show for UnderlineElem {
#[tracing::instrument(name = "UnderlineElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(TextElem::set_deco(Decoration {
+ Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
line: DecoLine::Underline {
stroke: self.stroke(styles).unwrap_or_default(),
offset: self.offset(styles),
@@ -170,7 +170,7 @@ pub struct OverlineElem {
impl Show for OverlineElem {
#[tracing::instrument(name = "OverlineElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(TextElem::set_deco(Decoration {
+ Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
line: DecoLine::Overline {
stroke: self.stroke(styles).unwrap_or_default(),
offset: self.offset(styles),
@@ -247,7 +247,7 @@ pub struct StrikeElem {
impl Show for StrikeElem {
#[tracing::instrument(name = "StrikeElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(TextElem::set_deco(Decoration {
+ Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
// Note that we do not support evade option for strikethrough.
line: DecoLine::Strikethrough {
stroke: self.stroke(styles).unwrap_or_default(),
@@ -317,7 +317,7 @@ pub struct HighlightElem {
impl Show for HighlightElem {
#[tracing::instrument(name = "HighlightElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(TextElem::set_deco(Decoration {
+ Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
line: DecoLine::Highlight {
fill: self.fill(styles),
top_edge: self.top_edge(styles),
diff --git a/crates/typst-library/src/text/misc.rs b/crates/typst-library/src/text/misc.rs
index 73657345..9f768f11 100644
--- a/crates/typst-library/src/text/misc.rs
+++ b/crates/typst-library/src/text/misc.rs
@@ -2,9 +2,15 @@ use super::TextElem;
use crate::prelude::*;
/// A text space.
-#[elem(Behave, Unlabellable, PlainText)]
+#[elem(Behave, Unlabellable, PlainText, Repr)]
pub struct SpaceElem {}
+impl Repr for SpaceElem {
+ fn repr(&self) -> EcoString {
+ EcoString::inline("[ ]")
+ }
+}
+
impl Behave for SpaceElem {
fn behaviour(&self) -> Behaviour {
Behaviour::Weak(2)
@@ -98,7 +104,10 @@ pub struct StrongElem {
impl Show for StrongElem {
#[tracing::instrument(name = "StrongElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(TextElem::set_delta(Delta(self.delta(styles)))))
+ Ok(self
+ .body()
+ .clone()
+ .styled(TextElem::set_delta(Delta(self.delta(styles)))))
}
}
@@ -153,7 +162,7 @@ pub struct EmphElem {
impl Show for EmphElem {
#[tracing::instrument(name = "EmphElem::show", skip(self))]
fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> {
- Ok(self.body().styled(TextElem::set_emph(Toggle)))
+ Ok(self.body().clone().styled(TextElem::set_emph(Toggle)))
}
}
diff --git a/crates/typst-library/src/text/mod.rs b/crates/typst-library/src/text/mod.rs
index 27dd4a3f..84a68d6f 100644
--- a/crates/typst-library/src/text/mod.rs
+++ b/crates/typst-library/src/text/mod.rs
@@ -64,7 +64,7 @@ pub(super) fn define(global: &mut Scope) {
/// With a function call.
/// ])
/// ```
-#[elem(Construct, PlainText)]
+#[elem(Construct, PlainText, Repr)]
pub struct TextElem {
/// A font family name or priority list of font family names.
///
@@ -97,6 +97,7 @@ pub struct TextElem {
/// هذا عربي.
/// ```
#[default(FontList(vec![FontFamily::new("Linux Libertine")]))]
+ #[borrowed]
pub font: FontList,
/// Whether to allow last resort font fallback when the primary font list
@@ -558,8 +559,8 @@ pub struct TextElem {
pub body: Content,
/// The text.
- #[internal]
#[required]
+ #[variant(0)]
pub text: EcoString,
/// A delta to apply on the font weight.
@@ -595,6 +596,12 @@ impl TextElem {
}
}
+impl Repr for TextElem {
+ fn repr(&self) -> EcoString {
+ eco_format!("[{}]", self.text)
+ }
+}
+
impl Construct for TextElem {
fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> {
// The text constructor is special: It doesn't create a text element.
@@ -608,7 +615,7 @@ impl Construct for TextElem {
impl PlainText for TextElem {
fn plain_text(&self, text: &mut EcoString) {
- text.push_str(&self.text());
+ text.push_str(self.text());
}
}
@@ -644,12 +651,12 @@ cast! {
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct FontList(pub Vec<FontFamily>);
-impl IntoIterator for FontList {
- type IntoIter = std::vec::IntoIter<FontFamily>;
- type Item = FontFamily;
+impl<'a> IntoIterator for &'a FontList {
+ type IntoIter = std::slice::Iter<'a, FontFamily>;
+ type Item = &'a FontFamily;
fn into_iter(self) -> Self::IntoIter {
- self.0.into_iter()
+ self.0.iter()
}
}
diff --git a/crates/typst-library/src/text/quote.rs b/crates/typst-library/src/text/quote.rs
index 86be2416..c555df2d 100644
--- a/crates/typst-library/src/text/quote.rs
+++ b/crates/typst-library/src/text/quote.rs
@@ -101,6 +101,7 @@ pub struct QuoteElem {
///
/// #bibliography("works.bib")
/// ```
+ #[borrowed]
attribution: Option<Attribution>,
/// The quote.
@@ -108,7 +109,7 @@ pub struct QuoteElem {
body: Content,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum Attribution {
Content(Content),
Label(Label),
@@ -126,7 +127,7 @@ cast! {
impl Show for QuoteElem {
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- let mut realized = self.body();
+ let mut realized = self.body().clone();
let block = self.block(styles);
if self.quotes(styles) == Smart::Custom(true) || !block {
@@ -140,16 +141,16 @@ impl Show for QuoteElem {
if block {
realized = BlockElem::new().with_body(Some(realized)).pack();
- if let Some(attribution) = self.attribution(styles) {
+ if let Some(attribution) = self.attribution(styles).as_ref() {
let mut seq = vec![TextElem::packed('—'), SpaceElem::new().pack()];
match attribution {
Attribution::Content(content) => {
- seq.push(content);
+ seq.push(content.clone());
}
Attribution::Label(label) => {
seq.push(
- CiteElem::new(label)
+ CiteElem::new(*label)
.with_form(Some(CitationForm::Prose))
.pack(),
);
@@ -164,7 +165,7 @@ impl Show for QuoteElem {
realized = PadElem::new(realized).pack();
} else if let Some(Attribution::Label(label)) = self.attribution(styles) {
- realized += SpaceElem::new().pack() + CiteElem::new(label).pack();
+ realized += SpaceElem::new().pack() + CiteElem::new(*label).pack();
}
Ok(realized)
diff --git a/crates/typst-library/src/text/quotes.rs b/crates/typst-library/src/text/quotes.rs
index 37e664fd..035ba422 100644
--- a/crates/typst-library/src/text/quotes.rs
+++ b/crates/typst-library/src/text/quotes.rs
@@ -78,6 +78,7 @@ pub struct SmartquoteElem {
/// #set smartquote(quotes: (single: ("[[", "]]"), double: auto))
/// 'Das sind eigene Anführungszeichen.'
/// ```
+ #[borrowed]
pub quotes: Smart<QuoteDict>,
}
diff --git a/crates/typst-library/src/text/raw.rs b/crates/typst-library/src/text/raw.rs
index d16659be..4f672be9 100644
--- a/crates/typst-library/src/text/raw.rs
+++ b/crates/typst-library/src/text/raw.rs
@@ -17,7 +17,7 @@ use super::{
FontFamily, FontList, Hyphenate, LinebreakElem, SmartquoteElem, TextElem, TextSize,
};
use crate::layout::BlockElem;
-use crate::meta::{Figurable, LocalName};
+use crate::meta::Figurable;
use crate::prelude::*;
// Shorthand for highlighter closures.
@@ -145,6 +145,7 @@ pub struct RawElem {
///
/// This is ```typ also *Typst*```, but inline!
/// ````
+ #[borrowed]
pub lang: Option<EcoString>,
/// The horizontal alignment that each line in a raw block should have.
@@ -225,11 +226,13 @@ pub struct RawElem {
let (theme_path, theme_data) = parse_theme(vm, args)?;
theme_path.map(Some)
)]
+ #[borrowed]
pub theme: Option<EcoString>,
/// The raw file buffer of syntax theme file.
#[internal]
#[parse(theme_data.map(Some))]
+ #[borrowed]
pub theme_data: Option<Bytes>,
/// The size for a tab stop in spaces. A tab is replaced with enough spaces to
@@ -252,7 +255,7 @@ pub struct RawElem {
/// Made accessible for the [`raw.line` element]($raw.line).
/// Allows more styling control in `show` rules.
#[synthesized]
- pub lines: Vec<Content>,
+ pub lines: Vec<RawLine>,
}
#[scope]
@@ -280,17 +283,20 @@ impl RawElem {
impl Synthesize for RawElem {
fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> {
- self.push_lang(self.lang(styles));
+ self.push_lang(self.lang(styles).clone());
- let mut text = self.text();
+ let mut text = self.text().clone();
if text.contains('\t') {
let tab_size = RawElem::tab_size_in(styles);
text = align_tabs(&text, tab_size);
}
+ let count = text.lines().count() as i64;
+
let lang = self
.lang(styles)
.as_ref()
+ .as_ref()
.map(|s| s.to_lowercase())
.or(Some("txt".into()));
@@ -298,12 +304,12 @@ impl Synthesize for RawElem {
load_syntaxes(&self.syntaxes(styles), &self.syntaxes_data(styles)).unwrap()
});
- let theme = self.theme(styles).map(|theme_path| {
- load_theme(theme_path, self.theme_data(styles).unwrap()).unwrap()
+ let theme = self.theme(styles).as_ref().as_ref().map(|theme_path| {
+ load_theme(theme_path, self.theme_data(styles).as_ref().as_ref().unwrap())
+ .unwrap()
});
let theme = theme.as_deref().unwrap_or(&THEME);
-
let foreground = theme.settings.foreground.unwrap_or(synt::Color::BLACK);
let mut seq = vec![];
@@ -319,15 +325,12 @@ impl Synthesize for RawElem {
synt::Highlighter::new(theme),
&mut |_, range, style| styled(&text[range], foreground, style),
&mut |i, range, line| {
- seq.push(
- RawLine::new(
- i + 1,
- text.split(is_newline).count() as i64,
- EcoString::from(&text[range]),
- Content::sequence(line.drain(..)),
- )
- .pack(),
- );
+ seq.push(RawLine::new(
+ i + 1,
+ count,
+ EcoString::from(&text[range]),
+ Content::sequence(line.drain(..)),
+ ));
},
)
.highlight();
@@ -342,7 +345,6 @@ impl Synthesize for RawElem {
})
}) {
let mut highlighter = syntect::easy::HighlightLines::new(syntax, theme);
- let len = text.lines().count();
for (i, line) in text.lines().enumerate() {
let mut line_content = vec![];
for (style, piece) in
@@ -351,18 +353,23 @@ impl Synthesize for RawElem {
line_content.push(styled(piece, foreground, style));
}
- seq.push(
- RawLine::new(
- i as i64 + 1,
- len as i64,
- EcoString::from(line),
- Content::sequence(line_content),
- )
- .pack(),
- );
+ seq.push(RawLine::new(
+ i as i64 + 1,
+ count,
+ EcoString::from(line),
+ Content::sequence(line_content),
+ ));
}
} else {
- seq.extend(text.lines().map(TextElem::packed));
+ let lines = text.lines();
+ seq.extend(lines.enumerate().map(|(i, line)| {
+ RawLine::new(
+ i as i64 + 1,
+ count,
+ EcoString::from(line),
+ TextElem::packed(line),
+ )
+ }));
};
self.push_lines(seq);
@@ -375,12 +382,12 @@ impl Show for RawElem {
#[tracing::instrument(name = "RawElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
let mut lines = EcoVec::with_capacity((2 * self.lines().len()).saturating_sub(1));
- for (i, line) in self.lines().into_iter().enumerate() {
+ for (i, line) in self.lines().iter().enumerate() {
if i != 0 {
lines.push(LinebreakElem::new().pack());
}
- lines.push(line);
+ lines.push(line.clone().pack());
}
let mut realized = Content::sequence(lines);
@@ -408,7 +415,7 @@ impl Finalize for RawElem {
}
impl LocalName for RawElem {
- fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str {
+ fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "List",
Lang::ARABIC => "قائمة",
@@ -443,7 +450,7 @@ impl Figurable for RawElem {}
impl PlainText for RawElem {
fn plain_text(&self, text: &mut EcoString) {
- text.push_str(&self.text());
+ text.push_str(self.text());
}
}
@@ -475,13 +482,13 @@ pub struct RawLine {
impl Show for RawLine {
fn show(&self, _vt: &mut Vt, _styles: StyleChain) -> SourceResult<Content> {
- Ok(self.body())
+ Ok(self.body().clone())
}
}
impl PlainText for RawLine {
fn plain_text(&self, text: &mut EcoString) {
- text.push_str(&self.text());
+ text.push_str(self.text());
}
}
@@ -617,7 +624,7 @@ fn to_syn(color: Color) -> synt::Color {
}
/// A list of bibliography file paths.
-#[derive(Debug, Default, Clone, Hash)]
+#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct SyntaxPaths(Vec<EcoString>);
cast! {
@@ -681,7 +688,7 @@ fn parse_syntaxes(
}
#[comemo::memoize]
-fn load_theme(path: EcoString, bytes: Bytes) -> StrResult<Arc<synt::Theme>> {
+fn load_theme(path: &str, bytes: &Bytes) -> StrResult<Arc<synt::Theme>> {
let mut cursor = std::io::Cursor::new(bytes.as_slice());
synt::ThemeSet::load_from_reader(&mut cursor)
@@ -705,7 +712,7 @@ fn parse_theme(
let data = vm.world().file(id).at(span)?;
// Check that parsing works.
- let _ = load_theme(path.clone(), data.clone()).at(span)?;
+ let _ = load_theme(&path, &data).at(span)?;
Ok((Some(path), Some(data)))
}
diff --git a/crates/typst-library/src/text/shaping.rs b/crates/typst-library/src/text/shaping.rs
index 0cfffce0..f7cf90bd 100644
--- a/crates/typst-library/src/text/shaping.rs
+++ b/crates/typst-library/src/text/shaping.rs
@@ -8,7 +8,7 @@ use typst::font::{Font, FontStyle, FontVariant};
use typst::util::SliceExt;
use unicode_script::{Script, UnicodeScript};
-use super::{decorate, FontFamily, NumberType, NumberWidth, TextElem};
+use super::{decorate, NumberType, NumberWidth, TextElem};
use crate::layout::SpanMapper;
use crate::prelude::*;
@@ -320,7 +320,7 @@ impl<'a> ShapedText<'a> {
for family in families(self.styles) {
if let Some(font) = world
.book()
- .select(family.as_str(), self.variant)
+ .select(family, self.variant)
.and_then(|id| world.font(id))
{
expand(&font, None);
@@ -424,7 +424,7 @@ impl<'a> ShapedText<'a> {
None
};
let mut chain = families(self.styles)
- .map(|family| book.select(family.as_str(), self.variant))
+ .map(|family| book.select(family, self.variant))
.chain(fallback_func.iter().map(|f| f()))
.flatten();
@@ -593,11 +593,11 @@ pub fn shape<'a>(
}
/// Shape text with font fallback using the `families` iterator.
-fn shape_segment(
+fn shape_segment<'a>(
ctx: &mut ShapingContext,
base: usize,
text: &str,
- mut families: impl Iterator<Item = FontFamily> + Clone,
+ mut families: impl Iterator<Item = &'a str> + Clone,
) {
// Fonts dont have newlines and tabs.
if text.chars().all(|c| c == '\n' || c == '\t') {
@@ -608,7 +608,7 @@ fn shape_segment(
let world = ctx.vt.world;
let book = world.book();
let mut selection = families.find_map(|family| {
- book.select(family.as_str(), ctx.variant)
+ book.select(family, ctx.variant)
.and_then(|id| world.font(id))
.filter(|font| !ctx.used.contains(font))
});
@@ -871,7 +871,7 @@ pub fn variant(styles: StyleChain) -> FontVariant {
}
/// Resolve a prioritized iterator over the font families.
-pub fn families(styles: StyleChain) -> impl Iterator<Item = FontFamily> + Clone {
+pub fn families(styles: StyleChain) -> impl Iterator<Item = &str> + Clone {
const FALLBACKS: &[&str] = &[
"linux libertine",
"twitter color emoji",
@@ -883,7 +883,8 @@ pub fn families(styles: StyleChain) -> impl Iterator<Item = FontFamily> + Clone
let tail = if TextElem::fallback_in(styles) { FALLBACKS } else { &[] };
TextElem::font_in(styles)
.into_iter()
- .chain(tail.iter().copied().map(FontFamily::new))
+ .map(|family| family.as_str())
+ .chain(tail.iter().copied())
}
/// Collect the tags of the OpenType features to apply.
diff --git a/crates/typst-library/src/text/shift.rs b/crates/typst-library/src/text/shift.rs
index 6cb4d895..903982ef 100644
--- a/crates/typst-library/src/text/shift.rs
+++ b/crates/typst-library/src/text/shift.rs
@@ -44,7 +44,7 @@ pub struct SubElem {
impl Show for SubElem {
#[tracing::instrument(name = "SubElem::show", skip_all)]
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- let body = self.body();
+ let body = self.body().clone();
let mut transformed = None;
if self.typographic(styles) {
if let Some(text) = search_text(&body, true) {
@@ -104,7 +104,7 @@ pub struct SuperElem {
impl Show for SuperElem {
#[tracing::instrument(name = "SuperElem::show", skip_all)]
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
- let body = self.body();
+ let body = self.body().clone();
let mut transformed = None;
if self.typographic(styles) {
if let Some(text) = search_text(&body, false) {
@@ -127,7 +127,7 @@ fn search_text(content: &Content, sub: bool) -> Option<EcoString> {
if content.is::<SpaceElem>() {
Some(' '.into())
} else if let Some(elem) = content.to::<TextElem>() {
- convert_script(&elem.text(), sub)
+ convert_script(elem.text(), sub)
} else if let Some(children) = content.to_sequence() {
let mut full = EcoString::new();
for item in children {
diff --git a/crates/typst-library/src/visualize/image.rs b/crates/typst-library/src/visualize/image.rs
index 931e38c6..6e166bc0 100644
--- a/crates/typst-library/src/visualize/image.rs
+++ b/crates/typst-library/src/visualize/image.rs
@@ -6,7 +6,7 @@ use typst::image::{Image, ImageFormat, RasterFormat, VectorFormat};
use typst::util::option_eq;
use crate::compute::Readable;
-use crate::meta::{Figurable, LocalName};
+use crate::meta::Figurable;
use crate::prelude::*;
use crate::text::families;
@@ -41,6 +41,7 @@ pub struct ImageElem {
let data = vm.world().file(id).at(span)?;
path
)]
+ #[borrowed]
pub path: EcoString,
/// The raw file data.
@@ -157,11 +158,11 @@ impl Layout for ImageElem {
};
let image = Image::with_fonts(
- data.into(),
+ data.clone().into(),
format,
self.alt(styles),
vt.world,
- &families(styles).map(|s| s.as_str().into()).collect::<Vec<_>>(),
+ &families(styles).map(|s| s.into()).collect::<Vec<_>>(),
)
.at(self.span())?;
@@ -223,7 +224,7 @@ impl Layout for ImageElem {
}
impl LocalName for ImageElem {
- fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str {
+ fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Figurë",
Lang::ARABIC => "شكل",
diff --git a/crates/typst-library/src/visualize/path.rs b/crates/typst-library/src/visualize/path.rs
index 79364b07..43b11526 100644
--- a/crates/typst-library/src/visualize/path.rs
+++ b/crates/typst-library/src/visualize/path.rs
@@ -77,7 +77,7 @@ impl Layout for PathElem {
.to_point()
};
- let vertices: Vec<PathVertex> = self.vertices();
+ let vertices = self.vertices();
let points: Vec<Point> = vertices.iter().map(|c| resolve(c.vertex())).collect();
let mut size = Size::zero();