ManimCommunity / ManimCommunity/ManimPango
disable_liga doesn't disable 'calt', so fonts like Fira Code still apply ligatures
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 62
- Forks
- 22
- PR merge metrics
- No merged PRs in 30d
Description
## Description of bug / unexpected behavior
`disable_liga` (passed through from `manim.Text(..., disable_ligatures=True)`) sets the Pango font feature string `'liga=0,dlig=0,clig=0,hlig=0'` in `manimpango/cmanimpango.pyx` (both `text2svg` and `text2pango`), but this doesn't cover every OpenType feature fonts can use to implement ligatures.
Popular monospaced/programming fonts — Fira Code being the most common example — implement their programming ligatures (`<=`, `->`, `!=`, etc.) exclusively through the `calt` (contextual alternates) feature, *not* through `liga`/`dlig`/`clig`/`hlig`. I confirmed this by inspecting Fira Code's own `GSUB` table with `fontTools`:
```py
from fontTools.ttLib import TTFont
font = TTFont("FiraCode-Regular.ttf")
tags = {fr.FeatureTag for fr in font["GSUB"].table.FeatureList.FeatureRecord}
print(sorted(tags))
# ['aalt', 'calt', 'case', 'ccmp', 'cv01', ..., 'locl', ...]
# note: no 'liga', 'dlig', 'clig', or 'hlig' at all
```
So when a `manim.Text`/`Code` mobject is rendered with such a font and `disable_ligatures=True`, Pango still merges e.g. `<` and `=` into a single glyph via `calt`, silently breaking the "one glyph per character" guarantee that `disable_ligatures` is supposed to provide. On the `manim` side, this manifests as a confusing `IndexError` in `Text._gen_chars()` (see [ManimCommunity/manim#3237](https://github.com/ManimCommunity/manim/issues/3237), where several users hit this with Fira Code without understanding why, and [ManimCommunity/manim#4868](https://github.com/ManimCommunity/manim/pull/4868), where I improved that error message but couldn't fix the actual root cause since it lives here).
## Expected behavior
`disable_liga` should also disable `calt`, so that character-for-glyph guarantees hold for fonts (like Fira Code) that implement their ligatures through that feature.
## How to reproduce the issue
```py
from manim import Code
Code(
code_string="print(1<=2)",
language="python",
paragraph_config={"font": "Fira Code"},
)
```
(Requires Fira Code, or another `calt`-ligature font, to be installed.)
## Suggested fix
In `manimpango/cmanimpango.pyx`, both occurrences of:
```py
font_features='liga=0,dlig=0,clig=0,hlig=0'
```
would need to become:
```py
font_features='liga=0,dlig=0,clig=0,hlig=0,calt=0'
```
I haven't built/tested this myself (would need to set up the Cython/C build), so I'm filing this as a diagnosis rather than a PR — happy to see if it holds up if someone with the build environment ready wants to verify it, or I may come back to it later with the toolchain set up.
## System specifications
System Details
- OS: macOS 26.5.1
- Font tested: Fira Code (Homebrew cask `font-fira-code`, version 6.2)
- Manim version: 0.20.1
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in manimpango/cmanimpango.pyx and inspect the two font_features strings used by text2svg and text2pango. Build the Cython/C extension and reproduce the Fira Code example, then verify that disable_liga prevents calt-based ligatures and preserves the one-glyph-per-character behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100