Skip to content

Principe du mode de masquage : pourquoi le calcul de la largeur est si important

Ce que vous apprendrez

  • Comprendre le fonctionnement du mode de masquage OpenCode
  • Savoir pourquoi les outils de formatage ordinaires provoquent un désalignement en mode de masquage
  • Maîtriser l'algorithme de calcul de la largeur du plugin (trois étapes)
  • Comprendre le rôle de Bun.stringWidth

Votre problème actuel

Vous écrivez du code avec OpenCode, l'IA génère un joli tableau :

markdown
| 字段 | 类型 | 说明 |
|--- | --- | ---|
| **name** | string | 用户名 |
| age | number | 年龄 |

Dans la vue du code source, il semble bien aligné. Mais en passant en mode aperçu, le tableau est désaligné :

| 字段     | 类型   | 说明   |
|--- | --- | ---|
| name | string | 用户名 |    ← Pourquoi c'est plus court ?
| age      | number | 年龄   |

Où est le problème ? Le mode de masquage.

Qu'est-ce que le mode de masquage

OpenCode active par défaut le mode de masquage (Concealment Mode), qui masque les symboles de syntaxe Markdown lors du rendu :

Code sourceAffichage en mode de masquage
**粗体**粗体(4 个字符)
*斜体*斜体(4 个字符)
~~删除线~~删除线(6 个字符)
`代码`代码(4 个字符 + 背景色)

Avantages du mode de masquage

Permet de vous concentrer sur le contenu lui-même, sans être distrait par une multitude de symboles **, *.

Pourquoi les outils de formatage ordinaires ont-ils des problèmes

Les outils de formatage de tableaux ordinaires calculent la largeur en considérant **name** comme 8 caractères :

** n a m e ** = 8 caractères

Mais en mode de masquage, l'utilisateur voit name, seulement 4 caractères.

Le résultat est : l'outil de formatage aligne selon 8 caractères, l'utilisateur voit 4 caractères, le tableau est naturellement désaligné.

Idée principale : calculer la « largeur d'affichage » et non la « longueur des caractères »

L'idée principale de ce plugin est : calculer la largeur que l'utilisateur voit réellement, et non le nombre de caractères du code source.

L'algorithme se déroule en trois étapes :

Étape 1 : Protéger les blocs de code (les symboles dans les blocs de code ne sont pas supprimés)
Étape 2 : Supprimer les symboles Markdown (**, *, ~~, etc.)
Étape 3 : Utiliser Bun.stringWidth pour calculer la largeur finale

Suivez-moi : comprendre l'algorithme en trois étapes

Étape 1 : Protéger les blocs de code

Pourquoi

Les symboles Markdown dans le code en ligne (entre backticks) sont des « littéraux », l'utilisateur voit ces 8 caractères **bold**, et non les 4 caractères bold.

Donc avant de supprimer les symboles Markdown, il faut d'abord « cacher » le contenu des blocs de code.

Implémentation du code source

typescript
// Étape 1 : Extraire et protéger le code en ligne
const codeBlocks: string[] = []
let textWithPlaceholders = text.replace(/`(.+?)`/g, (match, content) => {
  codeBlocks.push(content)
  return `\x00CODE${codeBlocks.length - 1}\x00`
})

Fonctionnement

EntréeAprès traitementTableau codeBlocks
`**bold**`\x00CODE0\x00["**bold**"]
`a` and `b`\x00CODE0\x00 and \x00CODE1\x00["a", "b"]

En remplaçant les blocs de code par des espaces réservés spéciaux comme \x00CODE0\x00, ils ne seront pas affectés lors de la suppression des symboles Markdown.

Étape 2 : Supprimer les symboles Markdown

Pourquoi

En mode de masquage, **粗体** s'affiche comme 粗体, *斜体* s'affiche comme 斜体. Lors du calcul de la largeur, il faut supprimer ces symboles.

Implémentation du code source

typescript
// Étape 2 : Supprimer les symboles Markdown des parties non-code
let visualText = textWithPlaceholders
let previousText = ""

while (visualText !== previousText) {
  previousText = visualText
  visualText = visualText
    .replace(/\*\*\*(.+?)\*\*\*/g, "$1") // ***粗斜体*** → 文本
    .replace(/\*\*(.+?)\*\*/g, "$1")     // **粗体** → 粗体
    .replace(/\*(.+?)\*/g, "$1")         // *斜体* → 斜体
    .replace(/~~(.+?)~~/g, "$1")         // ~~删除线~~ → 删除线
    .replace(/!\[([^\]]*)\]\(([^)]+)\)/g, "$1")     // ![alt](url) → alt
    .replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)") // [text](url) → text (url)
}

Pourquoi utiliser une boucle while ?

Pour traiter la syntaxe imbriquée. Par exemple ***粗斜体*** :

Tour 1 : ***粗斜体*** → **粗斜体**(suppression de la couche externe ***)
Tour 2 : **粗斜体** → *粗斜体*(suppression de **)
Tour 3 : *粗斜体* → 粗斜体(suppression de *)
Tour 4 : 粗斜体 = 粗斜体(pas de changement, sortie de la boucle)
Traitement des images et des liens
  • Images ![alt](url) : OpenCode affiche uniquement le texte alt, donc remplacé par alt
  • Liens [text](url) : Affiché comme text (url), conserve les informations de l'URL

Étape 3 : Restaurer les blocs de code + calculer la largeur

Pourquoi

Le contenu des blocs de code doit être remis en place, puis utiliser Bun.stringWidth pour calculer la largeur d'affichage finale.

Implémentation du code source

typescript
// Étape 3 : Restaurer le contenu des blocs de code
visualText = visualText.replace(/\x00CODE(\d+)\x00/g, (match, index) => {
  return codeBlocks[parseInt(index)]
})

return Bun.stringWidth(visualText)

Pourquoi utiliser Bun.stringWidth ?

Bun.stringWidth peut calculer correctement :

Type de caractèreExempleNombre de caractèresLargeur d'affichage
ASCIIabc33
Chinois你好24(chaque caractère occupe 2 cases)
Emoji😀12(occupe 2 cases)
Caractère de largeur nullea\u200Bb32(les caractères de largeur nulle n'occupent pas d'espace)

Le text.length ordinaire ne peut que compter le nombre de caractères, incapable de traiter ces cas particuliers.

Exemple complet

Supposons que le contenu de la cellule est :**`code`** and *text*

Étape 1 : Protéger les blocs de code

Entrée : **`code`** and *text*
Sortie : **\x00CODE0\x00** and *text*
codeBlocks = ["code"]

Étape 2 : Supprimer les symboles Markdown

Tour 1 : **\x00CODE0\x00** and *text* → \x00CODE0\x00 and text
Tour 2 : Pas de changement, sortie

Étape 3 : Restaurer les blocs de code + calculer la largeur

Après restauration : code and text
Largeur : Bun.stringWidth("code and text") = 13

Finalement, le plugin aligne cette cellule selon une largeur de 13 caractères, et non les 22 caractères du code source.

Point de contrôle

Après avoir terminé cette leçon, vous devriez pouvoir répondre :

  • [ ] Quels symboles sont masqués par le mode de masquage ? (Réponse : Symboles de syntaxe Markdown comme **, *, ~~, etc.)
  • [ ] Pourquoi faut-il d'abord protéger les blocs de code ? (Réponse : Les symboles dans les blocs de code sont des littéraux et ne doivent pas être supprimés)
  • [ ] Pourquoi utiliser une boucle while pour supprimer les symboles ? (Réponse : Pour traiter la syntaxe imbriquée, comme ***粗斜体***)
  • [ ] En quoi Bun.stringWidth est-il meilleur que text.length ? (Réponse : Peut calculer correctement la largeur d'affichage des caractères chinois, emoji, caractères de largeur nulle)

Attention aux pièges

Malentendus courants

Malentendu : Les ** dans les blocs de code seront également supprimés

Réalité : Non. Le protège d'abord le contenu des blocs de code avec des espaces réservés, puis restaure le contenu après avoir supprimé les symboles des autres parties.

Donc la largeur de `**bold**` est 8(**bold**), et non 4(bold)。

Résumé de la leçon

ÉtapeRôleCode clé
Protéger les blocs de codeEmpêcher la suppression accidentelle des symboles dans les blocs de codetext.replace(/\(.+?)`/g, ...)`
Supprimer MarkdownCalculer le contenu d'affichage réel en mode de masquageRemplacements regex multi-tours
Calculer la largeurTraiter les caractères spéciaux comme le chinois, les emojiBun.stringWidth()

Prochain cours

Dans le prochain cours, nous apprendrons Spécifications des tableaux

Vous apprendrez :

  • Quels types de tableaux peuvent être formatés
  • Les 4 règles de validation des tableaux
  • Comment éviter les erreurs de « tableau invalide »

Annexe : Référence du code source

Cliquez pour développer les emplacements du code source

Date de mise à jour : 2026-01-26

FonctionnalitéChemin du fichierNuméros de ligne
Point d'entrée du calcul de la largeur d'affichageindex.ts151-159
Protection des blocs de codeindex.ts168-173
Suppression des symboles Markdownindex.ts175-188
Restauration des blocs de codeindex.ts190-193
Appel de Bun.stringWidthindex.ts195

Fonctions clés :

  • calculateDisplayWidth() : Point d'entrée du calcul de la largeur avec cache
  • getStringWidth() : Algorithme principal, supprime les symboles Markdown et calcule la largeur d'affichage

Constantes clés :

  • \x00CODE{n}\x00 : Format de l'espace réservé pour les blocs de code