Aller au contenu

Extension LSP (serveur de langage)

Intelligence du code propulsée par le Language Server Protocol — soulignements d'erreurs, navigation, survol, complétion, aide à la signature, formatage, recherche de références, renommage et aller au symbole — pour tout langage disposant d'un serveur de langage. L'éditeur parle au serveur via LSP ; l'extension est le client. Les serveurs disponibles sont pilotés par les données (un petit JSON par langage) : C++/clangd ci-dessous n'est qu'une des définitions livrées.

L'éditeur n'embarque ni ne télécharge de serveurs

Un serveur de langage est un programme séparé que vous installez une fois. MTE détecte un serveur installé et le pointe vers votre projet ; il n'en livre jamais. Voir Obtenir un serveur de langage.

Fonctionnalités actuelles

Fonctionnalité Comment
Diagnostics Les erreurs/avertissements du serveur apparaissent en soulignements ondulés (rouge = erreur, ambre = avertissement, bleu = info, gris = indice), mis à jour pendant la frappe.
Aller à la définition Curseur sur un symbole et F12, ou Recherche ▸ Navigation dans le code ▸ Aller à la définition. Saute à la définition, en ouvrant un autre fichier si nécessaire.
Rechercher les références Curseur sur un symbole → Shift+F12 (ou Recherche ▸ Navigation dans le code ▸ Rechercher les références). Les résultats s'ouvrent dans un panneau inférieur Références, groupés par fichier avec un aperçu de la ligne source ; double-clic pour sauter.
Survol Laissez le pointeur sur un symbole ; une infobulle montre son type/sa signature et sa documentation (rendue depuis le Markdown du serveur).
Complétion Ctrl+Space demande les complétions au serveur et les fond dans la fenêtre de complétion de l'éditeur (avant les suggestions intégrées de mots-clés/mots des tampons), filtrées pendant la frappe.
Aide à la signature Taper le ( d'un appel ou une , affiche une bulle avec la signature de la fonction et le paramètre actif en surbrillance ; ) la ferme.
Formater le document Alt+Shift+F (ou Édition ▸ Formater le document) reformate tout le document via le serveur, en une seule étape d'annulation. Le style relève de la configuration du serveur (pour clangd, un fichier .clang-format).
Rechercher les références (ci-dessus)
Renommer le symbole Curseur sur un symbole → Shift+F6 (ou Édition ▸ Renommer le symbole). Saisissez un nouveau nom ; chaque usage est mis à jour. Quand le renommage couvre plusieurs fichiers, une confirmation est demandée d'abord — chaque fichier est ouvert, modifié et laissé modifié pour relecture et enregistrement.
Aller au symbole (dans le fichier) Ctrl+Shift+O ouvre la palette de commandes listant chaque symbole du fichier courant (fonctions, classes, méthodes…) ; tapez pour filtrer, Entrée saute. Chaque ligne montre le genre du symbole et son conteneur.
Aller au symbole dans l'espace de travail Ctrl+T cherche les symboles dans tout le projet pendant la frappe (le serveur fait la correspondance) ; Entrée ouvre le fichier au symbole.

Les sélecteurs « aller au symbole » sont les modes symboles de la palette de commandes — voir la palette de commandes.

Références inter-fichiers et renommage exigent l'index du serveur

Rechercher les références et Renommer n'atteignent d'autres fichiers qu'une fois le projet indexé par le serveur. Pour C/C++, cela signifie un compile_commands.json (voir plus bas) et l'index d'arrière-plan de clangd ; sans lui, ils n'opèrent que sur le fichier ouvert.

Le renommage s'annule fichier par fichier pour l'instant

Un renommage multi-fichiers est appliqué fichier par fichier : chaque fichier est sa propre étape d'annulation (la boîte de confirmation le précise). Relisez les onglets modifiés avant d'enregistrer.

L'indicateur d'état du serveur

La barre d'état affiche un segment compact LSP: (à gauche des autres segments d'extension) résumant chaque serveur de langage pertinent pour vos fichiers ouverts :

LSP: cpp ✓  python ↻2  rust ✗
Glyphe Signification
Démarrage — le serveur a été lancé et négocie.
Prêt — répond aux requêtes.
↻n Redémarrage — le serveur s'est arrêté de façon inattendue ; la tentative automatique n° n est planifiée.
Éteint — soit aucun serveur n'est installé pour ce langage, soit le serveur n'a cessé de planter et les redémarrages automatiques ont abandonné.

Le segment apparaît quand s'ouvre le premier document d'un langage configuré, ne suit que les langages dont vous avez réellement des documents ouverts — fermer le dernier fichier d'un langage retire son entrée (en rouvrir un la ramène aussitôt) — et disparaît entièrement quand plus aucun document de ce type ne reste.

Si un serveur plante

Un serveur de langage qui se termine de façon inattendue est redémarré automatiquement avec un délai croissant (1 s, 2 s, 4 s… plafonné à 30 s). Pendant ce temps, l'indicateur montre ↻n et une notification de la barre d'état signale le premier plantage. Après un redémarrage réussi, vos documents ouverts sont réannoncés au serveur et les diagnostics reviennent d'eux-mêmes ; les soulignements périmés du serveur mort sont effacés immédiatement. L'édition n'est jamais bloquée.

Après 5 tentatives échouées d'affilée, l'extension abandonne : l'indicateur montre , une notification vous renvoie aux paramètres, et le langage reste éteint jusqu'à un redémarrage manuel. Un serveur qui a fonctionné correctement au moins une minute retrouve un quota de tentatives neuf lors d'un plantage ultérieur.

Redémarrage manuel — au choix :

  • Recherche ▸ Navigation dans le code ▸ Redémarrer les serveurs de langage (pas de raccourci par défaut ; aussi disponible depuis la palette de commandes), ou
  • le bouton Re-scanner / redémarrer les serveurs dans Préférences ▸ Serveur de langage.

Les deux arrêtent tous les serveurs, relancent la découverte avec les paramètres actuels et remettent à zéro le quota d'échecs — à utiliser après avoir installé un serveur manquant ou réparé un serveur cassé.

Obtenir un serveur de langage

Installez le serveur de votre langage et vérifiez qu'il est dans le PATH (ou définissez un chemin explicite dans les paramètres). Si aucun n'est trouvé, la fonctionnalité ne fait simplement rien pour ce langage — l'indicateur d'état montre et le journal consigne un indice unique, mais rien ne vous interrompt.

MTE livre des définitions de serveurs (pas les serveurs) pour de nombreux langages : la plupart n'exigent que l'installation du serveur — aucune édition de JSON. Les définitions livrées couvrent C/C++, Python, Rust, Go, TypeScript, JavaScript, C#, Java, HTML, CSS, JSON, YAML et Bash (plus des entrées prospectives Kotlin, Swift et Objective-C qui s'activeront quand ces langages auront la coloration syntaxique).

Langage Serveur Où l'obtenir
C/C++ clangd winget install LLVM.LLVM (Windows), le composant « C++ Clang tools » de l'installeur Visual Studio, brew install llvm (macOS), ou le paquet clang-tools-extra de votre distribution.
Python pyright npm i -g pyright.
TypeScript/JS typescript-language-server npm i -g typescript-language-server typescript.
Rust rust-analyzer rustup component add rust-analyzer.
Go gopls go install golang.org/x/tools/gopls@latest.

Vérifiez dans un terminal, p. ex. clangd --version. Pour un langage sans définition livrée, ajoutez-en une comme décrit dans Ajouter un langage.

Les projets C/C++ ont besoin de compile_commands.json

clangd ne comprend votre code avec précision que s'il connaît les drapeaux de compilation, via une base de compilation (compile_commands.json). Sans elle, clangd devine et les fonctions inter-fichiers (références, renommage) restent limitées au fichier ouvert.

MTE trouve un compile_commands.json automatiquement — il cherche à la racine du projet et dans les dossiers de build usuels (build/, out/, cmake-build-*, .mte-compile-commands/) et y pointe clangd. C'est vous qui générez la base ; pas l'éditeur (configurer de façon fiable un projet arbitraire exige l'environnement de votre chaîne d'outils/SDK, que l'éditeur n'a pas). Quand un projet C/C++ n'en a pas, MTE montre un indice unique (avec une option Ne plus afficher) menant ici.

La générer (CMake)

CMAKE_EXPORT_COMPILE_COMMANDS n'est honoré que par les générateurs Ninja et Makefile — le générateur Visual Studio l'ignore (il ne produit pas de compile_commands.json même avec le drapeau). Générez donc la base avec Ninja, dans un dossier dédié, séparé de celui où vous construisez d'habitude : CMake refuse de reconfigurer un dossier de build existant avec un autre générateur, un projet construit avec Visual Studio a donc besoin de son propre dossier Ninja.

C'est une étape de configuration seule (pas de build complet). Depuis la racine du projet :

cmake -S . -B .mte-compile-commands -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
  • .mte-compile-commands/ fait partie des dossiers scannés par MTE, le compile_commands.json produit est donc trouvé automatiquement. Tout dossier scanné convient (build/, out/, cmake-build-* ou la racine du projet) — gardez-le simplement séparé d'un dossier configuré avec un autre générateur.
  • Exécutez-la depuis un environnement où le projet se configure vraiment : le bon compilateur dans le PATH (p. ex. une x64 Native Tools Command Prompt sous Windows) et les variables dont votre projet a besoin (comme QT6_DIR pour un projet Qt). Si cmake ne trouve pas votre compilateur ou SDK, la base sort vide ou sans chemins d'inclusion et clangd indexera mal.
  • Rouvrez le dossier ensuite. Le journal ne devrait plus dire « no compile_commands.json » ; laissez à clangd un moment pour bâtir son index d'arrière-plan avant que références/renommage ne couvrent les fichiers.

Autres systèmes de build : Bear (bear -- make), compiledb, Meson, Bazel et d'autres savent aussi produire un compile_commands.json que l'extension trouvera.

Ajouter un langage

Les serveurs sont décrits par des fichiers JSON que l'extension charge au démarrage depuis <editor>/lsp-servers/*.json. Chaque entrée associe un langage à sa commande plus des indices de découverte :

{
    "language":    "cpp",
    "command":     "clangd",
    "aliases":     ["clangd-18", "clangd-17"],
    "args":        ["--background-index"],
    "extensions":  [".cpp", ".h", ".hpp"],
    "searchDirs":  ["${LLVM}/bin", "${ProgramFiles}/LLVM/bin"],
    "docsAnchor":  "cpp-clangd",
    "compileCommandsArg": "--compile-commands-dir=${dir}"
}
  • language correspond à l'identifiant de langage détecté par l'éditeur ; command/aliases sont les noms d'exécutables essayés dans le PATH ; searchDirs (avec expansion ${VAR}) sont des emplacements d'installation supplémentaires.
  • compileCommandsArg (facultatif) est ajouté, ${dir} étant remplacé par le dossier de la base localisée — c'est ainsi que clangd est pointé vers compile_commands.json.

Comment un serveur est localisé

Pour un document correspondant, l'extension résout le serveur dans l'ordre : un chemin explicitement configuré → la command et ses aliases dans le PATH → les searchDirs de l'entrée et les emplacements de l'écosystème. Le serveur démarre une fois par langage et s'arrête avec l'éditeur.

Paramètres du serveur de langage

Préférences ▸ Serveur de langage liste chaque langage disposant d'une définition de serveur. Par langage, vous pouvez :

  • Activer / désactiver le serveur (un langage désactivé n'en démarre jamais).
  • Définir un chemin d'exécutable explicite (avec Parcourir…). Cette valeur l'emporte sur la recherche PATH/searchDirs ci-dessus — utile quand le serveur n'est pas dans le PATH ou que vous voulez un build précis.

Les changements prennent effet à OK / Appliquer : si un drapeau d'activation ou un chemin a réellement changé, les serveurs redémarrent automatiquement avec les nouveaux paramètres (une page non touchée ne perturbe jamais les serveurs en cours). Le bouton Re-scanner / redémarrer les serveurs force en plus un arrêt-et-redécouverte avec les paramètres actuels — utile après l'installation d'un serveur que l'éditeur ne trouvait pas ; il remet aussi à zéro le quota de redémarrages après plantage.

Limites

  • La coloration du code dans les infobulles de survol n'est pas appliquée (le texte est mis en forme — gras, titres, code à chasse fixe — mais pas colorisé syntaxiquement).
  • La précision dépend du serveur : pour C/C++, sans compile_commands.json, clangd retombe sur des heuristiques et les résultats peuvent être incomplets.