Nico Prat

Nico Prat

Personnaliser la visualisation de syntaxe TypeScript dans VSCode

Mieux aborder TypeScript avec une aide visuelle


VSCode TypeScript Syntax Highlighting

TypeScript peut être intimidant au premier abord, surtout quand on est habitué à la relative simplicité de JavaScript (ou allergique à la verbosité d'autres languages qu'on a appris pendant les études comme Java). Quand j'ai commencé à l'apprendre il y a environ deux ans, j'ai trouvé le code difficile à scanner, comme si tout était légèrement moins lisible.

J'ai alors cherché un moyen de mieux distinguer le code nouveau de l'existant, et ai commencé à m'intéresser à comment VSCode gère les thèmes visuels.

Editor tokens & scopes#

Un peu à la même manière d'AST (Abstract Syntax Tree), VSCode découpe le code de chaque fichier en tokens (jetons) pour avoir une vue abstraite de celui-ci et permettre de le manipuler plus facilement. Cette abstraction est ensuite utilisée pour créer des thèmes et analyser le code.

Pour mieux comprendre ce fonctionnement, il existe un guide concernant le syntax highlighting et le semantic highlighting. Le premier se contente d'une analyse statique, alors que le deuxième comprend le code (par exemple qu'une variable est en fait un paramètre, et va donc conserver la même couleur pour chaque occurrence dans un souci d'homogénéité) :

image

Pour faire simple, chaque caractère de notre code se verra attribuer :

  • un type de token : String, Comment, ... (liste exhaustive ici)
  • un ou plusieurs scopes, qui se déclinent comme des (sous-)ensembles

Des extensions peuvent bien sûr ajouter des scopes, par exemple pour les fichiers Vue (Single File Components), qui contiennent à la fois HTML, JavaScript et CSS.

Personnalisation#

Pour nous aider à appréhender ce système, VSCode propose une commande "Developer: Inspect Editor Tokens and Scopes" qui affiche une tooltip avec les informations concernant le code actuellement sélectionné. Voici un exemple avec la fonction compact de Lodash :

VSCode Developer: Inspect Editor Tokens and Scopes exemple

Il y a beaucoup d'informations, mais la seule qui nous intéresse pour le moment est la liste des scopes ; les plus restreints sont listés en premier. On va pouvoir les utiliser pour cibler les éléments à personnaliser.

Passons maintenant aux paramètres de VSCode pour ajuster le thème selon nos besoins. La documentation nous indique qu'il faut modifier notre fichier settings.json de cette façon (commande "Preferences: Open User Settings (JSON)") :

{
  "editor.tokenColorCustomizations": {
    "textMateRules": [
      {
        "scope": [],
        "settings": {}
      }
    ]
  },
}

En naviguant dans le code au fil des semaines, et en tatonnant sur la spécificité des règles, je suis arrivé à cette liste de scopes (qui n'est probablement pas exhaustive) :

{
  "editor.tokenColorCustomizations": {
    "textMateRules": [
      {
        "scope": [
            "support.type.builtin.ts",
            "meta.interface.ts punctuation.definition.block.ts",
            "meta.type.annotation.ts",
            "meta.type.declaration.ts",
            "entity.name.type.ts",
            "support.type.primitive.ts",
            "entity.name.type.alias.ts",
            "entity.name.type.interface.ts",
            "storage.type.interface.ts",
            "keyword.operator.type.annotation.ts",
            "punctuation.definition.typeparameters.begin.ts",
            "punctuation.definition.typeparameters.end.ts",
            "meta.object.type.ts",
            "meta.object.member.ts meta.type.tuple.ts",
            "keyword.control.satisfies.ts",
            "keyword.control.as.ts",
            "meta.type.declaration.ts punctuation.definition.block.ts",
            "meta.type.declaration.ts keyword.operator.assignment.ts",
            "meta.type.parameters.ts punctuation.separator.comma.ts",
            "meta.type.parameters.ts punctuation.definition.block.ts",
            "meta.type.annotation.ts keyword.operator.type.ts",
            "meta.type.annotation.ts punctuation.terminator.statement.ts",
            "meta.type.annotation.ts punctuation.definition.block.ts",
            "meta.type.annotation.ts string.quoted.single.ts",
            "meta.return.type.arrow.ts meta.type.tuple.ts",
            "meta.interface.ts",
            "keyword.operator.definiteassignment.ts",
            "keyword.operator.optional.ts",
            "storage.type.type.ts"
          ],
        "settings": {
          "fontStyle": "italic",
          "foreground": "#ff0000"
        }
      }
    ]
  },
}

Comme on peut le voir, tous les scopes terminent par ".ts", et les scopes peuvent être précisés, en s'assurant qu'il est bien contenu dans un autre, avec un espace (un peu à la manière d'un sélecteur CSS): "meta.type.annotation.ts keyword.operator.type.ts".

Ne reste plus qu'à choisir quels styles appliquer. Malheureusement, les options sont limitées : uniquement la couleur du texte, et quelques styles de font (gras, italique, souligné, barré), ou un mélange de tout ça. Pour éviter tout conflit de couleurs avec un thème, j'ai choisi d'appliquer l'italique, ce qui reste assez discret au quotidien. J'avais pour idée d'utiliser une couleur de fond très légère, mais ce n'est toujours pas possible dans VSCode (ticket en cours depuis 2016).

Voilà le résultat sur un exemple de code de la documentation TypeScript avec "fontStyle": "italic":

image

Libre à vous de trouver ce qui vous convient le mieux, par exemple en gras avec "fontStyle": "bold":

image

On peut même s'amuser avec des styles plus atypiques, ici avec filter: drop-shadow() (c'est plus compliqué, voilà comment le thème MoonLight propose de le faire):

image

Conclusion#

Pour ma part, cette astuce m'a aidé les premiers temps à mieux digérer les nouveautés de TypeScript. Je pourrais supprimer cette personnalisation aujourd'hui, mais je m'y suis habitué et l'ai conservée. J'espère que ça peut aider certains à se mettre à TypeScript !