Skip to content

Allow a function as an argument to various size parameters in math elements and add a delim-size parameter to mat, vec, and cases#6214

Closed
mkorje wants to merge 3 commits intotypst:mainfrom
mkorje:custom-delim-size
Closed

Allow a function as an argument to various size parameters in math elements and add a delim-size parameter to mat, vec, and cases#6214
mkorje wants to merge 3 commits intotypst:mainfrom
mkorje:custom-delim-size

Conversation

@mkorje
Copy link
Collaborator

@mkorje mkorje commented Apr 27, 2025

Closes #4181.

The commits are fairly detailed and broken into small parts explaining what's changed.

TLDR: The main change is the addition of the enum StretchSize which can take a relative length or a function that receives the absolute size of the base thing and should return a relative length. This is used throughout the element functions in math now.

Addressing #4181 specifically, it's difficult to exactly replicate TeX* as the way matrices (which are just wrappers over the array environment) are laid out is quite different to how they are laid out in Typst. But the below seems fairly close and uses the same formula TeX* does for scaling delimiters (with a +2pt added to better match how in TeX the inner content is slightly larger than in Typst. Anyways with the changes to allow a function the user has much more flexibility to customise this to their liking (and I'm sure someone will figure out a near perfect function to match TeX...)

#set text(11pt)
#set math.mat(delim: "[")

$ mat(c; c; c; c) mat(f; f; f; f) $

#set math.mat(delim-size: x => {
  let x = x + 2pt
  calc.max(x - 5pt, x * 0.901) // this is the TeX formula exactly
})

$ mat(c; c; c; c) mat(f; f; f; f) $
LuaTeX Typst
tex playground

@mkorje mkorje mentioned this pull request May 27, 2025
@mkorje mkorje force-pushed the custom-delim-size branch from 5709092 to 14a1235 Compare June 4, 2025 03:40
@laurmaedje
Copy link
Member

The implementation looks very clean! What I'm not 100% certain on is what knobs we do and don't want to expose in math layout customization. There a lot of hard-coded layout algorithms, some hard-coded constants and various font-dependent values. Which do we want to make customizable?

Also, regarding the tests. I'm not quite sure why the reference images for matrix tests changed. Did you change the matrix formula to match TeX more closely? I can't see it in the code. But either way, it might be good to extract those changes into a separate PR.

@mkorje
Copy link
Collaborator Author

mkorje commented Jun 4, 2025

The implementation looks very clean! What I'm not 100% certain on is what knobs we do and don't want to expose in math layout customization. There a lot of hard-coded layout algorithms, some hard-coded constants and various font-dependent values. Which do we want to make customizable?

I think I'd generally lean towards not exposing font-dependent stuff (and the layouting of elements that come with it), but anything else that is reasonable enough to expose and could have use to a user could then be added. In this case, scaling of delimiters is quite subjective and not really hard-coded into any of the layout algorithms, so I think it makes sense to expose for mat/vec/cases.

Also, regarding the tests. I'm not quite sure why the reference images for matrix tests changed. Did you change the matrix formula to match TeX more closely? I can't see it in the code. But either way, it might be good to extract those changes into a separate PR.

The only change made was in the first commit. Basically, we previously had a hard coded short fall used when scaling delimiters for the various elements. But this short fall didn't apply to the glyph assembly, i.e. we only considered it when picking a prebuilt variant. Because I'm exposing the size for delimiters in this PR, adding another knob for "short fall" seemed like a bad idea. So I instead in the first commit subtracted the short fall from the target for the glyph assembly as well. This is the reason for all the slight test changes in mat, etc.

Otherwise, I have kept as default the same as we had before. For example, the default for mat/vec/cases is still 1.1 * X - 0.1em. The default is just now a function instead, since this calculation is no longer hard-coded. I also think this makes things clearer to the user, as no hidden hard-coded short fall or scaling is going on anymore throughout. (For example, if you did set math.accent(size: 2em) in 0.13.1 it wouldn't actually be 2em, but 2em - 0.5em.)

@laurmaedje
Copy link
Member

Would you mind extracting the first and last commit into a separate PR? I think this change is fairly unrelated to exposing more user-facing knobs and should be judged separately. I can't remember the details anymore about why short fall works the way it works, but I see how it might make more sense to apply it consistently to variants and constructions and how that makes the extra parameter on the stretching functions obsolete.

@mkorje
Copy link
Collaborator Author

mkorje commented Jun 4, 2025

Sure I've opened #6377. I'll clean up this one very soon.

@mkorje mkorje force-pushed the custom-delim-size branch from 14a1235 to fd518ec Compare June 4, 2025 10:29
@mkorje
Copy link
Collaborator Author

mkorje commented Jun 4, 2025

The updated tests are due to relative lengths like 2em now no longer having the short fall applied (only the defaults do, as it has it in the function definition).

Comment on lines +10 to +23
#[func(name = "x => x - 0.5em")]
const fn default_accent_size(base: Length) -> Rel {
Rel {
rel: Ratio::zero(),
abs: Length { abs: base.abs, em: ACCENT_SHORT_FALL },
}
}
Copy link
Collaborator Author

@mkorje mkorje Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this too hacky? 😅
I generated the json docs and the default does show up as x => x - 0.5em. Not sure how it'll look on the actual docs though.
Also, I can't remember now whether these need to be const?

@laurmaedje laurmaedje added math Related to math syntax, layout, etc. interface PRs that add to or change Typst's user-facing interface as opposed to internals or docs changes. layout Related to layout, positioning, etc. labels Jun 4, 2025
@mkorje mkorje force-pushed the custom-delim-size branch from fd518ec to 189e2f4 Compare June 10, 2025 03:10
@mkorje mkorje force-pushed the custom-delim-size branch 5 times, most recently from 3a2df74 to 33ae930 Compare June 30, 2025 12:14
@mkorje mkorje force-pushed the custom-delim-size branch 2 times, most recently from 0e58966 to 333dfd5 Compare July 8, 2025 11:05
mkorje added 3 commits July 23, 2025 17:50
Previously there was always a short fall when scaling delimiters, even if
the user requested a specific size. This is no longer the case; the short
fall is only present in the default for `lr` (`x => x - 0.1em`) - the
size of the delimiters is now actually what was specified in the size
argument. This also makes the default for `lr` much clearer to the user.

A slight hack was used by exploiting the `name` property in the `func`
attribute macro so that the default value in the docs for `lr.size` would
clearly show what the default function was (instead of just its name
`default_lr_size` which is meaningless and inaccessible to the user).
The short fall is now only applied in the default for `accent`
(`x => x - 0.5em`).
Takes either a function or a relative length, just like with `lr`,
`stretch`, and `accent` which was changed in the previous two commits.
The default is now much clearer to the user: `x => x * 1.1 - 0.1em`.
@mkorje mkorje force-pushed the custom-delim-size branch from 333dfd5 to 8c81111 Compare July 23, 2025 07:55
@laurmaedje
Copy link
Member

We've discussed this in the team and were overall not sure about it. Right now, math layout is driven by a mix of hard-coded logic, a few hard-coded constants, and a lot of font data. With this, it feels like it opens the door to customization of math layout from user code without a clear plan of where we want to go with this and what is in scope / not in scope for customization in the math layout engine.

@laurmaedje
Copy link
Member

I'll close this for now — we can all always revisit it later. Thank you regardless!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

interface PRs that add to or change Typst's user-facing interface as opposed to internals or docs changes. layout Related to layout, positioning, etc. math Related to math syntax, layout, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow matrix delimiter to be smaller than content like latex/plaintex does

2 participants