ManimCommunity / ManimCommunity/ManimPango

disable_liga doesn't disable 'calt', so fonts like Fira Code still apply ligatures

Open Beginner friendly
#127 0 comments 0 reactions 0 assignees View on GitHub

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

  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

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.