[v4.1.1] Font commands not respected when using Unicode characters
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.9k
- Forks
- 1.2k
- PR merge metrics
- No merged PRs in 30d
Description
LLM Use Disclaimer
The bug was discovered after using Github Copilot through VSCode to replace Obsidian's v3 MathJax instance with v4. The following summary was written by Copilot as well.
Issue Summary
Font-switching commands (\symup, \mathrm, \mathup, etc.) fail to apply the correct mathvariant to Greek letters in two related scenarios:
-
lcGreekhandler ignoresenv.fontentirely —\symup{\alpha},\mathrm{\alpha}, etc. never produce upright lowercase Greek, regardless ofmathStyle. The handler unconditionally appliesmathStyle()without checking whether a font command has setenv.font. This affects allmathStyleconfigurations. -
hlUnicode handler overwritesenv.fontwithmathStyle— When a literal Unicode Greek character is used inside a font command (e.g.\symup{Π}), the Unicode fallback handler computes themathStylevariant afterenv.fonthas been set and overwrites themathvariantattribute. For uppercase Greek, this manifests only withmathStyle: 'ISO'(the only style where uppercase Greek is italic). For lowercase Greek, it compounds with bug 1.
The ucGreek handler (used by TeX commands like \Pi) is the only handler that correctly prioritises env.font over mathStyle. The variable handler (used by Latin letters) also works correctly.
Steps to Reproduce
- Configure MathJax with
tex: { mathStyle: 'ISO' } - Render the following expressions and compare output glyphs:
| Input | Expected | Actual | Handler |
|---|---|---|---|
\symup{\Pi} |
Upright Π (U+03A0) | ✓ Upright (U+03A0) | ucGreek |
\symup{Π} (Unicode) |
Upright Π (U+03A0) | ✗ Italic 𝛱 (U+1D6F1) | hl — bug 2 |
\mathrm{Π} (Unicode) |
Upright Π (U+03A0) | ✗ Italic 𝛱 (U+1D6F1) | hl — bug 2 |
\symup{\alpha} |
Upright α (U+03B1) | ✗ Italic 𝛼 (U+1D6FC) | lcGreek — bug 1 |
\mathrm{\alpha} |
Upright α (U+03B1) | ✗ Italic 𝛼 (U+1D6FC) | lcGreek — bug 1 |
\symup{α} (Unicode) |
Upright α (U+03B1) | ✗ Italic 𝛼 (U+1D6FC) | hl — bugs 1+2 |
\symup{x} |
Upright x (U+0078) | ✓ Upright (U+0078) | variable |
\symup{X} |
Upright X (U+0058) | ✓ Upright (U+0058) | variable |
Bug 1 (lcGreek) reproduces with all mathStyle values. Bug 2 (hl) reproduces with mathStyle: 'ISO' for uppercase Greek; for lowercase Greek and Latin, the effect depends on whether mathStyle returns a non-NORMAL variant.
Root Cause
Bug 1 — lcGreek ignores env.font:
// lcGreek — never checks env.font
lcGreek(t, e) {
const s = { mathvariant: t.configuration.mathStyle(e.char) || ITALIC };
// ...
}
// Compare ucGreek — correctly checks env.font first
ucGreek(t, e) {
const s = { mathvariant: t.stack.env.font || t.configuration.mathStyle(e.char, true) || NORMAL };
// ...
}
Fix: lcGreek should check t.stack.env.font before falling back to mathStyle, matching ucGreek.
Bug 2 — hl (Unicode fallback handler) overwrites env.font:
function hl(t, e) {
const s = t.stack.env.font; // e.g. "normal" from \symup
const i = s ? { mathvariant: s } : {}; // correctly sets mathvariant="normal"
const c = t.create("token", a, i, ...); // token created with "normal"
const l = isLatinOrGreekChar(e)
? t.configuration.mathStyle(e, true) || r
: ""; // l = "italic" (ISO uppercase Greek)
const h = o[4] || (s && l === NORMAL ? "" : l); // h = "italic" (since l ≠ NORMAL)
h && c.attributes.set("mathvariant", h); // OVERWRITES "normal" → "italic"
}
Fix: hl should skip the mathStyle override when env.font is already set.
Technical Details
- MathJax Version: 4.1.1
- Client OS: Windows 11
- Browser: Electron (Chromium-based, Obsidian desktop app)
I am using the following MathJax configuration:
MathJax = {
tex: {
packages: ['base', 'ams', 'newcommand', 'configmacros', 'noundefined', 'textmacros'],
mathStyle: 'ISO',
},
startup: {
typeset: false,
},
};
and loading a custom-built tex-chtml component (all TeX extensions pre-bundled via components/bin/makeAll).
Supporting Information
Verification via tex2chtml() in the console:
// Bug 1: lcGreek ignores env.font — all mathStyle values
MathJax.tex2chtml('\\symup{\\alpha}').querySelector('mjx-c').className
// → "mjx-c1D6FC" (U+1D6FC = italic 𝛼) ✗ expected "mjx-c3B1" (U+03B1 = upright α)
// Bug 2: hl overwrites env.font — mathStyle: 'ISO' only (for uppercase Greek)
MathJax.tex2chtml('\\symup{Π}').querySelector('mjx-c').className
// → "mjx-c1D6F1" (U+1D6F1 = italic 𝛱) ✗ expected "mjx-c3A0" (U+03A0 = upright Π)
// Working: ucGreek handler correctly respects env.font
MathJax.tex2chtml('\\symup{\\Pi}').querySelector('mjx-c').className
// → "mjx-c3A0" (U+03A0 = upright Π) ✓
// Working: variable handler correctly respects env.font (Latin)
MathJax.tex2chtml('\\symup{x}').querySelector('mjx-c').className
// → "mjx-c78" (U+0078 = upright x) ✓
Contributor guide
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 by reading the lcGreek and hl handlers, then compare their env.font handling with ucGreek and variable. Reproduce the examples with tex2chtml using mathStyle: 'ISO', and verify that font commands preserve the expected mathvariant for TeX and literal Greek characters.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100