Skip to content

fix(ui): show every character of monospace text, no font ligatures - #386

Merged
thierryvm merged 1 commit into
mainfrom
fix/monospace-no-ligatures
Sep 23, 2026
Merged

thierryvm merged 1 commit into
mainfrom
fix/monospace-no-ligatures

Conversation

@thierryvm

@thierryvm thierryvm commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Why

Reported by @thierryvm (24 September 2026) and reproduced in Chrome/Windows: typing git merge --no-ff, one of the two dashes "disappeared" as soon as the space was typed and reappeared after Enter, so the learner pasted the command to finish the exercise.

Root cause (evidence, not a guess): the characters were never altered — recorded keydown/beforeinput/input events show the field holding "-- " (U+002D U+002D U+0020). The font, JetBrains Mono, ships programming ligatures (contextual alternates) and draws -- as one continuous line. In a terminal course that hides the very characters being taught (--, ->, !=…).

What

src/styles/theme.css (@layer base): font-variant-ligatures: none; font-feature-settings: "liga" 0, "calt" 0; on .font-mono, code, kbd, samp, pre — inherited, so it covers the terminal output and input, the landing terminal demo, lesson code blocks and inline code chips.

Known limit — disclosed, tracked

WebKit (Safari macOS / iOS) is documented as unable to turn off contextual alternates from CSS. Verified in Chrome only. THI-354 tracks a real-iPhone check and, if needed, the robust fix: serve the official ligature-free JetBrains Mono NL (official JetBrains release, checksum verified, OFL) — no new npm package.

Gates

  • Guard test src/test/monospaceLigatures.test.ts — red without the rule, green with it (jsdom does not apply CSS, so it guards the rule itself)
  • Chrome (dev server): computed font-variant-ligatures: none on terminal input, output and lesson <code>; git merge --no-ff now shows two distinct dashes while typing
  • type-check ✅ lint ✅ vitest 2528 pass / 9 expected-fail (THI-353 ratchet) ✅ build ✅
  • Transparency: the first full run reported 3 failures that did not reproduce in 3 consecutive full runs; that run overlapped with an audit agent running vitest on the same files
  • ui-auditor: PASS (every monospace surface covered, no decorative text relies on ligatures)
  • feature-dev:code-reviewer: CSS correct; FIX FIRST only on disclosure of the Safari limit → done (code comment + this section + THI-354)

Refs THI-353, THI-354

🤖 Generated with Claude Code

Résumé par Sourcery

Garantir que les caractères monospace restent visuellement distincts dans toute l’interface en désactivant les ligatures de police et les variantes contextuelles.

Corrections de bugs :

  • Désactiver les ligatures de programmation et les variantes contextuelles dans tous les textes monospace afin que les commandes de terminal et le code affichent chaque caractère distinctement lors de la saisie et de la lecture.

Tests :

  • Ajouter une protection contre les régressions pour vérifier que le CSS désactivant les ligatures monospace reste configuré pour tous les éléments monospace pris en charge.
Original summary in English

Summary by Sourcery

Ensure monospace characters remain visually distinct throughout the interface by disabling font ligatures and contextual alternates.

Bug Fixes:

  • Disable programming ligatures and contextual alternates across monospace text so terminal commands and code display every character distinctly while typing and reading.

Tests:

  • Add a regression guard ensuring the monospace ligature-disabling CSS remains configured for all supported monospace elements.

JetBrains Mono ships programming ligatures (contextual alternates). It drew
`--` as one continuous line: a learner typing `git merge --no-ff` saw one of
the two dashes disappear as soon as the space was typed, and it reappeared
after Enter. They had to paste the command to finish the exercise (reported
by @thierryvm, 24 September 2026, reproduced in Chrome).

The characters were never altered: the input held "-- " (recorded
keydown/beforeinput/input events). Only the rendering merged them.

Ligatures are now disabled for .font-mono, code, kbd, samp and pre. The
property is inherited, so it covers the terminal output, its input, the
landing terminal demo, lesson code blocks and inline code chips. A static
test guards the rule (jsdom does not apply stylesheets); the visual effect
was checked in Chrome.

Known limit: WebKit (Safari macOS / iOS) is documented as unable to turn
off contextual alternates from CSS. Not verified on a real Apple device
yet; the ligature-free font fallback is tracked in THI-354.

Refs THI-353, THI-354

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@vercel

vercel Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
terminal-learning Ready Ready Preview Sep 23, 2026 10:34pm UTC

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @thierryvm, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 2 days and 17 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 23, 2026

Copy link
Copy Markdown

Guide du réviseur

La PR corrige les caractères fusionnés visuellement dans le texte monospace de l’interface en désactivant les ligatures et les variantes contextuelles de JetBrains Mono sur les surfaces du terminal et du code, avec une vérification Vitest au niveau du code source et une documentation explicite de la limitation non résolue concernant Safari/WebKit.

Diagramme de séquence pour le rendu des commandes en monospace

sequenceDiagram
    actor Learner
    participant Input as Terminal input
    participant CSS as Monospace CSS
    participant Browser as Chrome renderer

    Learner->>Input: Type git merge --no-ff
    Input->>CSS: Inherit ligature settings
    CSS->>Browser: Disable liga and calt
    Browser-->>Input: Render both dashes distinctly
    Input-->>Learner: Show exact command characters
Loading

Diagramme de flux pour empêcher les ligatures en monospace

flowchart LR
    Content[Monospace content] --> Surfaces[font-mono, code, kbd, samp, pre]
    Surfaces --> CSS[font-variant-ligatures: none<br/>font-feature-settings: liga 0, calt 0]
    CSS --> Rendering[Distinct character rendering]
    Rendering --> Learner[Learner sees and types every character]
Loading

Diagramme de flux pour la protection contre les ligatures et la limitation de Safari

flowchart LR
    Rule[Monospace ligature rule] --> Guard[monospaceLigatures.test.ts]
    Guard --> Pass[Source rule verified]
    Rule --> Chrome[Chrome: ligatures disabled]
    Rule --> Safari[WebKit: contextual alternates may remain]
    Safari --> Followup[JetBrains Mono NL tracked by THI-354]
Loading

Modifications au niveau des fichiers

Modification Détails Fichiers
Désactive les ligatures typographiques dans toutes les surfaces de texte monospace afin que les caractères individuels des commandes restent visuellement distincts.
  • Ajoute des paramètres CSS hérités qui désactivent les ligatures standard et les variantes contextuelles.
  • Limite la règle au texte monospace utilitaire et aux éléments de code sémantiques, couvrant les entrées/sorties du terminal ainsi que le contenu de code des leçons.
  • Documente la limitation de Safari/WebKit et suit une solution de repli vers JetBrains Mono NL.
src/styles/theme.css
Ajoute une protection contre les régressions qui vérifie que la police monospace et les déclarations de désactivation des ligatures restent présentes.
  • Lit directement la feuille de style du thème, car jsdom ne calcule pas le CSS.
  • Vérifie le sélecteur cible ainsi que les deux contrôles de ligature concernés.
  • Confirme que JetBrains Mono reste la police à l’origine de cette solution de contournement.
src/test/monospaceLigatures.test.ts

Conseils et commandes

Interagir avec Sourcery

  • Déclencher une nouvelle revue : commentez @sourcery-ai review sur la pull request.
  • Poursuivre les discussions : répondez directement aux commentaires de revue de Sourcery.
  • Générer une issue GitHub à partir d’un commentaire de revue : demandez à Sourcery de créer une issue à partir d’un commentaire de revue en y répondant. Vous pouvez également répondre à un commentaire de revue avec @sourcery-ai issue pour créer une issue à partir de celui-ci.
  • Générer un titre de pull request : écrivez @sourcery-ai n’importe où dans le titre de la pull request pour générer un titre à tout moment. Vous pouvez également commenter @sourcery-ai title sur la pull request pour générer ou régénérer le titre à tout moment.
  • Générer un résumé de pull request : écrivez @sourcery-ai summary n’importe où dans le corps de la pull request pour générer un résumé de PR exactement à l’endroit souhaité, à tout moment. Vous pouvez également commenter @sourcery-ai summary sur la pull request pour générer ou régénérer le résumé à tout moment.
  • Générer le guide du réviseur : commentez @sourcery-ai guide sur la pull request pour générer ou régénérer le guide du réviseur à tout moment.
  • Résoudre tous les commentaires de Sourcery : commentez @sourcery-ai resolve sur la pull request pour résoudre tous les commentaires de Sourcery. Cette commande est utile si vous avez déjà traité tous les commentaires et ne souhaitez plus les voir.
  • Ignorer toutes les revues de Sourcery : commentez @sourcery-ai dismiss sur la pull request pour ignorer toutes les revues de Sourcery existantes. Cette commande est particulièrement utile si vous souhaitez recommencer une revue à zéro : n’oubliez pas de commenter @sourcery-ai review pour déclencher une nouvelle revue !

Personnaliser votre expérience

Accédez à votre tableau de bord pour :

  • Activer ou désactiver des fonctionnalités de revue telles que le résumé de pull request généré par Sourcery, le guide du réviseur, etc.
  • Modifier la langue de la revue.
  • Ajouter, supprimer ou modifier les instructions de revue personnalisées.
  • Ajuster les autres paramètres de revue.

Obtenir de l’aide

Original review guide in English

Reviewer's Guide

The PR fixes visually merged characters in monospace UI text by disabling JetBrains Mono ligatures and contextual alternates across terminal and code surfaces, with a source-level Vitest guard and explicit documentation of the unresolved Safari/WebKit limitation.

Sequence diagram for monospace command rendering

sequenceDiagram
    actor Learner
    participant Input as Terminal input
    participant CSS as Monospace CSS
    participant Browser as Chrome renderer

    Learner->>Input: Type git merge --no-ff
    Input->>CSS: Inherit ligature settings
    CSS->>Browser: Disable liga and calt
    Browser-->>Input: Render both dashes distinctly
    Input-->>Learner: Show exact command characters
Loading

Flow diagram for monospace ligature prevention

flowchart LR
    Content[Monospace content] --> Surfaces[font-mono, code, kbd, samp, pre]
    Surfaces --> CSS[font-variant-ligatures: none<br/>font-feature-settings: liga 0, calt 0]
    CSS --> Rendering[Distinct character rendering]
    Rendering --> Learner[Learner sees and types every character]
Loading

Flow diagram for ligature guard and Safari limitation

flowchart LR
    Rule[Monospace ligature rule] --> Guard[monospaceLigatures.test.ts]
    Guard --> Pass[Source rule verified]
    Rule --> Chrome[Chrome: ligatures disabled]
    Rule --> Safari[WebKit: contextual alternates may remain]
    Safari --> Followup[JetBrains Mono NL tracked by THI-354]
Loading

File-Level Changes

Change Details Files
Disables programming ligatures across all monospace text surfaces so individual command characters remain visually distinct.
  • Adds inherited CSS settings disabling standard ligatures and contextual alternates.
  • Scopes the rule to utility monospace text and semantic code elements, covering terminal input/output and lesson code content.
  • Documents the Safari/WebKit limitation and tracks a fallback to JetBrains Mono NL.
src/styles/theme.css
Adds a regression guard that verifies the monospace font and ligature-disabling declarations remain present.
  • Reads the theme stylesheet directly because jsdom does not compute CSS.
  • Checks the target selector and both relevant ligature controls.
  • Confirms JetBrains Mono remains the font motivating the workaround.
src/test/monospaceLigatures.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@thierryvm
thierryvm merged commit d430b1c into main Sep 23, 2026
4 checks passed
@thierryvm
thierryvm deleted the fix/monospace-no-ligatures branch September 23, 2026 22:36

This branch was successfully deployed

1 active deployment
Preview — 37b51ec0 Deployed Sep 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant