turbo-editors/turbo-moonbitpublic Fork 0
v1.0.3
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-moonbit.git
git clone ssh://git@rickub.com/turbo-editors/turbo-moonbit.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

📦 Turbo MoonBit cc1f595 · on v1.0.3 · k33g · 23h ago
languages.md · 296 lines · 21.6 KBmarkdown
Blame HistoryOpen raw

Référence : langages colorés

Description neutre des fichiers que Turbo MoonBit colore, de la façon dont il décide, et de ce que reconnaît chaque scanner.

Reconnaissance

L'extension d'un fichier décide dès qu'elle fait partie de celles-ci :

Extension Langage
.mbt, .mbti, .mbtx MoonBit
.toml TOML
.yaml, .yml YAML
.md, .markdown Markdown
.js, .mjs, .cjs JavaScript
.html, .htm HTML
.xml, .xsd, .xsl, .xslt, .svg, .plist, .csproj, .pom XML
.sh, .bash, .zsh Shell
.dockerfile, .containerfile Dockerfile

Les extensions sont comparées sans tenir compte de la casse, et seule la dernière compte : README.mbt.md est du Markdown, et main.mbt.backup n'est pas du MoonBit.

Un fichier dont l'extension ne décide de rien est ensuite cherché par son nom. Seuls les fichiers dépourvus d'extension utile en ont besoin :

Nom Langage
Dockerfile, Containerfile Dockerfile

Un nom correspond soit en entier, soit sur la partie qui précède le premier point, sans tenir compte de la casse — Dockerfile, dockerfile et Dockerfile.dev sont donc tous reconnus, tandis que Dockerfile.md est du Markdown, puisque l'extension est consultée d'abord.

moon.mod, moon.pkg et moon.work ne sont pas dans cette table. Ce sont les fichiers du DSL de configuration de MoonBit plutôt que du MoonBit, et leurs anciennes formes JSON — moon.mod.json, moon.pkg.json — ne sont pas non plus du JSON que cet éditeur colore. Les cinq s'ouvrent en texte brut.

Un fichier qu'aucune des deux tables ne réclame est lu par sa première ligne. Un shebang nommant un shell — sh, bash, zsh, dash ou ksh — en fait un script shell, et l'interpréteur est reconnu comme élément de chemin ou comme argument de env. C'est ce qui colore un script dans un répertoire bin, un hook git ou un configure.

Aucun shebang ne fait d'un fichier du MoonBit. Le langage n'a pas de ligne d'interpréteur : un fichier commençant par #! serait lu comme un attribut nommé ! et échouerait. Un fichier sans extension n'est pas du MoonBit, et prétendre le contraire retirerait un script shell au scanner qui sait réellement le colorer.

Première ligne Résultat
#!/bin/sh Shell
#!/usr/bin/env bash Shell
#!/usr/bin/env -S bash -e Shell
#!/usr/bin/env moon Non coloré
#!/usr/bin/env node Non coloré
Tout ce qui ne commence pas par #! Non coloré

L'ordre est fixe — extension, puis nom, puis première ligne — et le premier qui décide l'emporte.

Tout le reste est affiché en texte brut. Ce n'est pas une erreur : ouvrir un PNG dans l'éditeur n'est pas une faute, ce n'est simplement pas coloré.

Classes

Chaque scanner produit le même vocabulaire de classes, et chacune correspond à une clé de thème.

Classe Clé de thème Produite par
identifier syntax.identifier MoonBit, TOML, JavaScript, shell, YAML, Dockerfile
keyword syntax.keyword MoonBit, JavaScript, shell, HTML (doctype), XML, Dockerfile
type syntax.type MoonBit (tout nom capitalisé, et les qualificateurs de paquet), TOML (en-têtes de table), YAML (tags)
builtin syntax.builtin MoonBit (le prélude), JavaScript, shell (primitives et expansions), YAML (ancres et alias), Dockerfile (variables)
constant syntax.constant MoonBit, TOML, JavaScript, shell, YAML, HTML et XML (entités)
function syntax.function MoonBit, JavaScript, shell (la commande)
string syntax.string tous
char syntax.char MoonBit ('c' et b'c')
number syntax.number MoonBit, TOML, JavaScript, shell, YAML, Dockerfile
comment syntax.comment MoonBit, TOML, JavaScript, shell, HTML, YAML, XML, Dockerfile
operator syntax.operator MoonBit, TOML, JavaScript, shell, HTML, YAML (en-têtes de scalaire de bloc), XML, Dockerfile
punctuation syntax.punctuation MoonBit, TOML, JavaScript, shell, Markdown, YAML, Dockerfile
heading syntax.heading Markdown
tag syntax.tag HTML, XML
attribute syntax.attribute MoonBit (attributs et arguments étiquetés), HTML, XML, Dockerfile (options)
emphasis syntax.emphasis Markdown
link syntax.link Markdown

Dans le seul thème turbo-classic, syntax.attribute et syntax.identifier sont tous deux en jaune simple : un attribut ou une étiquette MoonBit ne s'y distingue donc pas d'un nom ordinaire. Les sept autres thèmes leur donnent des couleurs différentes. Voir comment écrire son propre thème pour changer cela.

MoonBit

Écrit à la main, dans internal/moonbitlang. Rien ne franchit une fin de ligne, et c'est une propriété du langage plutôt qu'une simplification : MoonBit n'a pas de commentaire de bloc, un saut de ligne avant le guillemet fermant est une erreur de littéral non terminé, une chaîne multiligne est une suite de lignes #| ou $| complètes chacune en elle-même, et un attribut tient explicitement sur une ligne. Un guillemet égaré colore donc jusqu'à la fin de sa ligne, et la ligne suivante est de nouveau du code.

Reconnu Comme
and, as, async, break, catch, const, continue, declare, defer, derive, else, enum, enumview, extend, extenum, extern, fn, for, guard, if, impl, import, in, is, let, letrec, lexscan, loop, match, mut, nobreak, nocancel, noraise, package, priv, proof_assert, proof_let, pub, raise, readonly, return, struct, suberror, test, throw, trait, try, type, using, where, while, with mot-clé
try! et guard!, point d'exclamation compris mot-clé
true, false, None, Some, Ok, Err constante
tout nom commençant par une majuscule ASCII — Int, StringBuilder, Shape, Circle type
println, abort, panic, fail, ignore, inspect, debug, repr, hash, compare, null, assert_eq, assert_not_eq, assert_true, assert_false, debug_assert, debug_inspect, json_inspect, physical_equal primitive
tout autre nom en minuscules immédiatement suivi de ( fonction
"…", b"…", re"…" chaîne
'c', b'c' caractère
#| et $| le préfixe de deux caractères en ponctuation, le reste de la ligne en chaîne
42, 1_000, 0xFF_FF, 0o17, 0b1010, 1.5, 1., 1.5e-3, 0x1.8p3F, 42U, 42L, 42UL, 42N, 1.0F nombre
// et /// jusqu'à la fin de la ligne commentaire
#deprecated("…"), #external, #custom.attribute(key="v") — la ligne entière attribut
name~ dans un argument étiqueté, tilde compris attribut
@json, @moonbitlang/core/builtin, @my-pkg — le @ compris, en une seule étendue type
.0 dans un accès de tuple le point en ponctuation, les chiffres en nombre
.., ..=, ..<, ... opérateur
suites de +-*/%=<>!&|^~?: opérateur
()[]{},;. ponctuation

Il n'y a ici aucune table des types intégrés, et il n'en faut aucune. La casse des identifiants de MoonBit est une règle lexicale et non une convention : la grammaire dit qu'un uident « commence par une majuscule ASCII », et seuls un type, un trait ou un constructeur d'énumération peuvent s'écrire ainsi. Int, StringBuilder et un type écrit ce matin sont tous colorés par la même ligne de code. Tous les autres scanners de cette famille ont besoin d'une table ici ; celui-ci non.

Un entier se termine avant ... La grammaire est explicite — « avant .., l'entier se termine d'abord, donc 1..=2 commence par 1 puis ..= » — un point ne fait donc partie d'un nombre que si un second ne le suit pas. Sans cette règle, 1..=2 se lit comme le double 1. puis .=2, et tous les intervalles du fichier sont mal colorés.

Le suffixe d'un nombre est en majuscules ou ce n'est pas un suffixe. 42UL est un seul nombre ; 42u est le nombre 42 suivi du nom u, ce que voit aussi le compilateur.

Un attribut prend la ligne entière. La grammaire lui donne tout ce qui suit le nom pointé : « tout ce qui va jusqu'au saut de ligne suivant est la charge utile brute ». Colorer moins que la ligne inventerait une structure que le lexeur n'a pas.

#| et #deprecated se distinguent par le caractère qui suit le #. Le nom d'un attribut doit commencer par une lettre ou un tiret bas ; une ligne de chaîne multiligne a une barre verticale à cette place.

Un commentaire de documentation est coloré comme n'importe quel autre commentaire. ///, ///| et // aboutissent tous à syntax.comment, parce que l'ensemble des classes de turbo-core est délibérément fermé — c'est ce qui permet à un seul thème de colorer tous les langages qu'un éditeur apprendra jamais.

Un nom après un point n'est jamais un mot-clé. Les identifiants pointés de MoonBit « suivent les règles de casse des identifiants sans consulter la table des mots-clés, si bien que .if est valide » — un enregistrement avec un champ nommé type est du MoonBit ordinaire.

package est aussi coloré comme mot-clé dans un fichier .mbt, alors qu'il n'y est qu'un mot réservé. C'est un vrai mot-clé dans les fichiers d'interface .mbti que cet éditeur colore également, et dans un .mbt la couleur dit exactement ce que le compilateur s'apprête à dire : ce mot ne vous appartient pas. Le reste de la liste réservée — move, ref, static, unsafe, await et les quarante autres — est délibérément laissé tranquille, parce que ce sont réellement des noms utilisables.

Un tilde collé à la fin d'un nom en minuscules est une étiquette, et collé à autre chose il ne l'est pas : la grammaire dit que « les identifiants en majuscules ASCII et les mots-clés ne peuvent pas former d'étiquette », donc Foo~ est un type suivi d'un tilde.

Non reconnu, chaque cas pour une raison énoncée :

Non reconnu Parce que
L'expression à l'intérieur de \{…} La grammaire la fait aller jusqu'à « l'accolade correspondante », les accolades des littéraux imbriqués ne comptant pas : trouver la fin demande l'analyseur syntaxique. "a \{b} c" est donc une seule étendue de chaîne, d'accolade à accolade. C'est une chaîne imbriquée dans une interpolation qui arrête cela : le scanner prend le premier guillemet non échappé pour le fermant, si bien que "a \{f("x")} c" se lit comme chaîne, puis x en identifiant, puis chaîne. Les étendues restent ordonnées et ne se chevauchent jamais ; le coût est une couleur fausse à l'intérieur d'un littéral imbriqué, plus rare que les bugs de comptage d'accolades qu'entraînerait l'alternative
Un constructeur d'énumération à vous, autrement que comme un type Rien dans la syntaxe ne sépare Circle(1.0) d'un type appliqué à des arguments ; inventer une séparation reviendrait à se tromper dans les deux sens au lieu d'un
.5 comme nombre MoonBit exige un chiffre avant le point : un point initial est donc un accès de tuple ou un identifiant pointé, jamais un littéral
Un mot réservé comme mot-clé move, ref et les autres sont des identifiants dont le compilateur se contente d'avertir, et les colorer dirait au lecteur qu'il ne peut pas écrire let ref = 1 alors qu'il le peut
Un identifiant contenant des lettres non ASCII MoonBit accepte le CJK et plusieurs autres plages dans un nom ; les prédicats de caractères sur lesquels ce scanner est bâti sont ASCII, un tel nom est donc franchi sans couleur plutôt que deviné
.mbt.md comme du MoonBit C'est un document Markdown contenant du MoonBit dans ses blocs. Son extension est .md, et c'est Markdown qui le colore
Si un nom est lié dans cette portée Rien ici ne lit plus d'une ligne à la fois ; c'est la question du serveur de langage, et F1 y répond

TOML

Reconnu Comme
# commentaire comment
[table], [[array]] le nom en type, les crochets en punctuation
clé = identifier, puis operator
"basique", 'littérale', """multi-ligne""", '''multi-ligne''' string
true, false constant
nombres, dates, heures, inf, nan number

YAML

Un fichier compose, un manifeste Kubernetes et un workflow d'intégration continue sont tous cela : il n'y a pas de dialecte séparé, parce qu'un dialecte serait le schéma de quelqu'un d'autre à maintenir en phase.

Reconnu Comme
# commentaire commentaire
clé: suivie d'une espace ou de la fin de ligne la clé en identifiant, le deux-points en ponctuation
"entre guillemets": 1, 'apostrophes': 1 la clé citée en identifiant
- ouvrant une entrée de séquence ponctuation
"…", '…' chaîne
true, false, yes, no, on, off, null constante, quelle que soit la casse
nombres, dates et heures écrits sans guillemets nombre
&ancre, *alias builtin
!!str, !Custom type
---, ... toute la ligne en ponctuation
{, }, [, ], , ponctuation
|, >, avec leurs indicateurs de coupe et d'indentation l'en-tête en opérateur, le corps en chaîne

Un deux-points n'est un séparateur que si une espace ou la fin de ligne le suit. image: nginx:1.27 est une clé et une seule valeur, et url: http://example.com/x une clé et une seule URL — colorer les deux-points intérieurs en séparateurs mettrait chaque étiquette d'image et chaque URL en trois couleurs.

L'étendue d'un scalaire de bloc est décidée par l'indentation, pas par un délimiteur. La première ligne de contenu après | ou > fixe l'indentation du bloc ; toute ligne indentée au moins autant lui appartient, et la première qui ne l'est pas y met fin. Une ligne vide à l'intérieur d'un bloc y reste : un scalaire littéral conserve ses lignes vides, et terminer le bloc au premier saut de paragraphe couperait en deux un script shell dans un fichier d'intégration continue.

Un # a besoin d'une espace devant lui pour ouvrir un commentaire, si bien que colour: ff#00aa est un seul scalaire.

Non reconnu Parce que
Le schéma d'un fichier compose, d'un manifeste ou d'un workflow Colorer services: autrement qu'une clé quelconque revient à transporter le schéma de quelqu'un d'autre, qui se périme le jour où il ajoute une clé
Les flux multi-documents comme documents distincts --- est coloré, mais rien n'est réinitialisé à cet endroit ; rien dans la coloration ne dépend des frontières de documents
Si un mot nu est une chaîne ou un nombre pour un analyseur 1.2.3 est une version pour un lecteur et une chaîne pour YAML ; l'analyseur colore ce à quoi cela ressemble

Markdown

Reconnu Comme
# Titre###### Titre toute la ligne en heading
**gras**, __gras__, *italique*, _italique_ emphasis
`code` string
[texte](cible), ![alt](src) l'ensemble en link
- , * , + , 1. , 1) le marqueur en punctuation
> punctuation
---, ***, ___ punctuation
clôtures ``` et ~~~ tout le bloc, lignes d'ouverture et de fermeture comprises, en string

Un bloc clôturé est d'une seule couleur quel que soit le langage annoncé : ```moonbit ne colore pas son contenu en MoonBit. La suite de marqueurs qui ouvre un bloc doit être fermée par le même caractère : une clôture en accents graves ne se ferme pas par des tildes. Une clôture non fermée colore jusqu'à la fin du fichier.

La suite de marqueurs qui ouvre une emphase doit être fermée par une suite de même longueur, de sorte que **gras** fasse un seul span et non deux italiques.

JavaScript

Reconnu Comme
const, let, function, class, async, await, import, export, … keyword
true, false, null, undefined, NaN, Infinity, this constant
console, document, window, Array, Object, Promise, Math, JSON, … builtin
un nom immédiatement suivi de ( function
"…", '…' string
`…`, interpolations comprises, sur plusieurs lignes string
// jusqu'à la fin de la ligne, /* … */ sur plusieurs lignes comment
42, 3.14, 0x1f, 0b1010, 0o777, 1_000_000, 1e6, 10n number
suites de `+-*/%=<>!& ^~?:`
()[]{},;. punctuation

Les littéraux d'expression régulière ne sont pas reconnus. Distinguer /x/g d'une division exige de savoir si le token précédent pouvait terminer une expression ; une mauvaise supposition colore le reste de la ligne comme une chaîne, ce qui est pire que de laisser une regex à la couleur d'un opérateur.

Les globales sont reconnues par leur nom : un fichier qui masque Math la voit quand même colorée comme un builtin — la même règle que les types primitifs de MoonBit.

HTML

Reconnu Comme
<balise, </balise, >, /> tag
noms d'attributs, dont data-*, xlink:href, @click, v-bind.prop attribute
= operator
"…", '…' string
<!-- … -->, sur plusieurs lignes comment
&amp;, &#169; constant
<!DOCTYPE …> et les autres déclarations keyword

Le texte entre balises n'est pas coloré. Une esperluette isolée sans ; dans les 32 caractères qui suivent est laissée telle quelle, parce que c'est du texte légal.

Le contenu de <script> et de <style> n'est pas coloré en JavaScript ni en CSS.

XML

Son propre analyseur plutôt que celui du HTML, pour une raison qui compte : CDATA. Tout l'intérêt de <![CDATA[ … ]]> est que son contenu n'est pas du balisage, et colorer les balises qu'il contient comme des balises est exactement l'inverse.

Reconnu Comme
<?xml version="1.0"?> et les autres instructions de traitement la cible et ?> en mot-clé, les paires entre les deux en attributs et chaînes
<!DOCTYPE …> et les autres formes <! mot-clé
<!-- … -->, sur plusieurs lignes commentaire
<![CDATA[ … ]]>, sur plusieurs lignes chaîne
<balise, </balise, >, /> balise
<ns:balise>, xsi:type le préfixe et le nom local en un seul segment
les noms d'attributs attribut
= opérateur
"…", '…' chaîne
&amp;, &#169; constante

Un commentaire et une section CDATA se ferment sur des délimiteurs différents, et sont transportés séparément : un --> à l'intérieur d'une section CDATA n'y met pas fin.

Une esperluette isolée sans point-virgule dans les 32 caractères suivants est laissée telle quelle, parce que c'est du texte légal dans bien des documents et qu'avaler le reste de la ligne serait la plus grosse erreur.

Le texte entre balises n'est pas coloré.

Shell

S'applique indifféremment à sh, bash et zsh : les mots-clés reconnus sont ceux qu'ils partagent.

Reconnu Comme
if, then, fi, for, while, case, esac, function, return, … keyword
true, false constant
echo, printf, export, local, read, cd, set, source, … builtin
$NOM, ${…}, $(…), $1, $?, $@ builtin
le premier mot nu d'une ligne function
tout mot nu suivant, et NOM dans NOM=valeur identifier
'…', sans échappement ni expansion à l'intérieur string
"…", avec les expansions colorées comme telles string
# jusqu'à la fin de la ligne comment

$(a $(b) c) fait un seul span : l'imbrication est comptée. Une option comme -euo est un seul mot, et non un moins suivi d'un mot.

Les heredocs ne sont pas reconnus. <<EOF et le texte qui suit sont colorés comme du shell ordinaire.

Dockerfile

Reconnu Comme
FROM, RUN, COPY, ADD, ARG, ENV, CMD, ENTRYPOINT, EXPOSE, LABEL, USER, VOLUME, WORKDIR, HEALTHCHECK, ONBUILD, SHELL, STOPSIGNAL, MAINTAINER mot-clé, quelle que soit la casse
AS, NONE mot-clé
# commentaire, y compris les directives # syntax= et # escape= commentaire
--from=builder, --chown=me:me le nom de l'option en attribut
$NOM, ${NOM}, ${NOM:-defaut} builtin, en un seul segment jusqu'à l'accolade fermante
"…", '…' chaîne
un \ final opérateur
les nombres nombre
chemins et références d'images — /usr/local/bin, golang:1.26-alpine identifiant, en un seul segment

Seul le premier mot d'une ligne peut être une instruction, et un mot qui n'en est pas une est un argument — ce qui garde le premier mot d'une ligne de continuation hors de la couleur des mots-clés.

Rien ne traverse un saut de ligne. Un \ joint deux lignes pour Docker, mais chaque moitié se lit encore comme une commande et est colorée pour elle-même.

Non reconnu Parce que
Le shell à l'intérieur d'un RUN Il faudrait passer l'analyseur shell sur une partie de ligne et en remonter les colonnes, et un RUN peut contenir n'importe quel langage
Les heredocs dans un RUN La même raison que pour l'analyseur shell
Quelle étape nomme un --from Rien ici ne lit le reste du fichier

Voir aussi

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# Référence : langages colorés

> Description neutre des fichiers que Turbo MoonBit colore, de la façon dont il décide, et de ce que reconnaît chaque scanner.

## Reconnaissance

L'**extension** d'un fichier décide dès qu'elle fait partie de celles-ci :

| Extension | Langage |
| --- | --- |
| `.mbt`, `.mbti`, `.mbtx` | MoonBit |
| `.toml` | TOML |
| `.yaml`, `.yml` | YAML |
| `.md`, `.markdown` | Markdown |
| `.js`, `.mjs`, `.cjs` | JavaScript |
| `.html`, `.htm` | HTML |
| `.xml`, `.xsd`, `.xsl`, `.xslt`, `.svg`, `.plist`, `.csproj`, `.pom` | XML |
| `.sh`, `.bash`, `.zsh` | Shell |
| `.dockerfile`, `.containerfile` | Dockerfile |

Les extensions sont comparées sans tenir compte de la casse, et seule la dernière compte : `README.mbt.md` est du Markdown, et `main.mbt.backup` n'est pas du MoonBit.

Un fichier dont l'extension ne décide de rien est ensuite cherché par son **nom**. Seuls les fichiers dépourvus d'extension utile en ont besoin :

| Nom | Langage |
| --- | --- |
| `Dockerfile`, `Containerfile` | Dockerfile |

Un nom correspond soit en entier, soit sur la partie qui précède le premier point, sans tenir compte de la casse — `Dockerfile`, `dockerfile` et `Dockerfile.dev` sont donc tous reconnus, tandis que `Dockerfile.md` est du Markdown, puisque l'extension est consultée d'abord.

`moon.mod`, `moon.pkg` et `moon.work` ne sont **pas** dans cette table. Ce sont les fichiers du DSL de configuration de MoonBit plutôt que du MoonBit, et leurs anciennes formes JSON — `moon.mod.json`, `moon.pkg.json` — ne sont pas non plus du JSON que cet éditeur colore. Les cinq s'ouvrent en texte brut.

Un fichier qu'aucune des deux tables ne réclame est lu par sa **première ligne**. Un shebang nommant un shell — `sh`, `bash`, `zsh`, `dash` ou `ksh` — en fait un script shell, et l'interpréteur est reconnu comme élément de chemin ou comme argument de `env`. C'est ce qui colore un script dans un répertoire `bin`, un hook git ou un `configure`.

**Aucun shebang ne fait d'un fichier du MoonBit.** Le langage n'a pas de ligne d'interpréteur : un fichier commençant par `#!` serait lu comme un attribut nommé `!` et échouerait. Un fichier sans extension n'est pas du MoonBit, et prétendre le contraire retirerait un script shell au scanner qui sait réellement le colorer.

| Première ligne | Résultat |
| --- | --- |
| `#!/bin/sh` | Shell |
| `#!/usr/bin/env bash` | Shell |
| `#!/usr/bin/env -S bash -e` | Shell |
| `#!/usr/bin/env moon` | Non coloré |
| `#!/usr/bin/env node` | Non coloré |
| Tout ce qui ne commence pas par `#!` | Non coloré |

L'ordre est fixe — extension, puis nom, puis première ligne — et le premier qui décide l'emporte.

Tout le reste est affiché en texte brut. Ce n'est pas une erreur : ouvrir un PNG dans l'éditeur n'est pas une faute, ce n'est simplement pas coloré.

## Classes

Chaque scanner produit le même vocabulaire de classes, et chacune correspond à une clé de thème.

| Classe | Clé de thème | Produite par |
| --- | --- | --- |
| `identifier` | `syntax.identifier` | MoonBit, TOML, JavaScript, shell, YAML, Dockerfile |
| `keyword` | `syntax.keyword` | MoonBit, JavaScript, shell, HTML (doctype), XML, Dockerfile |
| `type` | `syntax.type` | MoonBit (tout nom capitalisé, et les qualificateurs de paquet), TOML (en-têtes de table), YAML (tags) |
| `builtin` | `syntax.builtin` | MoonBit (le prélude), JavaScript, shell (primitives et expansions), YAML (ancres et alias), Dockerfile (variables) |
| `constant` | `syntax.constant` | MoonBit, TOML, JavaScript, shell, YAML, HTML et XML (entités) |
| `function` | `syntax.function` | MoonBit, JavaScript, shell (la commande) |
| `string` | `syntax.string` | tous |
| `char` | `syntax.char` | MoonBit (`'c'` et `b'c'`) |
| `number` | `syntax.number` | MoonBit, TOML, JavaScript, shell, YAML, Dockerfile |
| `comment` | `syntax.comment` | MoonBit, TOML, JavaScript, shell, HTML, YAML, XML, Dockerfile |
| `operator` | `syntax.operator` | MoonBit, TOML, JavaScript, shell, HTML, YAML (en-têtes de scalaire de bloc), XML, Dockerfile |
| `punctuation` | `syntax.punctuation` | MoonBit, TOML, JavaScript, shell, Markdown, YAML, Dockerfile |
| `heading` | `syntax.heading` | Markdown |
| `tag` | `syntax.tag` | HTML, XML |
| `attribute` | `syntax.attribute` | MoonBit (attributs et arguments étiquetés), HTML, XML, Dockerfile (options) |
| `emphasis` | `syntax.emphasis` | Markdown |
| `link` | `syntax.link` | Markdown |

Dans le seul thème `turbo-classic`, `syntax.attribute` et `syntax.identifier` sont tous deux en jaune simple : un attribut ou une étiquette MoonBit ne s'y distingue donc pas d'un nom ordinaire. Les sept autres thèmes leur donnent des couleurs différentes. Voir [comment écrire son propre thème](../how-to/write-a-theme.md) pour changer cela.

## MoonBit

Écrit à la main, dans `internal/moonbitlang`. **Rien ne franchit une fin de ligne**, et c'est une propriété du langage plutôt qu'une simplification : MoonBit n'a pas de commentaire de bloc, un saut de ligne avant le guillemet fermant est une erreur de *littéral non terminé*, une chaîne multiligne est une suite de lignes `#|` ou `$|` complètes chacune en elle-même, et un attribut tient explicitement sur une ligne. Un guillemet égaré colore donc jusqu'à la fin de sa ligne, et la ligne suivante est de nouveau du code.

| Reconnu | Comme |
| --- | --- |
| `and`, `as`, `async`, `break`, `catch`, `const`, `continue`, `declare`, `defer`, `derive`, `else`, `enum`, `enumview`, `extend`, `extenum`, `extern`, `fn`, `for`, `guard`, `if`, `impl`, `import`, `in`, `is`, `let`, `letrec`, `lexscan`, `loop`, `match`, `mut`, `nobreak`, `nocancel`, `noraise`, `package`, `priv`, `proof_assert`, `proof_let`, `pub`, `raise`, `readonly`, `return`, `struct`, `suberror`, `test`, `throw`, `trait`, `try`, `type`, `using`, `where`, `while`, `with` | mot-clé |
| `try!` et `guard!`, point d'exclamation compris | mot-clé |
| `true`, `false`, `None`, `Some`, `Ok`, `Err` | constante |
| tout nom commençant par une majuscule ASCII — `Int`, `StringBuilder`, `Shape`, `Circle` | type |
| `println`, `abort`, `panic`, `fail`, `ignore`, `inspect`, `debug`, `repr`, `hash`, `compare`, `null`, `assert_eq`, `assert_not_eq`, `assert_true`, `assert_false`, `debug_assert`, `debug_inspect`, `json_inspect`, `physical_equal` | primitive |
| tout autre nom en minuscules immédiatement suivi de `(` | fonction |
| `"…"`, `b"…"`, `re"…"` | chaîne |
| `'c'`, `b'c'` | caractère |
| `#\|` et `$\|` | le préfixe de deux caractères en ponctuation, le reste de la ligne en chaîne |
| `42`, `1_000`, `0xFF_FF`, `0o17`, `0b1010`, `1.5`, `1.`, `1.5e-3`, `0x1.8p3F`, `42U`, `42L`, `42UL`, `42N`, `1.0F` | nombre |
| `//` et `///` jusqu'à la fin de la ligne | commentaire |
| `#deprecated("…")`, `#external`, `#custom.attribute(key="v")` — la ligne entière | attribut |
| `name~` dans un argument étiqueté, tilde compris | attribut |
| `@json`, `@moonbitlang/core/builtin`, `@my-pkg` — le `@` compris, en une seule étendue | type |
| `.0` dans un accès de tuple | le point en ponctuation, les chiffres en nombre |
| `..`, `..=`, `..<`, `...` | opérateur |
| suites de `+-*/%=<>!&\|^~?:` | opérateur |
| `()[]{},;.` | ponctuation |

**Il n'y a ici aucune table des types intégrés, et il n'en faut aucune.** La casse des identifiants de MoonBit est une règle *lexicale* et non une convention : la grammaire dit qu'un `uident` « commence par une majuscule ASCII », et seuls un type, un trait ou un constructeur d'énumération peuvent s'écrire ainsi. `Int`, `StringBuilder` et un type écrit ce matin sont tous colorés par la même ligne de code. Tous les autres scanners de cette famille ont besoin d'une table ici ; celui-ci non.

**Un entier se termine avant `..`.** La grammaire est explicite — « avant `..`, l'entier se termine d'abord, donc `1..=2` commence par `1` puis `..=` » — un point ne fait donc partie d'un nombre que si un second ne le suit pas. Sans cette règle, `1..=2` se lit comme le double `1.` puis `.=2`, et tous les intervalles du fichier sont mal colorés.

**Le suffixe d'un nombre est en majuscules ou ce n'est pas un suffixe.** `42UL` est un seul nombre ; `42u` est le nombre `42` suivi du nom `u`, ce que voit aussi le compilateur.

**Un attribut prend la ligne entière.** La grammaire lui donne tout ce qui suit le nom pointé : « tout ce qui va jusqu'au saut de ligne suivant est la charge utile brute ». Colorer moins que la ligne inventerait une structure que le lexeur n'a pas.

**`#|` et `#deprecated` se distinguent par le caractère qui suit le `#`.** Le nom d'un attribut doit commencer par une lettre ou un tiret bas ; une ligne de chaîne multiligne a une barre verticale à cette place.

**Un commentaire de documentation est coloré comme n'importe quel autre commentaire.** `///`, `///|` et `//` aboutissent tous à `syntax.comment`, parce que l'ensemble des classes de turbo-core est délibérément fermé — c'est ce qui permet à un seul thème de colorer tous les langages qu'un éditeur apprendra jamais.

**Un nom après un point n'est jamais un mot-clé.** Les identifiants pointés de MoonBit « suivent les règles de casse des identifiants sans consulter la table des mots-clés, si bien que `.if` est valide » — un enregistrement avec un champ nommé `type` est du MoonBit ordinaire.

**`package` est aussi coloré comme mot-clé dans un fichier `.mbt`**, alors qu'il n'y est qu'un mot *réservé*. C'est un vrai mot-clé dans les fichiers d'interface `.mbti` que cet éditeur colore également, et dans un `.mbt` la couleur dit exactement ce que le compilateur s'apprête à dire : ce mot ne vous appartient pas. Le reste de la liste réservée — `move`, `ref`, `static`, `unsafe`, `await` et les quarante autres — est délibérément laissé tranquille, parce que ce sont réellement des noms utilisables.

**Un tilde collé à la fin d'un nom en minuscules est une étiquette**, et collé à autre chose il ne l'est pas : la grammaire dit que « les identifiants en majuscules ASCII et les mots-clés ne peuvent pas former d'étiquette », donc `Foo~` est un type suivi d'un tilde.

**Non reconnu**, chaque cas pour une raison énoncée :

| Non reconnu | Parce que |
| --- | --- |
| L'expression à l'intérieur de `\{…}` | La grammaire la fait aller jusqu'à « l'accolade correspondante », les accolades des littéraux imbriqués ne comptant pas : trouver la fin demande l'analyseur syntaxique. `"a \{b} c"` est donc une seule étendue de chaîne, d'accolade à accolade. **C'est une chaîne imbriquée dans une interpolation qui arrête cela** : le scanner prend le premier guillemet non échappé pour le fermant, si bien que `"a \{f("x")} c"` se lit comme chaîne, puis `x` en identifiant, puis chaîne. Les étendues restent ordonnées et ne se chevauchent jamais ; le coût est une couleur fausse à l'intérieur d'un littéral imbriqué, plus rare que les bugs de comptage d'accolades qu'entraînerait l'alternative |
| Un constructeur d'énumération à vous, autrement que comme un type | Rien dans la syntaxe ne sépare `Circle(1.0)` d'un type appliqué à des arguments ; inventer une séparation reviendrait à se tromper dans les deux sens au lieu d'un |
| `.5` comme nombre | MoonBit exige un chiffre avant le point : un point initial est donc un accès de tuple ou un identifiant pointé, jamais un littéral |
| Un mot réservé comme mot-clé | `move`, `ref` et les autres sont des identifiants dont le compilateur se contente d'avertir, et les colorer dirait au lecteur qu'il ne peut pas écrire `let ref = 1` alors qu'il le peut |
| Un identifiant contenant des lettres non ASCII | MoonBit accepte le CJK et plusieurs autres plages dans un nom ; les prédicats de caractères sur lesquels ce scanner est bâti sont ASCII, un tel nom est donc franchi sans couleur plutôt que deviné |
| `.mbt.md` comme du MoonBit | C'est un document Markdown contenant du MoonBit dans ses blocs. Son extension est `.md`, et c'est Markdown qui le colore |
| Si un nom est lié dans cette portée | Rien ici ne lit plus d'une ligne à la fois ; c'est la question du serveur de langage, et [F1 y répond](../how-to/ask-about-code.md) |

## TOML

| Reconnu | Comme |
| --- | --- |
| `# commentaire` | comment |
| `[table]`, `[[array]]` | le nom en type, les crochets en punctuation |
| `clé =` | identifier, puis operator |
| `"basique"`, `'littérale'`, `"""multi-ligne"""`, `'''multi-ligne'''` | string |
| `true`, `false` | constant |
| nombres, dates, heures, `inf`, `nan` | number |

## YAML

Un fichier compose, un manifeste Kubernetes et un workflow d'intégration continue sont tous cela : il n'y a pas de dialecte séparé, parce qu'un dialecte serait le schéma de quelqu'un d'autre à maintenir en phase.

| Reconnu | Comme |
| --- | --- |
| `# commentaire` | commentaire |
| `clé:` suivie d'une espace ou de la fin de ligne | la clé en identifiant, le deux-points en ponctuation |
| `"entre guillemets": 1`, `'apostrophes': 1` | la clé citée en identifiant |
| `- ` ouvrant une entrée de séquence | ponctuation |
| `"…"`, `'…'` | chaîne |
| `true`, `false`, `yes`, `no`, `on`, `off`, `null` | constante, quelle que soit la casse |
| nombres, dates et heures écrits sans guillemets | nombre |
| `&ancre`, `*alias` | builtin |
| `!!str`, `!Custom` | type |
| `---`, `...` | toute la ligne en ponctuation |
| `{`, `}`, `[`, `]`, `,` | ponctuation |
| `\|`, `>`, avec leurs indicateurs de coupe et d'indentation | l'en-tête en opérateur, le corps en chaîne |

**Un deux-points n'est un séparateur que si une espace ou la fin de ligne le suit.** `image: nginx:1.27` est une clé et une seule valeur, et `url: http://example.com/x` une clé et une seule URL — colorer les deux-points intérieurs en séparateurs mettrait chaque étiquette d'image et chaque URL en trois couleurs.

**L'étendue d'un scalaire de bloc est décidée par l'indentation**, pas par un délimiteur. La première ligne de contenu après `|` ou `>` fixe l'indentation du bloc ; toute ligne indentée au moins autant lui appartient, et la première qui ne l'est pas y met fin. **Une ligne vide à l'intérieur d'un bloc y reste** : un scalaire littéral conserve ses lignes vides, et terminer le bloc au premier saut de paragraphe couperait en deux un script shell dans un fichier d'intégration continue.

**Un `#` a besoin d'une espace devant lui pour ouvrir un commentaire**, si bien que `colour: ff#00aa` est un seul scalaire.

| Non reconnu | Parce que |
| --- | --- |
| Le schéma d'un fichier compose, d'un manifeste ou d'un workflow | Colorer `services:` autrement qu'une clé quelconque revient à transporter le schéma de quelqu'un d'autre, qui se périme le jour où il ajoute une clé |
| Les flux multi-documents comme documents distincts | `---` est coloré, mais rien n'est réinitialisé à cet endroit ; rien dans la coloration ne dépend des frontières de documents |
| Si un mot nu est une chaîne ou un nombre pour un analyseur | `1.2.3` est une version pour un lecteur et une chaîne pour YAML ; l'analyseur colore ce à quoi cela ressemble |

## Markdown

| Reconnu | Comme |
| --- | --- |
| `# Titre``###### Titre` | toute la ligne en heading |
| `**gras**`, `__gras__`, `*italique*`, `_italique_` | emphasis |
| `` `code` `` | string |
| `[texte](cible)`, `![alt](src)` | l'ensemble en link |
| `- `, `* `, `+ `, `1. `, `1) ` | le marqueur en punctuation |
| `>` | punctuation |
| `---`, `***`, `___` | punctuation |
| clôtures ` ``` ` et `~~~` | tout le bloc, lignes d'ouverture et de fermeture comprises, en string |

Un bloc clôturé est **d'une seule couleur quel que soit le langage annoncé** : ```` ```moonbit ```` ne colore pas son contenu en MoonBit. La suite de marqueurs qui ouvre un bloc doit être fermée par le même caractère : une clôture en accents graves ne se ferme pas par des tildes. Une clôture non fermée colore jusqu'à la fin du fichier.

La suite de marqueurs qui ouvre une emphase doit être fermée par une suite de même longueur, de sorte que `**gras**` fasse un seul span et non deux italiques.

## JavaScript

| Reconnu | Comme |
| --- | --- |
| `const`, `let`, `function`, `class`, `async`, `await`, `import`, `export`, … | keyword |
| `true`, `false`, `null`, `undefined`, `NaN`, `Infinity`, `this` | constant |
| `console`, `document`, `window`, `Array`, `Object`, `Promise`, `Math`, `JSON`, … | builtin |
| un nom immédiatement suivi de `(` | function |
| `"…"`, `'…'` | string |
| `` `` ``, interpolations comprises, sur plusieurs lignes | string |
| `//` jusqu'à la fin de la ligne, `/* … */` sur plusieurs lignes | comment |
| `42`, `3.14`, `0x1f`, `0b1010`, `0o777`, `1_000_000`, `1e6`, `10n` | number |
| suites de `+-*/%=<>!&|^~?:` | operator |
| `()[]{},;.` | punctuation |

**Les littéraux d'expression régulière ne sont pas reconnus.** Distinguer `/x/g` d'une division exige de savoir si le token précédent pouvait terminer une expression ; une mauvaise supposition colore le reste de la ligne comme une chaîne, ce qui est pire que de laisser une regex à la couleur d'un opérateur.

Les globales sont reconnues par leur nom : un fichier qui masque `Math` la voit quand même colorée comme un builtin — la même règle que les types primitifs de MoonBit.

## HTML

| Reconnu | Comme |
| --- | --- |
| `<balise`, `</balise`, `>`, `/>` | tag |
| noms d'attributs, dont `data-*`, `xlink:href`, `@click`, `v-bind.prop` | attribute |
| `=` | operator |
| `"…"`, `'…'` | string |
| `<!-- … -->`, sur plusieurs lignes | comment |
| `&amp;`, `&#169;` | constant |
| `<!DOCTYPE …>` et les autres déclarations | keyword |

Le texte entre balises n'est pas coloré. Une esperluette isolée sans `;` dans les 32 caractères qui suivent est laissée telle quelle, parce que c'est du texte légal.

**Le contenu de `<script>` et de `<style>` n'est pas coloré** en JavaScript ni en CSS.

## XML

Son propre analyseur plutôt que celui du HTML, pour une raison qui compte : CDATA. Tout l'intérêt de `<![CDATA[ … ]]>` est que son contenu n'est *pas* du balisage, et colorer les balises qu'il contient comme des balises est exactement l'inverse.

| Reconnu | Comme |
| --- | --- |
| `<?xml version="1.0"?>` et les autres instructions de traitement | la cible et `?>` en mot-clé, les paires entre les deux en attributs et chaînes |
| `<!DOCTYPE …>` et les autres formes `<!` | mot-clé |
| `<!-- … -->`, sur plusieurs lignes | commentaire |
| `<![CDATA[ … ]]>`, sur plusieurs lignes | chaîne |
| `<balise`, `</balise`, `>`, `/>` | balise |
| `<ns:balise>`, `xsi:type` | le préfixe et le nom local en **un seul** segment |
| les noms d'attributs | attribut |
| `=` | opérateur |
| `"…"`, `'…'` | chaîne |
| `&amp;`, `&#169;` | constante |

**Un commentaire et une section CDATA se ferment sur des délimiteurs différents**, et sont transportés séparément : un `-->` à l'intérieur d'une section CDATA n'y met pas fin.

**Une esperluette isolée sans point-virgule dans les 32 caractères suivants est laissée telle quelle**, parce que c'est du texte légal dans bien des documents et qu'avaler le reste de la ligne serait la plus grosse erreur.

Le texte entre balises n'est pas coloré.

## Shell

S'applique indifféremment à `sh`, `bash` et `zsh` : les mots-clés reconnus sont ceux qu'ils partagent.

| Reconnu | Comme |
| --- | --- |
| `if`, `then`, `fi`, `for`, `while`, `case`, `esac`, `function`, `return`, … | keyword |
| `true`, `false` | constant |
| `echo`, `printf`, `export`, `local`, `read`, `cd`, `set`, `source`, … | builtin |
| `$NOM`, `${…}`, `$(…)`, `$1`, `$?`, `$@` | builtin |
| le **premier mot nu d'une ligne** | function |
| tout mot nu suivant, et `NOM` dans `NOM=valeur` | identifier |
| `'…'`, sans échappement ni expansion à l'intérieur | string |
| `"…"`, avec les expansions colorées comme telles | string |
| `#` jusqu'à la fin de la ligne | comment |

`$(a $(b) c)` fait un seul span : l'imbrication est comptée. Une option comme `-euo` est un seul mot, et non un moins suivi d'un mot.

**Les heredocs ne sont pas reconnus.** `<<EOF` et le texte qui suit sont colorés comme du shell ordinaire.

## Dockerfile

| Reconnu | Comme |
| --- | --- |
| `FROM`, `RUN`, `COPY`, `ADD`, `ARG`, `ENV`, `CMD`, `ENTRYPOINT`, `EXPOSE`, `LABEL`, `USER`, `VOLUME`, `WORKDIR`, `HEALTHCHECK`, `ONBUILD`, `SHELL`, `STOPSIGNAL`, `MAINTAINER` | mot-clé, quelle que soit la casse |
| `AS`, `NONE` | mot-clé |
| `# commentaire`, y compris les directives `# syntax=` et `# escape=` | commentaire |
| `--from=builder`, `--chown=me:me` | le nom de l'option en attribut |
| `$NOM`, `${NOM}`, `${NOM:-defaut}` | builtin, en un seul segment jusqu'à l'accolade fermante |
| `"…"`, `'…'` | chaîne |
| un `\` final | opérateur |
| les nombres | nombre |
| chemins et références d'images — `/usr/local/bin`, `golang:1.26-alpine` | identifiant, en **un seul** segment |

**Seul le premier mot d'une ligne peut être une instruction**, et un mot qui n'en est pas une est un argument — ce qui garde le premier mot d'une ligne de continuation hors de la couleur des mots-clés.

**Rien ne traverse un saut de ligne.** Un `\` joint deux lignes pour Docker, mais chaque moitié se lit encore comme une commande et est colorée pour elle-même.

| Non reconnu | Parce que |
| --- | --- |
| Le shell à l'intérieur d'un `RUN` | Il faudrait passer l'analyseur shell sur une partie de ligne et en remonter les colonnes, et un `RUN` peut contenir n'importe quel langage |
| Les heredocs dans un `RUN` | La même raison que pour l'analyseur shell |
| Quelle étape nomme un `--from` | Rien ici ne lit le reste du fichier |

## Voir aussi

- [Format des fichiers de thème](themes.md) — toutes les clés vers lesquelles ces classes se résolvent
- [Coloration et complétion](../explanation/colouring-and-completion.md) — pourquoi les scanners sont écrits ainsi
- [Écrire son propre thème](../how-to/write-a-theme.md)