typst / typst/codex

Improve forward compatibility with a notion of minimal modifier set

Open
#51 8 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

meta proposal
Dominant language
Rust
Stars
53
Forks
22
PR merge metrics
No merged PRs in 30d

Description

Motivation

Currently, when selecting a variant from a set of modifiers, the first variant from the list that contains all the modifiers, and a minimal amount of additional modifiers, is chosen.[^1][^2] This means using non-fully qualified names when referring to a symbol might cause breakage when Codex is updated. For example, consider the following symbol:

arrow
  .l ←
  .r →
  .r.bar ↦

arrow.bar resolves to arrow.r.bar, which is ↦. Now, suppose a new version of Codex changes the symbol to the following:

arrow
  .l ←
  .l.bar ↤
  .r →
  .r.bar ↦

Now, arrow.bar will resolve to arrow.l.bar, which is ↤.

Essentially, this means adding new variants in the middle of the variant list can cause unexpected breakage. As of now, there is no policy regarding what constitute a breaking change when it comes to fallbacks.

[^1]: This is actually not defined in Codex, but in Typst. Making the variant selection part of Codex is the topic of #30.
[^2]: https://github.com/typst/typst/blob/d199546f9fe92b2d380dc337298fdca3e6fca8c8/crates/typst-library/src/foundations/symbol.rs#L387-L420

Proposed solution

The intuitive idea of this solution is to make explicit what parts of the fully qualified form (i.e., which modifiers) can be omitted.

As before, each variant has a set of modifiers. Hereafter, we refer to this set of modifiers as the fully qualified form, denoted $M_\text{full}$. Additionally, a variant can define a minimal modifier set, denoted $M_\text{min}$, which is a subset of the fully qualified form (i.e., $M_\text{min} \subseteq M_\text{full}$). When selecting a variant for a set of modifiers $M$, the same process as before is applied, with the additional constraint that the selected variant's minimal modifier set is included in $M$ (i.e., $M_\text{min} \subseteq M$).

The current behavior corresponds to having $M_\text{min} = \emptyset$ for all variants. With this proposal, the default would become $M_\text{min} = M_\text{full}$, with lots of manual overrides to allow for backward compatibility and more leniency.

This improves forward-compatibility by explicitly specifying which fallbacks can be relied on, and which can't. Ideally, there could even be an automated way of detecting breakages. This is currently not feasible, because most breakages are not implicitly guaranteed to be future proof.[^3]

[^3]: For example, sym.angle.top currently resolves to sym.angle.spheric.top (⦡), but this is more a side effect of the fact that there is no bare sym.angle.top symbol than a conscious decision, and shouldn't be relied upon.

Other benefits

As well as improving forward compatibility, this proposal can be the source of documentation improvements. Indeed, the current documentation^4 only presents fully qualified names. For some common symbols, this can be problematic. For example, sym.errorbar.square.stroked can be accessed through simply sym.errorbar, but the documentation does not reflect that. With this proposal, the documentation can present $M_\text{min}$ as the main symbol name and $M_\text{full}$ as the fully qualified name, when $M_\text{min} \neq M_\text{max}$.

As mentioned previously, this proposal would make it possible to detect breakages automatically, because it clarifies which non-fully qualified variants are legal and clearly defined, and which are not.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No Codex file or test is named. Start with the linked Typst symbol-selection implementation and Codex issue #30, then trace where variants and modifiers are represented and selected. Done means the minimal modifier-set proposal is specified, implemented, and covered by compatibility tests and documentation updates.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.