summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst/src/engine.rs14
-rw-r--r--crates/typst/src/foundations/styles.rs6
-rw-r--r--crates/typst/src/layout/flow.rs39
-rw-r--r--crates/typst/src/layout/frame.rs6
-rw-r--r--crates/typst/src/layout/mod.rs15
-rw-r--r--crates/typst/src/layout/regions.rs6
-rw-r--r--crates/typst/src/layout/transform.rs2
-rw-r--r--crates/typst/src/realize/mod.rs65
-rw-r--r--crates/typst/src/realize/process.rs4
9 files changed, 134 insertions, 23 deletions
diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs
index f42ea192..03e4957c 100644
--- a/crates/typst/src/engine.rs
+++ b/crates/typst/src/engine.rs
@@ -17,7 +17,7 @@ pub struct Engine<'a> {
/// Provides access to information about the document.
pub introspector: Tracked<'a, Introspector>,
/// The route the engine took during compilation. This is used to detect
- /// cyclic imports and too much nesting.
+ /// cyclic imports and excessive nesting.
pub route: Route<'a>,
/// Provides stable identities to elements.
pub locator: &'a mut Locator<'a>,
@@ -45,8 +45,11 @@ impl Engine<'_> {
}
/// The route the engine took during compilation. This is used to detect
-/// cyclic imports and too much nesting.
+/// cyclic imports and excessive nesting.
pub struct Route<'a> {
+ /// The parent route segment, if present.
+ ///
+ /// This is used when an engine is created from another engine.
// We need to override the constraint's lifetime here so that `Tracked` is
// covariant over the constraint. If it becomes invariant, we're in for a
// world of lifetime pain.
@@ -60,9 +63,10 @@ pub struct Route<'a> {
/// route exceeds `MAX_DEPTH`, then we throw a "maximum ... depth exceeded"
/// error.
len: usize,
- /// The upper bound we've established for the parent chain length. We don't
- /// know the exact length (that would defeat the whole purpose because it
- /// would prevent cache reuse of some computation at different,
+ /// The upper bound we've established for the parent chain length.
+ ///
+ /// We don't know the exact length (that would defeat the whole purpose
+ /// because it would prevent cache reuse of some computation at different,
/// non-exceeding depths).
upper: AtomicUsize,
}
diff --git a/crates/typst/src/foundations/styles.rs b/crates/typst/src/foundations/styles.rs
index 35460088..9b434a1e 100644
--- a/crates/typst/src/foundations/styles.rs
+++ b/crates/typst/src/foundations/styles.rs
@@ -354,9 +354,13 @@ impl Hash for dyn Blockable {
/// A show rule recipe.
#[derive(Clone, PartialEq, Hash)]
pub struct Recipe {
- /// The span errors are reported with.
+ /// The span that errors are reported with.
pub span: Span,
/// Determines whether the recipe applies to an element.
+ ///
+ /// If this is `None`, then this recipe is from a show rule with
+ /// no selector (`show: rest => ...`), which is [eagerly applied][Content::styled_with_recipe]
+ /// to the rest of the content in the scope.
pub selector: Option<Selector>,
/// The transformation to perform on the match.
pub transform: Transformation,
diff --git a/crates/typst/src/layout/flow.rs b/crates/typst/src/layout/flow.rs
index 3cc53c6a..1e09ed83 100644
--- a/crates/typst/src/layout/flow.rs
+++ b/crates/typst/src/layout/flow.rs
@@ -1,3 +1,9 @@
+//! Layout flows.
+//!
+//! A *flow* is a collection of block-level layoutable elements.
+//! This is analogous to a paragraph, which is a collection of
+//! inline-level layoutable elements.
+
use std::fmt::{self, Debug, Formatter};
use crate::diag::{bail, SourceResult};
@@ -20,7 +26,7 @@ use crate::util::Numeric;
/// and the contents of boxes.
#[elem(Debug, LayoutMultiple)]
pub struct FlowElem {
- /// The children that will be arranges into a flow.
+ /// The children that will be arranged into a flow.
#[variadic]
pub children: Vec<Content>,
}
@@ -96,10 +102,12 @@ struct FlowLayouter<'a> {
/// subtracting.
initial: Size,
/// Whether the last block was a paragraph.
+ ///
+ /// Used for indenting paragraphs after the first in a block.
last_was_par: bool,
/// Spacing and layouted blocks for the current region.
items: Vec<FlowItem>,
- /// A queue of floats.
+ /// A queue of floating elements.
pending_floats: Vec<FlowItem>,
/// Whether we have any footnotes in the current region.
has_footnotes: bool,
@@ -123,10 +131,19 @@ enum FlowItem {
Absolute(Abs, bool),
/// Fractional spacing between other items.
Fractional(Fr),
- /// A frame for a layouted block, how to align it, whether it sticks to the
- /// item after it (for orphan prevention), and whether it is movable
- /// (to keep it together with its footnotes).
- Frame { frame: Frame, align: Axes<FixedAlignment>, sticky: bool, movable: bool },
+ /// A frame for a layouted block.
+ Frame {
+ /// The frame itself.
+ frame: Frame,
+ /// How to align the frame.
+ align: Axes<FixedAlignment>,
+ /// Whether the frame sticks to the item after it (for orphan prevention).
+ sticky: bool,
+ /// Whether the frame is movable; that is, kept together with its footnotes.
+ ///
+ /// This is true for frames created by paragraphs and [`LayoutSingle`] elements.
+ movable: bool,
+ },
/// An absolutely placed frame.
Placed {
frame: Frame,
@@ -143,7 +160,7 @@ enum FlowItem {
impl FlowItem {
/// Whether this item is out-of-flow.
///
- /// Out-of-flow items are guaranteed to have a [`Size::zero()`].
+ /// Out-of-flow items are guaranteed to have a [zero size][Size::zero()].
fn is_out_of_flow(&self) -> bool {
match self {
Self::Placed { float: false, .. } => true,
@@ -235,6 +252,8 @@ impl<'a> FlowLayouter<'a> {
)?
.into_frames();
+ // If the first line doesn’t fit in this region, then defer any
+ // previous sticky frame to the next region (if available)
if let Some(first) = lines.first() {
while !self.regions.size.y.fits(first.height()) && !self.regions.in_last() {
let mut sticky = self.items.len();
@@ -641,6 +660,9 @@ impl<'a> FlowLayouter<'a> {
}
impl FlowLayouter<'_> {
+ /// Tries to process all footnotes in the frame, placing them
+ /// in the next region if they could not be placed in the current
+ /// one.
fn try_handle_footnotes(
&mut self,
engine: &mut Engine,
@@ -663,6 +685,9 @@ impl FlowLayouter<'_> {
}
/// Processes all footnotes in the frame.
+ ///
+ /// Returns true if the footnote entries fit in the allotted
+ /// regions.
fn handle_footnotes(
&mut self,
engine: &mut Engine,
diff --git a/crates/typst/src/layout/frame.rs b/crates/typst/src/layout/frame.rs
index b4223526..61e2d65f 100644
--- a/crates/typst/src/layout/frame.rs
+++ b/crates/typst/src/layout/frame.rs
@@ -285,6 +285,10 @@ impl Frame {
}
/// Attach the metadata from this style chain to the frame.
+ ///
+ /// If `force` is true, then the metadata is attached even when
+ /// the frame is empty.
+ // TODO: when would you want to pass true to `force` as opposed to false?
pub fn meta(&mut self, styles: StyleChain, force: bool) {
if force || !self.is_empty() {
self.meta_iter(MetaElem::data_in(styles));
@@ -456,6 +460,8 @@ pub enum FrameKind {
#[default]
Soft,
/// A container which uses its own size.
+ ///
+ /// This is used for page, block, box, column, grid, and stack elements.
Hard,
}
diff --git a/crates/typst/src/layout/mod.rs b/crates/typst/src/layout/mod.rs
index 7f0c3916..23a08c5f 100644
--- a/crates/typst/src/layout/mod.rs
+++ b/crates/typst/src/layout/mod.rs
@@ -119,6 +119,11 @@ pub fn define(global: &mut Scope) {
}
/// Root-level layout.
+///
+/// This produces a complete document and is implemented for
+/// [`DocumentElem`][crate::model::DocumentElem]. Any [`Content`]
+/// can also be laid out at root level, in which case it is
+/// wrapped inside a document element.
pub trait LayoutRoot {
/// Layout into a document with one frame per page.
fn layout_root(
@@ -128,7 +133,10 @@ pub trait LayoutRoot {
) -> SourceResult<Document>;
}
-/// Layout into multiple regions.
+/// Layout into multiple [regions][Regions].
+///
+/// This is more appropriate for elements that, for example, can be
+/// laid out across multiple pages or columns.
pub trait LayoutMultiple {
/// Layout into one frame per region.
fn layout(
@@ -160,7 +168,10 @@ pub trait LayoutMultiple {
}
}
-/// Layout into a single region.
+/// Layout into a single [region][Regions].
+///
+/// This is more appropriate for elements that don't make sense to
+/// layout across multiple pages or columns, such as shapes.
pub trait LayoutSingle {
/// Layout into one frame per region.
fn layout(
diff --git a/crates/typst/src/layout/regions.rs b/crates/typst/src/layout/regions.rs
index 46e85e68..d8807f37 100644
--- a/crates/typst/src/layout/regions.rs
+++ b/crates/typst/src/layout/regions.rs
@@ -3,6 +3,12 @@ use std::fmt::{self, Debug, Formatter};
use crate::layout::{Abs, Axes, Size};
/// A sequence of regions to layout into.
+///
+/// A *region* is a contiguous rectangular space in which elements
+/// can be laid out. All regions within a `Regions` object have the
+/// same width, namely `self.size.x`. This means that it is not
+/// currently possible to, for instance, have content wrap to the
+/// side of a floating element.
#[derive(Copy, Clone, Hash)]
pub struct Regions<'a> {
/// The remaining size of the first region.
diff --git a/crates/typst/src/layout/transform.rs b/crates/typst/src/layout/transform.rs
index 13ff66ae..85bbb362 100644
--- a/crates/typst/src/layout/transform.rs
+++ b/crates/typst/src/layout/transform.rs
@@ -8,7 +8,7 @@ use crate::layout::{
/// Moves content without affecting layout.
///
-/// The `move` function allows you to move content while th layout still 'sees'
+/// The `move` function allows you to move content while the layout still 'sees'
/// it at the original positions. Containers will still be sized as if the
/// content was not moved.
///
diff --git a/crates/typst/src/realize/mod.rs b/crates/typst/src/realize/mod.rs
index 99b12a18..e06059ff 100644
--- a/crates/typst/src/realize/mod.rs
+++ b/crates/typst/src/realize/mod.rs
@@ -1,4 +1,10 @@
//! Realization of content.
+//!
+//! *Realization* is the process of applying show rules to produce
+//! something that can be laid out directly.
+//!
+//! Currently, there are issues with the realization process, and
+//! it is subject to changes in the future.
mod arenas;
mod behaviour;
@@ -98,11 +104,13 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
}
}
+ /// Adds a piece of content to this builder.
fn accept(
&mut self,
mut content: &'a Content,
styles: StyleChain<'a>,
) -> SourceResult<()> {
+ // Implicitly wrap math content in an equation if needed
if content.can::<dyn LayoutMath>() && !content.is::<EquationElem>() {
content = self
.arenas
@@ -133,6 +141,8 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
return Ok(());
}
+ // Try to merge `content` with an element under construction
+
if self.cites.accept(content, styles) {
return Ok(());
}
@@ -227,6 +237,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
Ok(())
}
+ /// Interrupts citation grouping and adds the resulting citation group to the builder.
fn interrupt_cites(&mut self) -> SourceResult<()> {
if !self.cites.items.is_empty() {
let staged = mem::take(&mut self.cites.staged);
@@ -239,6 +250,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
Ok(())
}
+ /// Interrupts list building and adds the resulting list element to the builder.
fn interrupt_list(&mut self) -> SourceResult<()> {
self.interrupt_cites()?;
if !self.list.items.is_empty() {
@@ -252,6 +264,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
Ok(())
}
+ /// Interrupts paragraph building and adds the resulting paragraph element to the builder.
fn interrupt_par(&mut self) -> SourceResult<()> {
self.interrupt_list()?;
if !self.par.0.is_empty() {
@@ -262,6 +275,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
Ok(())
}
+ /// Interrupts page building and adds the resulting page element to the builder.
fn interrupt_page(
&mut self,
styles: Option<StyleChain<'a>>,
@@ -284,7 +298,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
}
}
-/// Accepts pagebreaks and pages.
+/// Builds a [document][DocumentElem] from pagebreaks and pages.
struct DocBuilder<'a> {
/// The page runs built so far.
pages: BehavedBuilder<'a>,
@@ -295,6 +309,12 @@ struct DocBuilder<'a> {
}
impl<'a> DocBuilder<'a> {
+ /// Tries to accept a piece of content.
+ ///
+ /// Returns true if this content could be merged into the document.
+ /// If this function returns false, then the
+ /// content could not be merged, and document building should be
+ /// interrupted so that the content can be added elsewhere.
fn accept(
&mut self,
arenas: &'a Arenas<'a>,
@@ -324,6 +344,8 @@ impl<'a> DocBuilder<'a> {
false
}
+ /// Turns this builder into the resulting document, along with
+ /// its [style chain][StyleChain].
fn finish(self) -> (Packed<DocumentElem>, StyleChain<'a>) {
let (children, trunk, span) = self.pages.finish();
(Packed::new(DocumentElem::new(children)).spanned(span), trunk)
@@ -340,11 +362,17 @@ impl Default for DocBuilder<'_> {
}
}
-/// Accepts flow content.
+/// Builds a [flow][FlowElem] from flow content.
#[derive(Default)]
struct FlowBuilder<'a>(BehavedBuilder<'a>, bool);
impl<'a> FlowBuilder<'a> {
+ /// Tries to accept a piece of content.
+ ///
+ /// Returns true if this content could be merged into the flow.
+ /// If this function returns false, then the
+ /// content could not be merged, and flow building should be
+ /// interrupted so that the content can be added elsewhere.
fn accept(
&mut self,
arenas: &'a Arenas<'a>,
@@ -403,17 +431,25 @@ impl<'a> FlowBuilder<'a> {
false
}
+ /// Turns this builder into the resulting flow, along with
+ /// its [style chain][StyleChain].
fn finish(self) -> (Packed<FlowElem>, StyleChain<'a>) {
let (children, trunk, span) = self.0.finish();
(Packed::new(FlowElem::new(children)).spanned(span), trunk)
}
}
-/// Accepts paragraph content.
+/// Builds a [paragraph][ParElem] from paragraph content.
#[derive(Default)]
struct ParBuilder<'a>(BehavedBuilder<'a>);
impl<'a> ParBuilder<'a> {
+ /// Tries to accept a piece of content.
+ ///
+ /// Returns true if this content could be merged into the paragraph.
+ /// If this function returns false, then the
+ /// content could not be merged, and paragraph building should be
+ /// interrupted so that the content can be added elsewhere.
fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool {
if content.is::<MetaElem>() {
if !self.0.is_empty() {
@@ -437,13 +473,16 @@ impl<'a> ParBuilder<'a> {
false
}
+ /// Turns this builder into the resulting paragraph, along with
+ /// its [style chain][StyleChain].
fn finish(self) -> (Packed<ParElem>, StyleChain<'a>) {
let (children, trunk, span) = self.0.finish();
(Packed::new(ParElem::new(children)).spanned(span), trunk)
}
}
-/// Accepts list / enum items, spaces, paragraph breaks.
+/// Builds a list (either [`ListElem`], [`EnumElem`], or [`TermsElem`])
+/// from list or enum items, spaces, and paragraph breaks.
struct ListBuilder<'a> {
/// The list items collected so far.
items: BehavedBuilder<'a>,
@@ -454,6 +493,12 @@ struct ListBuilder<'a> {
}
impl<'a> ListBuilder<'a> {
+ /// Tries to accept a piece of content.
+ ///
+ /// Returns true if this content could be merged into the list.
+ /// If this function returns false, then the
+ /// content could not be merged, and list building should be
+ /// interrupted so that the content can be added elsewhere.
fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool {
if !self.items.is_empty()
&& (content.is::<SpaceElem>() || content.is::<ParbreakElem>())
@@ -479,6 +524,8 @@ impl<'a> ListBuilder<'a> {
false
}
+ /// Turns this builder into the resulting list, along with
+ /// its [style chain][StyleChain].
fn finish(self) -> (Content, StyleChain<'a>) {
let (items, trunk, span) = self.items.finish_iter();
let mut items = items.peekable();
@@ -545,7 +592,7 @@ impl Default for ListBuilder<'_> {
}
}
-/// Accepts citations.
+/// Builds a [citation group][CiteGroup] from citations.
#[derive(Default)]
struct CiteGroupBuilder<'a> {
/// The styles.
@@ -557,6 +604,12 @@ struct CiteGroupBuilder<'a> {
}
impl<'a> CiteGroupBuilder<'a> {
+ /// Tries to accept a piece of content.
+ ///
+ /// Returns true if this content could be merged into the citation
+ /// group. If this function returns false, then the
+ /// content could not be merged, and citation grouping should be
+ /// interrupted so that the content can be added elsewhere.
fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool {
if !self.items.is_empty()
&& (content.is::<SpaceElem>() || content.is::<MetaElem>())
@@ -577,6 +630,8 @@ impl<'a> CiteGroupBuilder<'a> {
false
}
+ /// Turns this builder into the resulting citation group, along with
+ /// its [style chain][StyleChain].
fn finish(self) -> (Packed<CiteGroup>, StyleChain<'a>) {
let span = self.items.first().map(|cite| cite.span()).unwrap_or(Span::detached());
(Packed::new(CiteGroup::new(self.items)).spanned(span), self.styles)
diff --git a/crates/typst/src/realize/process.rs b/crates/typst/src/realize/process.rs
index 8d3d01a6..da06159b 100644
--- a/crates/typst/src/realize/process.rs
+++ b/crates/typst/src/realize/process.rs
@@ -15,7 +15,7 @@ use crate::util::{hash128, BitSet};
/// What to do with an element when encountering it during realization.
struct Verdict<'a> {
- /// Whether the element is already prepated (i.e. things that should only
+ /// Whether the element is already prepared (i.e. things that should only
/// happen once have happened).
prepared: bool,
/// A map of styles to apply to the element.
@@ -32,7 +32,7 @@ enum ShowStep<'a> {
Builtin,
}
-/// Whether the `target` element needs processing.
+/// Returns whether the `target` element needs processing.
pub fn processable<'a>(
engine: &mut Engine,
target: &'a Content,