Teilen über


Hinzufügen einer Erweiterung für das Sprachserverprotokoll

Das Sprachserverprotokoll (LSP) ist ein gängiges Protokoll in Form von JSON RPC v2.0, das zur Bereitstellung von Sprachdienstfunktionen für verschiedene Code-Editoren verwendet wird. Mithilfe des Protokolls können Entwickler einen einzelnen Sprachserver schreiben, um verschiedenen Code-Editoren, die den LSP unterstützen, Sprachdienstfunktionen wie IntelliSense, Fehlerdiagnose, die Suche nach allen Referenzen usw. bereitzustellen. Traditionell können Sprachdienste in Visual Studio hinzugefügt werden, indem TextMate-Grammatikdateien verwendet werden, um grundlegende Funktionen wie Syntaxhervorhebung bereitzustellen, oder indem benutzerdefinierte Sprachdienste geschrieben werden, die den vollständigen Satz der Visual Studio-Erweiterbarkeits-APIs verwenden, um umfangreichere Daten bereitzustellen. Mit der Visual Studio-Unterstützung für LSP gibt es eine dritte Option.

language server protocol service in Visual Studio

Um die bestmögliche Benutzererfahrung sicherzustellen, sollten Sie auch die Implementierung der Sprachkonfiguration in Betracht ziehen, die die lokale Verarbeitung vieler derselben Vorgänge ermöglicht und daher die Leistung vieler der vom LSP unterstützten sprachspezifischen Editorvorgänge verbessern kann.

Sprachserverprotokoll

language server protocol implementation

In diesem Artikel wird beschrieben, wie Sie eine Visual Studio-Erweiterung erstellen, die einen LSP-basierten Sprachserver verwendet. Dabei wird davon ausgegangen, dass Sie bereits einen LSP-basierten Sprachserver entwickelt haben und ihn nur noch in Visual Studio integrieren möchten.

Zur Unterstützung innerhalb von Visual Studio können Sprachserver über einen beliebigen Stream-basierten Übertragungsmechanismus mit dem Client (Visual Studio) kommunizieren, zum Beispiel:

  • Standard-Eingabe-/Ausgabestreams
  • Named Pipes
  • Sockets (nur TCP)

Die Absicht des LSP und seiner Unterstützung in Visual Studio besteht darin, Sprachdienste zu integrieren, die nicht Teil des Visual Studio-Produkts sind. Es ist nicht vorgesehen, vorhandene Sprachdienste (z. B. C#) in Visual Studio zu erweitern. Informationen zum Erweitern vorhandener Sprachen finden Sie im Erweiterbarkeitsleitfaden des Sprachdiensts (z. B. "Roslyn" .NET Compiler Platform) oder unter Erweitern des Editors und der Sprachdienste.

Weitere Informationen zum Protokoll selbst finden Sie hier in der Dokumentation.

Weitere Informationen zum Erstellen eines Beispielsprachenservers oder zum Integrieren eines vorhandenen Sprachservers in Visual Studio Code finden Sie hier in der Dokumentation.

Unterstützte Features des Sprachserverprotokolls

Die folgenden Tabellen zeigen, welche LSP-Features in Visual Studio unterstützt werden:

`Message` Wird in Visual Studio unterstützt
initialize ja
initialisiert ja
shutdown ja
exit ja
$/cancelRequest ja
window/showMessage ja
window/showMessageRequest ja
window/logMessage ja
telemetry/event
client/registerCapability
client/unregisterCapability
workspace/didChangeConfiguration ja
workspace/didChangeWatchedFiles ja
workspace/symbol ja
workspace/executeCommand ja
workspace/applyEdit ja
textDocument/publishDiagnostics ja
textDocument/didOpen ja
textDocument/didChange ja
textDocument/willSave
textDocument/willSaveWaitUntil
textDocument/didSave ja
textDocument/didClose ja
textDocument/completion ja
completion/resolve ja
textDocument/hover ja
textDocument/signatureHelp ja
textDocument/references ja
textDocument/documentHighlight ja
textDocument/documentSymbol ja
textDocument/formatting ja
textDocument/rangeFormatting ja
textDocument/onTypeFormatting
textDocument/definition ja
textDocument/codeAction ja
textDocument/codeLens
codeLens/resolve
textDocument/documentLink
documentLink/resolve
textDocument/rename ja

Erste Schritte

Hinweis

Ab Visual Studio 2017 Version 15.8 ist die Unterstützung für das allgemeine Sprachserverprotokoll in Visual Studio integriert. Wenn Sie LSP-Erweiterungen mithilfe der Sprachserver-Client-VSIX-Vorschauversion erstellt haben, funktionieren sie nicht mehr, sobald Sie ein Upgrade auf Version 15.8 oder höher durchführen. Sie müssen die folgenden Schritte ausführen, damit Ihre LSP-Erweiterungen wieder funktionieren:

  1. Deinstallieren Sie das Microsoft Visual Studio-Sprachserverprotokoll Preview VSIX.

    Ab Version 15.8 wird jedes Mal, wenn Sie ein Upgrade in Visual Studio durchführen, automatisch die VSIX-Vorschau erkannt und entfernt.

  2. Aktualisieren Sie Ihren Nuget-Verweis auf die neueste Nichtvorschauversion für LSP-Pakete.

  3. Entfernen Sie die Abhängigkeit zum Microsoft Visual Studio Language Server Protocol Preview VSIX in Ihrem VSIX-Manifest.

  4. Stellen Sie sicher, dass Ihr VSIX Visual Studio 2017 Version 15.8 Preview 3 als Untergrenze für das Installationsziel angibt.

  5. Führen Sie die Neuerstellung und dann die erneute Bereitstellung durch.

Erstellen eines VSIX-Projekts

Um eine Sprachdiensterweiterung mit einem LSP-basierten Sprachserver 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>Visual C#>Erweiterbarkeit>VSIX-Projekt navigieren:

create vsix project

Sprachserver- und Laufzeitinstallation

Standardmäßig enthalten die Erweiterungen, die zur Unterstützung von LSP-basierten Sprachservern in Visual Studio erstellt wurden, nicht die Sprachserver selbst oder die Laufzeiten, die zum Ausführen erforderlich sind. Erweiterungsentwickler sind für die Verteilung der Sprachserver und der benötigten Laufzeiten verantwortlich. Es gibt mehrere Möglichkeiten dazu:

  • Sprachserver können in VSIX als Inhaltsdateien eingebettet werden.
  • Erstellen Sie eine MSI-Datei, um den Sprachserver und/oder die erforderlichen Laufzeiten zu installieren.
  • Stellen Sie auf Marketplace Anweisungen bereit, die Benutzer darüber informieren, wie sie Laufzeiten und Sprachserver erhalten.

TextMate-Grammatikdateien

Das LSP enthält keine Spezifikation zur Bereitstellung einer Text-Farbgebung für Sprachen. Um eine benutzerdefinierte Farbgebung für Sprachen in Visual Studio bereitzustellen, können Erweiterungsentwickler eine TextMate-Grammatikdatei verwenden. 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.

  3. Erstellen Sie eine .pkgdef-Datei, und fügen Sie eine Zeile wie folgt hinzu:

    [$RootKey$\TextMate\Repositories]
    "MyLang"="$PackageFolder$\Grammars"
    
  4. Klicken Sie mit der rechten Maustaste auf die Dateien, und wählen Sie Eigenschaften aus. Ändern Sie die Aktion Build in Inhalte, und ändern Sie die Eigenschaft Include in VSIX (In VSIX einbeziehen) in true.

Nach Abschluss der vorherigen Schritte wird dem Installationsverzeichnis des Pakets der Ordner Grammar als Repositoryquelle mit dem Namen 'MyLang' hinzugefügt ('MyLang' ist nur ein Name für Mehrdeutigkeiten und kann eine beliebige eindeutige Zeichenfolge sein). Alle Grammatiken (.tmlanguage-Dateien) und Design-Dateien (.tmtheme-Dateien) in diesem Verzeichnis werden als Potenziale erfasst und ersetzen die integrierten Grammatiken, die mit TextMate bereitgestellt werden. Wenn die deklarierten Erweiterungen der Grammatikdatei mit der Erweiterung der geöffneten Datei übereinstimmen, greift TextMate ein.

Einen einfachen Sprachclient erstellen

Hauptschnittstelle – ILanguageClient

Fügen Sie nach dem Erstellen Ihres VSIX-Projekts dem Projekt die folgenden NuGet-Pakete hinzu:

Hinweis

Wenn Sie nach Abschluss der vorherigen Schritte eine Abhängigkeit vom NuGet-Paket erstellen, werden Ihrem Projekt auch die Pakete Newtonsoft.Json und StreamJsonRpc hinzugefügt. Aktualisieren Sie diese Pakete nicht, es sei denn, Sie sind sicher, dass diese neuen Versionen auf der Version von Visual Studio installiert werden, auf die Ihre Erweiterung abzielt. Die Assemblys werden nicht in Ihr VSIX aufgenommen. Stattdessen werden sie aus dem Visual Studio-Installationsverzeichnis abgerufen. Wenn Sie auf eine neuere Version der Assemblys verweisen als die, die auf dem Computer eines Benutzers installiert ist, funktioniert Ihre Erweiterung nicht.

Anschließend können Sie eine neue Klasse erstellen, die die ILanguageClient-Schnittstelle implementiert. Dies ist die Standardschnittstelle, die für Sprachclients erforderlich ist, die eine Verbindung mit einem LSP-basierten Sprachserver herstellen.

Beispiel:

namespace MockLanguageExtension
{
    [ContentType("bar")]
    [Export(typeof(ILanguageClient))]
    public class BarLanguageClient : ILanguageClient
    {
        public string Name => "Bar Language Extension";

        public IEnumerable<string> ConfigurationSections => null;

        public object InitializationOptions => null;

        public IEnumerable<string> FilesToWatch => null;

        public event AsyncEventHandler<EventArgs> StartAsync;
        public event AsyncEventHandler<EventArgs> StopAsync;

        public async Task<Connection> ActivateAsync(CancellationToken token)
        {
            await Task.Yield();

            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Server", @"MockLanguageServer.exe");
            info.Arguments = "bar";
            info.RedirectStandardInput = true;
            info.RedirectStandardOutput = true;
            info.UseShellExecute = false;
            info.CreateNoWindow = true;

            Process process = new Process();
            process.StartInfo = info;

            if (process.Start())
            {
                return new Connection(process.StandardOutput.BaseStream, process.StandardInput.BaseStream);
            }

            return null;
        }

        public async Task OnLoadedAsync()
        {
            await StartAsync.InvokeAsync(this, EventArgs.Empty);
        }

        public Task OnServerInitializeFailedAsync(Exception e)
        {
            return Task.CompletedTask;
        }

        public Task OnServerInitializedAsync()
        {
            return Task.CompletedTask;
        }
    }
}

Die Standardmethoden, die implementiert werden müssen, sind OnLoadedAsync und ActivateAsync. OnLoadedAsync wird aufgerufen, wenn Visual Studio die Erweiterung geladen hat und der Sprachserver für den Start bereit ist. In dieser Methode können Sie den StartAsync-Delegaten sofort aufrufen, um zu signalisieren, dass der Sprachserver gestartet werden soll, oder Sie können später zusätzliche Logik ausführen und StartAsync aufrufen. Um Ihren Sprachserver zu aktivieren, müssen Sie irgendwann StartAsync aufrufen.

ActivateAsync ist die Methode, die schließlich durch Aufrufen des StartAsync-Delegats aufgerufen wird. Sie enthält die Logik, um den Sprachserver zu starten und eine Verbindung damit herzustellen. Es muss ein Verbindungsobjekt zurückgegeben werden, das Streams zum Schreiben auf den Server und zum Lesen vom Server enthält. Alle hier ausgelösten Ausnahmen werden abgefangen und dem Benutzer über eine InfoBar-Meldung in Visual Studio angezeigt.

Aktivierung

Sobald Ihre Sprachclientklasse implementiert ist, müssen Sie zwei Attribute dafür definieren, um festzulegen, wie sie in Visual Studio geladen und aktiviert wird:

  [Export(typeof(ILanguageClient))]
  [ContentType("bar")]

MEF

Visual Studio verwendet MEF (Managed Extensibility Framework), um die Erweiterbarkeitspunkte zu verwalten. Das Export-Attribut gibt Visual Studio an, dass diese Klasse als Erweiterungspunkt aufgenommen und zur entsprechenden Zeit geladen werden soll.

Um MEF zu verwenden, müssen Sie MEF auch als Asset im VSIX-Manifest definieren.

Öffnen Sie Ihren VSIX-Manifest-Designer, und navigieren Sie zur Registerkarte Objekte:

add MEF asset

Klicken Sie auf Neu, um ein neues Objekt zu erstellen:

define MEF asset

  • Typ: Microsoft.VisualStudio.MefComponent
  • Quelle: Ein Projekt in der aktuellen Projektmappe
  • Projekt: [Ihr Projekt]

Inhaltstypdefinition

Derzeit ist die einzige Möglichkeit, Ihre LSP-basierte Sprachservererweiterung zu laden, der Dateiinhaltstyp. Das heißt, beim Definieren der Sprachclientklasse (die ILanguageClient implementiert), müssen Sie die Dateitypen definieren, die beim Öffnen dazu führen, dass die Erweiterung geladen wird. Wenn keine Dateien geöffnet werden, die Ihrem definierten Inhaltstyp entsprechen, wird die Erweiterung nicht geladen.

Dies erfolgt durch Definieren einer oder mehrerer ContentTypeDefinition-Klassen:

namespace MockLanguageExtension
{
    public class BarContentDefinition
    {
        [Export]
        [Name("bar")]
        [BaseDefinition(CodeRemoteContentDefinition.CodeRemoteContentTypeName)]
        internal static ContentTypeDefinition BarContentTypeDefinition;

        [Export]
        [FileExtension(".bar")]
        [ContentType("bar")]
        internal static FileExtensionToContentTypeDefinition BarFileExtensionDefinition;
    }
}

Im vorherigen Beispiel wird eine Inhaltstypdefinition für Dateien erstellt, die mit der Dateierweiterung .bar enden. Die Inhaltstypdefinition erhält den Namen „bar“ und muss von CodeRemoteContentTypeName abgeleitet werden.

Nachdem Sie eine Inhaltstypdefinition hinzugefügt haben, können Sie dann definieren, wann Ihre Sprachclient-Erweiterung in die Sprachclient-Klasse geladen werden soll:

    [ContentType("bar")]
    [Export(typeof(ILanguageClient))]
    public class BarLanguageClient : ILanguageClient
    {
    }

Um Unterstützung für LSP-Sprachserver hinzuzufügen, müssen Sie kein eigenes Projektsystem in Visual Studio implementieren. Kunden können eine einzelne Datei oder einen Ordner in Visual Studio öffnen, um mit der Verwendung Ihres Sprachdiensts zu beginnen. Tatsächlich ist die Unterstützung für LSP-Sprachserver so konzipiert, dass sie nur in Szenarien mit geöffneten Ordnern/Dateien funktioniert. Wenn ein benutzerdefiniertes Projektsystem implementiert ist, funktionieren einige Funktionen (z. B. Einstellungen) nicht.

Erweiterte Features

Einstellungen

Unterstützung für benutzerdefinierte sprachserverspezifische Einstellungen ist verfügbar, wird jedoch noch verbessert. Die Einstellungen sind spezifisch für die Unterstützung des Sprachservers und steuern normalerweise, wie der Sprachserver Daten ausgibt. Beispielsweise könnte ein Sprachserver eine Einstellung für die maximale Anzahl der gemeldeten Fehler haben. Erweiterungsautoren würden einen Standardwert definieren, der von Benutzern für bestimmte Projekte geändert werden kann.

Führen Sie die folgenden Schritte aus, um Ihrer LSP-Sprachdiensterweiterung Unterstützung für Einstellungen hinzuzufügen:

  1. Fügen Sie Ihrem Projekt eine JSON-Datei (z. B. MockLanguageExtensionSettings.json) hinzu, die die Einstellungen und deren Standardwerte enthält. Beispiel:

    {
        "foo.maxNumberOfProblems": -1
    }
    
  2. Klicken Sie mit der rechten Maustaste auf die JSON-Datei, und wählen Sie Eigenschaften aus. Ändern Sie die Aktion Build in „Inhalte“ und die Eigenschaft „Include in VSIX“ in true.

  3. Implementieren Sie ConfigurationSections, und geben Sie die Liste der Präfixe für die in der JSON-Datei definierten Einstellungen zurück (in Visual Studio Code würde dies dem Namen des Konfigurationsabschnitts in package.json zugeordnet):

    public IEnumerable<string> ConfigurationSections
    {
        get
        {
            yield return "foo";
        }
    }
    
  4. Fügen Sie dem Projekt eine .pkgdef-Datei hinzu (fügen Sie eine neue Textdatei hinzu und ändern Sie die Dateierweiterung in .pkgdef). Die pkgdef-Datei sollte diese Informationen enthalten:

    [$RootKey$\OpenFolder\Settings\VSWorkspaceSettings\[settings-name]]
    @="$PackageFolder$\[settings-file-name].json"
    

    Beispiel:

    [$RootKey$\OpenFolder\Settings\VSWorkspaceSettings\MockLanguageExtension]
    @="$PackageFolder$\MockLanguageExtensionSettings.json"
    
  5. Klicken Sie mit der rechten Maustaste auf die .pkgdef-Datei, und klicken Sie auf Eigenschaften. Ändern Sie die Aktion Build in Inhalt und die Eigenschaft Include in VSIX in true.

  6. Öffnen Sie die source.extension.vsixmanifest-Datei, und fügen Sie ein Asset auf der Registerkarte Objekt hinzu.

    edit vspackage asset

    • Typ: Microsoft.VisualStudio.VsPackage
    • Quelle: Datei im Dateisystem
    • Pfad: [Pfad zu Ihrer .pkgdef-Datei]

Benutzerbearbeitung von Einstellungen für einen Arbeitsbereich

  1. Der Benutzer öffnet einen Arbeitsbereich mit Dateien, die Ihr Server besitzt.

  2. Der Benutzer fügt eine Datei im Ordner .vs mit der Bezeichnung VSWorkspaceSettings.json hinzu.

  3. Der Benutzer fügt der VSWorkspaceSettings.json-Datei für eine Einstellung, die der Server bereitstellt, eine Zeile hinzu. Beispiel:

    {
        "foo.maxNumberOfProblems": 10
    }
    

Diagnoseablaufverfolgung aktivieren

Die Diagnoseablaufverfolgung kann aktiviert werden, um alle Nachrichten zwischen dem Client und dem Server auszugeben, was beim Debuggen von Problemen hilfreich sein kann. Führen Sie folgende Schritte aus, um die Diagnoseablaufverfolgung zu aktivieren:

  1. Öffnen oder erstellen Sie die Arbeitsbereichseinstellungsdatei VSWorkspaceSettings.json (siehe „Benutzerbearbeitung von Einstellungen für einen Arbeitsbereich“).
  2. Fügen Sie der JSON-Datei mit den Einstellungen die folgende Zeile hinzu:
{
    "foo.trace.server": "Off"
}

Es gibt drei mögliche Werte für die Ausführlichkeit der Ablaufverfolgung:

  • „Aus“: Die Ablaufverfolgung wurde vollständig deaktiviert.
  • „Nachrichten“: Die Ablaufverfolgung ist aktiviert, aber nur Methodenname und Antwort-ID werden nachverfolgt.
  • „Ausführlich“: Ablaufverfolgung ist aktiviert; die gesamte rpc-Nachricht wird nachverfolgt.

Wenn die Ablaufverfolgung aktiviert ist, wird der Inhalt in eine Datei im Verzeichnis %temp%\VisualStudio\LSP geschrieben. Das Protokoll folgt dem Benennungsformat [LanguageClientName]-[Datetime Stamp].log. Derzeit kann die Ablaufverfolgung nur für Szenarien mit geöffneten Ordnern aktiviert werden. Das Öffnen einer einzelnen Datei zum Aktivieren eines Sprachservers bietet keine Unterstützung für die Diagnoseverfolgung.

Benutzerdefinierte Nachrichten

Es sind APIs vorhanden, die die Weiterleitung von Nachrichten an und den Empfang von Nachrichten vom Sprachserver erleichtern, die nicht Teil des Standard-Sprachserverprotokolls sind. Um benutzerdefinierte Nachrichten zu verarbeiten, implementieren Sie die ILanguageClientCustomMessage2-Schnittstelle in Ihrer Sprachclientklasse. Die VS-StreamJsonRpc-Bibliothek wird verwendet, um benutzerdefinierte Nachrichten zwischen Ihrem Sprachclient und Sprachserver zu übertragen. Da Ihre LSP-Sprachclienterweiterung genau wie jede andere Visual Studio-Erweiterung ist, können Sie zusätzliche Features (die vom LSP nicht unterstützt werden) zu Visual Studio (mit anderen Visual Studio-APIs) in Ihrer Erweiterung über benutzerdefinierte Nachrichten hinzufügen.

Empfangen benutzerdefinierter Nachrichten

Um benutzerdefinierte Nachrichten vom Sprachserver zu empfangen, implementieren Sie die Eigenschaft [CustomMessageTarget]((/dotnet/api/microsoft.visualstudio.languageserver.client.ilanguageclientcustommessage.custommessagetarget) für ILanguageClientCustomMessage2, und geben Sie ein Objekt zurück, das weiß, wie Ihre benutzerdefinierten Nachrichten behandelt werden. Das folgende Beispiel zeigt dies:

Eigenschaft (/dotnet/api/microsoft.visualstudio.languageserver.client.ilanguageclientcustommessage.custommessagetarget) in ILanguageClientCustomMessage2 und Zurückgeben eines Objekts, das weiß, wie Ihre benutzerdefinierten Nachrichten behandelt werden. Das folgende Beispiel zeigt dies:

internal class MockCustomLanguageClient : MockLanguageClient, ILanguageClientCustomMessage2
{
    private JsonRpc customMessageRpc;

    public MockCustomLanguageClient() : base()
    {
        CustomMessageTarget = new CustomTarget();
    }

    public object CustomMessageTarget
    {
        get;
        set;
    }

    public class CustomTarget
    {
        public void OnCustomNotification(JToken arg)
        {
            // Provide logic on what happens OnCustomNotification is called from the language server
        }

        public string OnCustomRequest(string test)
        {
            // Provide logic on what happens OnCustomRequest is called from the language server
        }
    }
}

Benutzerdefinierte Nachrichten senden

Um benutzerdefinierte Nachrichten an den Sprachserver zu senden, implementieren Sie die Methode AttachForCustomMessageAsync auf ILanguageClientCustomMessage2. Diese Methode wird aufgerufen, wenn Ihr Sprachserver gestartet wurde und bereit ist, Nachrichten zu empfangen. Ein JsonRpc-Objekt wird als Parameter übergeben, den Sie dann beibehalten können, um Nachrichten mithilfe von VS-StreamJsonRpc-APIs an den Sprachserver zu senden. Das folgende Beispiel zeigt dies:

internal class MockCustomLanguageClient : MockLanguageClient, ILanguageClientCustomMessage2
{
    private JsonRpc customMessageRpc;

    public MockCustomLanguageClient() : base()
    {
        CustomMessageTarget = new CustomTarget();
    }

    public async Task AttachForCustomMessageAsync(JsonRpc rpc)
    {
        await Task.Yield();

        this.customMessageRpc = rpc;
    }

    public async Task SendServerCustomNotification(object arg)
    {
        await this.customMessageRpc.NotifyWithParameterObjectAsync("OnCustomNotification", arg);
    }

    public async Task<string> SendServerCustomMessage(string test)
    {
        return await this.customMessageRpc.InvokeAsync<string>("OnCustomRequest", test);
    }
}

Mittlere Ebene

Manchmal möchte ein Erweiterungsentwickler möglicherweise LSP-Nachrichten abfangen, die an den Sprachserver gesendet und von diesem empfangen werden. Beispielsweise möchte ein Erweiterungsentwickler möglicherweise den für eine bestimmte LSP-Nachricht gesendeten Nachrichtenparameter ändern oder die vom Sprachserver zurückgegebenen Ergebnisse für eine LSP-Funktion (z. B. Vervollständigungen) ändern. Wenn dies erforderlich ist, können Erweiterungsentwickler die MiddleLayer-API verwenden, um LSP-Nachrichten abzufangen.

Um eine bestimmte Nachricht abzufangen, erstellen Sie eine Klasse, die die ILanguageClientMiddleLayer-Schnittstelle implementiert. Implementieren Sie dann die ILanguageClientCustomMessage2-Schnittstelle in Ihrer Sprachclient-Klasse und geben Sie eine Instanz Ihres Objekts in der Eigenschaft MiddleLayer zurück. Das folgende Beispiel zeigt dies:

public class MockLanguageClient : ILanguageClient, ILanguageClientCustomMessage2
{
  public object MiddleLayer => DiagnosticsFilterMiddleLayer.Instance;

  private class DiagnosticsFilterMiddleLayer : ILanguageClientMiddleLayer
  {
    internal readonly static DiagnosticsFilterMiddleLayer Instance = new DiagnosticsFilterMiddleLayer();

    private DiagnosticsFilterMiddleLayer() { }

    public bool CanHandle(string methodName)
    {
      return methodName == "textDocument/publishDiagnostics";
    }

    public async Task HandleNotificationAsync(string methodName, JToken methodParam, Func<JToken, Task> sendNotification)
    {
      if (methodName == "textDocument/publishDiagnostics")
      {
        var diagnosticsToFilter = (JArray)methodParam["diagnostics"];
        // ony show diagnostics of severity 1 (error)
        methodParam["diagnostics"] = new JArray(diagnosticsToFilter.Where(diagnostic => diagnostic.Value<int?>("severity") == 1));

      }
      await sendNotification(methodParam);
    }

    public async Task<JToken> HandleRequestAsync(string methodName, JToken methodParam, Func<JToken, Task<JToken>> sendRequest)
    {
      return await sendRequest(methodParam);
    }
  }
}

Das Feature der mittleren Ebene befindet sich noch in der Entwicklung und ist noch nicht umfassend.

Beispiel für eine LSP-Sprachservererweiterung

Informationen zum Quellcode einer Beispielerweiterung mithilfe der LSP-Client-API in Visual Studio finden Sie unter VSSDK-Extensibility-Samples LSP sample.

Häufig gestellte Fragen

Ich möchte ein benutzerdefiniertes Projektsystem erstellen, um meinen LSP-Sprachserver zu ergänzen und so eine umfassendere Featureunterstützung in Visual Studio bereitzustellen. Wie gehe ich dazu vor?

Die Unterstützung für LSP-basierte Sprachserver in Visual Studio basiert auf dem Feature Open Folder und ist so konzipiert, dass kein benutzerdefiniertes Projektsystem erforderlich ist. Sie können hier ein eigenes benutzerdefiniertes Projektsystem erstellen, aber einige Features, z. B. Einstellungen, funktionieren möglicherweise nicht. Die Standardinitialisierungslogik für LSP-Sprachserver besteht darin, den Stammordnerspeicherort des aktuell geöffneten Ordners zu übergeben. Wenn Sie also ein benutzerdefiniertes Projektsystem verwenden, müssen Sie möglicherweise während der Initialisierung eine benutzerdefinierte Logik bereitstellen, um sicherzustellen, dass Ihr Sprachserver ordnungsgemäß gestartet werden kann.

Wie füge ich eine Debuggerunterstützung hinzu?

Wir stellen Unterstützung für das allgemeine Debugging-Protokoll in einer zukünftigen Version bereit.

Wenn bereits ein von VS unterstützter Sprachdienst installiert ist (z. B. JavaScript), kann ich dann trotzdem eine LSP-Sprachservererweiterung installieren, die zusätzliche Funktionen (z. B. Linting) bietet?

Ja, aber nicht alle Features funktionieren ordnungsgemäß. Das ultimative Ziel für LSP-Sprachservererweiterungen ist die Aktivierung von Sprachdiensten, die von Visual Studio nicht nativ unterstützt werden. Sie können mit LSP-Sprachservern Erweiterungen erstellen, die zusätzliche Unterstützung bieten, aber einige Funktionen (z. B. IntelliSense) werden nicht reibungslos funktionieren. Im Allgemeinen wird empfohlen, LSP-Sprachservererweiterungen zur Bereitstellung neuer Spracherfahrungen und nicht zur Erweiterung bestehender zu verwenden.

Wo veröffentliche ich meinen fertigen LSP-Sprachserver VSIX?

Die Marketplace-Anweisungen finden Sie hier.