Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show block-level elements as blocks #4310

Merged
merged 1 commit into from
Jun 3, 2024
Merged

Show block-level elements as blocks #4310

merged 1 commit into from
Jun 3, 2024

Conversation

laurmaedje
Copy link
Member

This PR reworks how block-level elements are represented and laid out:

  • Previously, block-level elements respected block.{above, below}, but other than that, they weren't blocks per se
  • Instead, now block-level elements implement Show and show themselves as BlockElems
  • This removes the need for the layout traits LayoutRoot, LayoutMultiple, and LayoutSingle.
  • To implement custom behaviour (like table layout), the body of a BlockElem can be a closure which is given access to the regions (just like layout(size => ..) in Typst).

This change has the following benefits:

  • First of all, things like show list: set block(..) now make more sense conceptually, since these blocks are really physically present. Due to this, the internal handling of the above and below properties is much more natural now. The exception for this are paragraphs, which are still not blocks with this PR. They are merely a collection of inline-level items and, in a future PR, text and other inline elements will likely be able to exist without a wrapping paragraph, directly as a flow child. This makes it sensible for them not be wrapped in a block. Rather, the paragraph would apply paragraph-specific things like first-line-indent and then show itself as its children, which would then be collected directly into a flow. Since, in contrast to e.g. headings, paragraphs also almost never need different above and below values, I am considering to introduce set par(spacing: ..) specifically for paragraphs, which would also be more beginner-friendly than the current show-set rule. The show-set rule would only be needed to override the block spacing (which would inherit par.spacing) for specific block-level elements.

  • While the layout traits were static, in the new setup, an element can show itself differently under different circumstances:

    • Different handling for HTML export can arise naturally from a show rule that produces HTML fragments instead of a block layouter.
    • Elements that can be inline or block-level can simply show themselves as the respective layouter instead of being forced to pick a layout trait. This is mostly relevant for equations at the moment, which don't need special-purpose handling anymore.
    • Elements can now also generate additional elements aside from a layouter in their show rules. For example, the show rule for tight lists can return attach spacing alongside its block layouter.
  • All block-like elements can now have block properties, which can be uniformly handled by the layout engine. For instance, a rect shows itself as a block and forwards its width and height to the block. This means that we can quite easily add support for height: 1fr on blocks, shapes, and images in a future PR. Previously, the opaque layout traits simply had no mechanism to communicate the fractional ratios between the flow and its children.

  • This change brings the internals closer to the way Typst already works for users: A show rule that returns layout(size => ..) is the user-space equivalent to the new block layouter model. In the future, we could consider moving this functionality from a special layout function directly to block. (In this PR, layout simply defers to block internally.)

A note on the implementation: We can't directly use normal capturing Rust closures for the callbacks because they cannot be hashed, which is a requirement for being a field of BlockElem. For this reason, src/layout/container.rs now contains a small manual implementation of closure types that capture Packed<T> for the relevant signatures.

@laurmaedje laurmaedje added this pull request to the merge queue Jun 3, 2024
Merged via the queue into main with commit 755dd41 Jun 3, 2024
12 checks passed
@laurmaedje laurmaedje deleted the show-as-block branch June 3, 2024 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant