Anpassen des Editorverhaltens mithilfe der Sprachkonfiguration

Sie können eine benutzerdefinierte sprachspezifische Syntax im Visual Studio-Editor implementieren, indem Sie die Sprachkonfiguration verwenden, um sprachspezifische Syntaxoperationen zu ermöglichen. Im Vergleich zur Verwendung eines Sprachservers kann die Verwendung der Sprachkonfiguration die Leistung verbessern, da alle Vorgänge lokal erfolgen.

Was ist die Sprachkonfiguration?

Visual Studio bietet durch Spracherweiterungen intelligente Bearbeitungsmöglichkeiten für verschiedene Programmiersprachen. Die Sprachkonfiguration ergänzt die Server, die das Sprachserverprotokoll (LSP) verwenden, und stellt deklarative Daten bereit, die es dem Visual Studio-Editor ermöglichen, Formatierungs-, Farbgebungs- und Vervollständigungsentscheidungen zu treffen, ohne die Verzögerung einer asynchronen Abfrage an den LSP-Server. Deklarative Sprachfeatures werden in Konfigurationsdateien definiert. Beispielsweise bieten mit Visual Studio gebündelte HTML-, CSS- und TypeScript-Basic-Erweiterungen eine Teilmenge der folgenden deklarativen Sprachfunktionen:

  • Syntaxhervorhebung
  • Vervollständigung des Codeausschnitts
  • Klammernabgleich
  • Automatisches Schließen der Klammer
  • Kommentarumschaltung
  • Automatischer Einzug

Visual Studio bietet die Möglichkeit für Erweiterungen, um eine Sprachkonfiguration für jede Programmiersprache zu definieren. Die Sprachkonfigurationsdatei steuert grundlegende Bearbeitungsfunktionen wie das Umschalten von Kommentaren sowie das Anpassen und Einschließen von Klammern.

Die Verwendung der Sprachkonfiguration unterstützt Folgendes:

  • Synchrones Arbeiten beim Eingeben von Benutzern
  • Einfachheit: Kurze JSON-Dateien mit regulären Ausdrücken sind einfacher zu verwalten als komplexe Algorithmen
  • Portabilität: Erfordert keine oder minimale Änderungen zwischen Visual Studio Code und Visual Studio

Außerdem bieten Sprachkonfigurationsdateien eine einfache Möglichkeit, Visual Studio zu erweitern, um einige grundlegende Umgestaltungs-Funktionen über eine leicht lesbare JSON-Datei zu unterstützen.

Hinzufügen von Sprachkonfigurationsunterstützung zu einer Visual Studio-Erweiterung

Es gibt drei Teile zum Hinzufügen der Sprachkonfigurationsunterstützung zu einer Visual Studio-Erweiterung:

  1. Erstellen eines VSIX-Projekts
  2. Erstellen einer Sprachkonfigurationsdatei
  3. Hinzufügen einer Grammatikdatei
  4. Aktualisieren der pkgdef-Datei

Sie können ein Arbeitsbeispiel im Sprachkonfigurationsbeispiel erkunden.

Erstellen eines VSIX-Projekts

Um eine Sprachdiensterweiterung mit einer Sprachkonfiguration zu erstellen, stellen Sie zunächst sicher, dass die Visual Studio-Erweiterungsentwicklungs-Workload für Ihre Instanz von VS installiert ist.

Erstellen Sie als Nächstes ein neues VSIX-Projekt, indem Sie zu Datei>Neues Projekt navigieren, nach „vsix“ und dann nach VSIX-Projekt suchen:

Screenshot showing how to create a VSIX project.

Erstellen einer Sprachkonfigurationsdatei

Beim Erstellen einer eigenen Sprachkonfigurationsdatei können Sie auswählen, welche Aspekte in der JSON-Datei integriert werden sollen. Sie können beispielsweise das Umschalten von Kommentaren, das automatische Schließen von geschweiften Klammern oder eine beliebige Kombination der in diesem Abschnitt beschriebenen verfügbaren Funktionen unterstützen.

Um Ihrer Erweiterung Unterstützung hinzuzufügen, erstellen Sie zuerst eine Sprachkonfigurationsdatei. Der Name der Datei muss einem Standard entsprechen: Verwenden Sie Bindestriche, um die Wörter im Dateinamen zu trennen, und stellen Sie sicher, dass sie mit language-configuration.json endet.

Der folgende Code zeigt ein Beispiel einer Sprachkonfigurationsdatei.

{
    "comments": {
      "lineComment": "***",
      "blockComment": ["{*", "*}"]
    },
    "brackets": [
      ["@", "@"],
      ["#", "#"],
      ["$", "$"],
      ["(", ")"]
    ],
    "autoClosingPairs": [
      { "open": "{", "close": "}" },
      { "open": "@", "close": "@" },
      { "open": "#", "close": "#" },
      { "open": "$", "close": "$" },
      { "open": "(", "close": ")" },
      { "open": "'", "close": "'", "notIn": ["string", "comment"] },
      { "open": "\"", "close": "\"", "notIn": ["string"] },
    ],
    "autoCloseBefore": ";:.,=}])>` \n\t",
    "surroundingPairs": [
      ["@", "@"],
      ["#", "#"],
      ["$", "$"],
      ["[", "]"],
      ["(", ")"],
      ["'", "'"],
      ["\"", "\""],
      ["`", "`"]
    ],
    "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)",
    "indentationRules": {
      "increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$",
      "decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\)\\}\\]].*$"
    }
  }

Konfigurationseinstellungen

In den folgenden Abschnitten werden die Einstellungen beschrieben, die in der Sprachkonfigurationsdatei verfügbar sind.

Kommentarumschaltung

Sprachkonfigurationsdateien bieten zwei Befehle zum Umschalten von Kommentaren. Zeilenkommentar umschalten und Blockkommentar umschalten. Sie können comments.blockComment und comments.lineComment angeben, um zu steuern, wie Visual Studio Zeilen/Blöcke kommentieren soll.

{
  "comments": {
    "lineComment": "//",
    "blockComment": ["/*", "*/"]
  }
}

Diese Einstellung wirkt sich auf das Verhalten des Visual Studio-Text-Editors aus, wenn Sie Strg+K, Strg+C drücken.

Definition der Klammern

Wenn Sie den Cursor auf eine hier definierte Klammer bewegen, hebt Visual Studio diese Klammer zusammen mit ihrem entsprechenden Paar hervor.

{
  "brackets": [["{", "}"], ["[", "]"], ["(", ")"]]
}

Die relevante Einstellung im Visual Studio-Dialogfeld Extras > Optionen in Text-Editor, Allgemein, Anzeige ist das Kontrollkästchen Farbgebung für geschweifte Klammerpaare aktivieren.

Automatisches Schließen

Wenn Sie ' eingeben, erstellt Visual Studio ein Paar einzelner Anführungszeichen und platziert den Cursor in der Mitte: '|'. In diesem Abschnitt werden solche Paare definiert.

{
  "autoClosingPairs": [
    { "open": "{", "close": "}" },
    { "open": "[", "close": "]" },
    { "open": "(", "close": ")" },
    { "open": "'", "close": "'", "notIn": ["string", "comment"] },
    { "open": "\"", "close": "\"", "notIn": ["string"] },
    { "open": "`", "close": "`", "notIn": ["string", "comment"] },
    { "open": "/**", "close": " */", "notIn": ["string"] }
  ]
}

Der Schlüssel notIn deaktiviert dieses Feature in bestimmten Codebereichen. Dies ist beispielsweise der Fall, wenn Sie den folgenden Code schreiben:

// ES6's Template String
`ES6's Template String`;

Das einfache Anführungszeichen wird nicht automatisch geschlossen.

Paare, die keine notIn-Eigenschaft erfordern, können auch eine einfachere Syntax verwenden:

{
  "autoClosingPairs": [ ["{", "}"], ["[", "]"] ]
}
Automatisches Schließen vor

Standardmäßig schließt Visual Studio Paare nur dann automatisch, wenn direkt nach dem Cursor ein Leerzeichen vorhanden ist. Wenn Sie also { im folgenden JSX-Code eingeben, würde kein automatisches Schließen erfolgen.

const Component = () =>
  <div className={>
                  ^ Does not get autoclosed by default
  </div>

Diese Definition überschreibt dieses Verhalten jedoch:

{
  "autoCloseBefore": ";:.,=}])>` \n\t"
}

Wenn Sie jetzt { direkt vor > eingeben, schließt Visual Studio es nicht automatisch mit }.

Automatisch Umranden

Wenn Sie in Visual Studio einen Bereich auswählen und eine öffnende Klammer eingeben, umrandet Visual Studio den ausgewählten Inhalt mit zwei Klammern. Dieses Feature wird als automatisches Umranden bezeichnet. Hier können Sie die Paare für automatisches Umranden für eine bestimmte Sprache definieren:

{
  "surroundingPairs": [
    ["{", "}"],
    ["[", "]"],
    ["(", ")"],
    ["'", "'"],
    ["\"", "\""],
    ["`", "`"]
  ]
}

Die relevante Einstellung in Visual Studio Extras > Optionen ist in Text-Editor, Allgemein, Anzeigen das Kontrollkästchen Auswahl beim Eingeben von Anführungszeichen oder eckigen Klammern automatisch umranden.

Wortmuster

wordPattern definiert, was als Wort in der Programmiersprache betrachtet wird. Codevorschlagsfeatures verwenden diese Einstellung, um Wortgrenzen zu bestimmen, falls wordPattern festgelegt ist.

{
  "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)"
}

Einzugsregeln

indentationRules definiert, wie der Editor den Einzug der aktuellen Zeile oder der nächsten Zeile beim Eingeben, Einfügen und Verschieben von Zeilen anpassen soll oder wenn Sie Text mit Strg+K, Strg+D (Dokument formatieren) und Strg+K, Strg+F (Formatauswahl) formatieren.

{
  "indentationRules": {
    "increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$",
    "decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\)\\}\\]].*$"
  }
}

Wenn beispielsweise if (true) { mit increaseIndentPattern übereinstimmt und Sie dann die Eingabetaste nach der offenen Klammer drücken {, wird der Editor automatisch einmal eingerückt und Ihr Code sieht am Ende wie folgt aus:

if (true) {
  console.log();

Zusätzlich zu increaseIndentPattern und decreaseIndentPatter gibt es zwei weitere Einzugsregeln:

  • indentNextLinePattern – Wenn eine Zeile mit diesem Muster übereinstimmt, sollte nur die nächste Zeile danach eingezogen werden.
  • unIndentedLinePattern – Wenn eine Zeile mit diesem Muster übereinstimmt, sollte der Einzug nicht geändert werden und nicht anhand der anderen Regeln ausgewertet werden.

Wenn für die Programmiersprache keine Einzugsregel festgelegt ist, rückt der Editor ein, wenn die Zeile mit einer offenen Klammer endet, und entfernt den Einzug, wenn Sie eine schließende Klammer eingeben. Die Klammer hier wird durch brackets definiert.

Drücken der Eingabetaste

onEnterRules definiert eine Liste von Regeln, die ausgewertet werden sollen, wenn die Eingabetaste im Editor gedrückt wird.

{
  "onEnterRules": [{
    "beforeText": "^\\s*(?:def|class|for|if|elif|else|while|try|with|finally|except|async).*?:\\s*$",
    "action": { "indent": "indent" }
  }]
}

Beim Drücken der Eingabetaste wird der Text vor, nach oder eine Zeile über dem Cursor anhand der folgenden Eigenschaften überprüft:

  • beforeText (obligatorisch). Ein regulärer Ausdruck, der mit dem Text vor dem Cursor übereinstimmt (begrenzt auf die aktuelle Zeile).
  • afterText. Ein regulärer Ausdruck, der mit dem Text nach dem Cursor übereinstimmt (begrenzt auf die aktuelle Zeile).
  • previousLineText. Ein regulärer Ausdruck, der mit dem Text eine Zeile über dem Cursor übereinstimmt.

Wenn alle angegebenen Eigenschaften übereinstimmen, wird die Regel als Übereinstimmung betrachtet, und es werden keine weiteren onEnterRules ausgewertet. Eine onEnterRule kann die folgenden Aktionen angeben:

  • indent (obligatorisch). Eine von none, indent, outdent, indentOutdent.
    • none bedeutet, dass die neue Zeile den Einzug der aktuellen Zeile erbt.
    • indent bedeutet, dass die neue Zeile relativ zur aktuellen Zeile eingezogen wird.
    • outdent bedeutet, dass die neue Zeile relativ zur aktuellen Zeile nicht eingerückt ist.
    • indentOutdent bedeutet, dass zwei neue Zeilen eingefügt werden, eine eingerückt und die zweite nicht eingerückt.
  • appendText. Eine Zeichenfolge, die nach der neuen Zeile und nach dem Einzug angehängt wird.
  • removeText. Die Anzahl der Zeichen, die aus dem Einzug der neuen Zeile entfernt werden sollen.

Eigenschafteneinstellungen

Stellen Sie im Erweiterungsprojekt sicher, dass Ihre language-configuration.json-Datei die folgenden Eigenschafteneinstellungen aufweist:

Build Action = Content
Include in VSIX = True
Copy to output = Copy always 

(optional) Hinzufügen einer Grammatikdatei

Darüber hinaus können Sie eine TextMate-Grammatikdatei hinzufügen, um Syntaxfarben für die Sprache bereitzustellen. TextMate-Grammatiken sind eine strukturierte Sammlung regulärer Ausdrücke und werden als Plist- (XML) oder JSON-Dateien geschrieben. Siehe Sprachgrammatiken. Wenn Sie keine sprachspezifische Grammatikdatei bereitstellen, wird eine integrierte Standardeinstellung verwendet.

Gehen Sie folgendermaßen vor, um benutzerdefinierte TextMate-Grammatik- oder Designdateien hinzuzufügen:

  1. Erstellen Sie einen Ordner mit dem Namen „Grammatiken“ in Ihrer Erweiterung (oder es kann sich um den von Ihnen ausgewählten Namen handeln).

  2. Schließen Sie im Ordner Grammatiken alle folgenden Dateien, *.tmlanguage, *.plist, *.tmtheme oder *.json, ein, die Sie für benutzerdefinierte Farbgebung bereitstellen möchten.

    Tipp

    Eine .tmtheme-Datei definiert, wie die Bereiche Visual Studio-Klassifizierungen (benannte Farbschlüssel) zugeordnet werden. Eine Anleitung finden Sie in der globalen Datei .tmtheme im Verzeichnis %ProgramFiles(x86)%\Microsoft Visual Studio\<version>\<SKU>\Common7\IDE\CommonExtensions\Microsoft\TextMate\Starterkit\Themesg.

Erstellen einer pkgdef-Datei

Erstellen Sie dann eine .pkgdef-Datei. Eine .pkgdef-Datei enthält alle Registrierungsinformationen, die andernfalls der Systemregistrierung hinzugefügt werden. Weitere Informationen zu pkgdef-Dateien finden Sie unter Registrieren von VSPackages und Was ist eine pkgdef-Datei? Und warum?. In Ihrer pkgdef-Datei sollten Sie über den Pfad zu der language-configuration.json-Datei und den Pfad für die Sprachgrammatik verfügen. Sprachdienste wie LSP fordern den Inhaltstyp des Editors an und erhalten diesen über die Sprachkonfiguration. Diese Informationen stellen die sprachspezifische Intelligenz innerhalb eines Servers bereit, die mit Entwicklungstools kommunizieren kann. Wenn kein Sprachdienst vorhanden ist, greift das Sprachkonfigurationsmodul auf die TextMate-Grammatik zurück. Ihre Datei .pkgdef sollte wie folgt aussehen:

[$RootKey$\TextMate\Repositories]
"AspNetCoreRazor="$PackageFolder$\Grammars

// Defines where the language configuration file for a given
// grammar name is (value of the ScopeName tag in the tmlanguage file).
[$RootKey$\TextMate\LanguageConfiguration\GrammarMapping]
"text.aspnetcorerazor"="$PackageFolder$\language-configuration.json"

// Defines where the language configuration file for a given
// language name is (partial value of the content type name).
[$RootKey$\TextMate\LanguageConfiguration\ContentTypeMapping]
"RazorLSP"="$PackageFolder$\language-configuration.json"

[$RootKey$\TextMate\LanguageConfiguration\GrammarMapping]
"text.html.basic"="$PackageFolder$\html-language-configuration.json"
"source.js"="$PackageFolder$\javascript-language-configuration.json"
"source.css"="$PackageFolder$\css-language-configuration.json"
"source.cs"="$PackageFolder$\csharp-language-configuration.json

Stellen Sie sicher, dass die Eigenschaften der pkgdef-Datei wie folgt festgelegt werden:

Build Action = Content
Include in VSIX = True
Copy to output = Copy always 

Um die Sprachkonfigurationsinformationen für Visual Studio zugänglich zu machen, schließen Sie die language-configuration-Datei in das VSIX-Paket ein. Das Einschließen dieser Datei bedeutet, dass sie mit der Visual Studio-Erweiterung bereitgestellt wird. Die Datei teilt Visual Studio mit, dass eine Sprachkonfiguration zur Verwendung verfügbar ist. Um die Datei hinzuzufügen, bearbeiten Sie vsixmanifest, um Ihre PKGDEF-Def-Datei hinzuzufügen, z. B.:

<Asset Type="Microsoft.VisualStudio.VsPackage" Path="Test.pkgdef"/>