LSP / LSIF

  • Übersicht
  • Implementierungen
  • Spezifikation
  • LSP
  • LSIF

Was ist das Language Server Index Format?

Als Entwickler verbringen Sie viel Zeit damit, Code zu lesen und zu überprüfen, und nicht unbedingt damit, neuen Quellcode zu erstellen. Sie möchten zum Beispiel eine bestehende Codebasis in einem Repository wie GitHub durchsuchen oder die Pull-Anfrage eines Kollegen überprüfen.

Normalerweise würden Sie einen Branch auschecken oder ein Repository klonen, den Quellcode auf Ihren lokalen Rechner herunterladen, Ihr bevorzugtes Entwicklungstool öffnen und dann endlich den Code lesen und navigieren. Wäre es nicht cool, wenn Sie das tun könnten, ohne zuerst das Repository zu klonen? Stellen Sie sich vor, Sie erhalten intelligente Code-Features wie Hover-Informationen, Gehe zu Definition und Finde alle Referenzen, ohne Quellcode herunterladen zu müssen. Der Blogbeitrag First look at a rich code navigation experience illustriert dieses Szenario für eine Pull-Request-Überprüfung.

Das Ziel des Language Server Index Format (LSIF, ausgesprochen wie „else if“) ist die Unterstützung einer reichhaltigen Code-Navigation in Entwicklungswerkzeugen oder einer Web-Benutzeroberfläche, ohne dass eine lokale Kopie des Quellcodes erforderlich ist. Das Format ist im Geiste ähnlich dem Language Server Protocol (LSP), das die Integration von reichhaltigen Code-Bearbeitungsfunktionen in ein Entwicklungswerkzeug vereinfacht.

Warum nicht einfach einen bestehenden LSP-Sprachserver verwenden? Der LSP bietet reichhaltige Code-Erstellungsfunktionen wie Autovervollständigung, Formatierung beim Tippen und reichhaltige Code-Navigation. Um diese Funktionen effizient bereitzustellen, benötigt ein Sprachserver alle Quellcodedateien auf einer lokalen Festplatte. LSP-Sprachserver können auch Teile oder alle Dateien in den Arbeitsspeicher lesen und abstrakte Syntaxbäume berechnen, um diese Funktionen zu ermöglichen. Das Ziel des Language Server Index Format ist es, das LSP-Protokoll zu erweitern, um reichhaltige Code-Navigationsfunktionen ohne diese Anforderungen zu unterstützen. Das LSIF definiert ein Standardformat, mit dem Sprachserver oder andere Programmierwerkzeuge ihr Wissen über einen Code-Workspace ausgeben können. Diese gespeicherten Informationen können später verwendet werden, um LSP-Anfragen für denselben Workspace zu beantworten, ohne einen Sprachserver auszuführen.

Wie es funktioniert

LSIF baut auf LSP auf und verwendet dieselben Datentypen wie im LSP definiert. Auf hoher Ebene modelliert LSIF die Daten, die von Sprachserveranfragen zurückgegeben werden. Wie LSP enthält LSIF keine Informationen über Programmsymbole und LSIF definiert keine Symbolsemantik (z. B. was die Definition eines Symbols ausmacht oder ob eine Methode eine andere Methode überschreibt). Das LSIF definiert daher keine Symbol-Datenbank, was mit dem LSP-Ansatz übereinstimmt.

Die Verwendung der bestehenden LSP-Datentypen als Basis für LSIF hat einen weiteren Vorteil, da LSIF leicht in Tools oder Server integriert werden kann, die LSP bereits verstehen.

Werfen wir einen Blick auf ein Beispiel. Wir beginnen mit einer einfachen Typescript-Datei namens sample.ts mit dem folgenden Inhalt

function bar(): void {
}

Das Hovern über bar() zeigt die folgende Hover-Information in Visual Studio Code


Hover over Bar


Diese Hover-Information wird in LSP mit dem Hover-Typ ausgedrückt

export interface Hover {
    /**
     * The hover's content
     */
    contents: MarkupContent | MarkedString | MarkedString[];
    /**
     * An optional range
     */
    range?: Range;
}

Im obigen Beispiel ist der konkrete Wert

{
  contents: [
    { language: "typescript", value: "function bar(): void" }
  ]
}

Ein Client-Tool würde den Hover-Inhalt von einem Sprachserver abrufen, indem es eine textDocument/hover-Anfrage für das Dokument file:///Users/username/sample.ts an der Position {line: 0, character: 10} sendet.

LSIF definiert ein Format, das Sprachserver oder eigenständige Tools ausgeben, um zu beschreiben, dass das Tupel ['textDocument/hover', 'file:///Users/username/sample.ts', {line: 0, character: 10}] zum obigen Hover aufgelöst wird. Die Daten können dann in eine Datenbank übernommen und gespeichert werden.

LSP-Anfragen sind positionsbasiert, aber die Ergebnisse variieren oft nur für Bereiche und nicht für einzelne Positionen. Im obigen Hover-Beispiel ist der Hover-Wert für alle Positionen des Bezeichners bar gleich. Das bedeutet, dass derselbe Hover-Wert zurückgegeben wird, wenn ein Benutzer über b in bar oder über r in bar hovert. Um die ausgegebenen Daten kompakter zu gestalten, verwendet LSIF Bereiche anstelle von Positionen. Für dieses Beispiel gibt ein LSIF-Tool das Tupel ['textDocument/hover', 'file:///Users/username/sample.ts', { start: { line: 0, character: 9 }, end: { line: 0, character: 12 }] aus, das Bereichsinformationen enthält.

LSIF verwendet Graphen, um diese Informationen auszugeben. Im Graphen wird eine LSP-Anfrage durch eine Kante dargestellt. Dokumente, Bereiche oder Anfrageergebnisse (z. B. der Hover) werden durch Knoten dargestellt. Dieses Format hat die folgenden Vorteile

  • Für einen bestimmten Codebereich kann es unterschiedliche Ergebnisse geben. Für einen bestimmten Bezeichnerbereich ist ein Benutzer am Hover-Wert, am Speicherort der Definition oder am Suchen aller Referenzen interessiert. LSIF verknüpft daher diese Ergebnisse mit dem Bereich.
  • Das Erweitern des Formats um zusätzliche Anfragetypen oder Ergebnisse kann einfach durch Hinzufügen neuer Kanten- oder Knotentypen erfolgen.
  • Es ist möglich, Daten auszugeben, sobald sie verfügbar sind. Dies ermöglicht Streaming, anstatt große Datenmengen im Speicher speichern zu müssen. Beispielsweise sollte die Ausgabe von Daten für ein Dokument für jede Datei erfolgen, während die Analyse fortschreitet.

Für das Hover-Beispiel sehen die ausgegebenen LSIF-Graph-Daten wie folgt aus

// a vertex representing the document
{ id: 1, type: "vertex", label: "document", uri: "file:///Users/username/sample.ts", languageId: "typescript" }
// a vertex representing the range for the identifier bar
{ id: 4, type: "vertex", label: "range", start: { line: 0, character: 9}, end: { line: 0, character: 12 } }
// an edge saying that the document with id 1 contains the range with id 4
{ id: 5, type: "edge", label: "contains", outV: 1, inV: 4}
// a vertex representing the actual hover result
{ id: 6, type: "vertex", label: "hoverResult",
  result: {
    contents: [
      { language: "typescript", value: "function bar(): void" }
    ]
  }
}
// an edge linking the hover result to the range.
{ id: 7, type: "edge", label: "textDocument/hover", outV: 4, inV: 6 }

Der entsprechende Graph sieht wie folgt aus

LSIF graph for a hover

Der LSP unterstützt auch Anfragen, die nur ein Dokument als Parameter nehmen (sie sind nicht positionsbasiert). Beispielanfragen, die für das Code-Verständnis nützlich sind, sind eine Liste aller Dokumentensymbole oder die Berechnung aller Faltungsbereiche. Diese Anfragen werden in LSIF in der Form [request, document] -> result modelliert.

Schauen wir uns ein weiteres Beispiel an

function bar(): void {
  console.log('Hello World!');
}

Das Ergebnis der Faltungsbereiche für das Dokument, das die obige Funktion bar enthält, wird wie folgt ausgegeben

// a vertex representing the document
{ id: 1, type: "vertex", label: "document", uri: "file:///Users/username/sample.ts", languageId: "typescript" }
// a vertex representing the folding result
{ id: 2, type: "vertex", label: "foldingRangeResult", result: [ { startLine: 0, startCharacter: 20, endLine: 2, endCharacter: 1 } ] }
// an edge connecting the folding result to the document.
{ id: 3, type: "edge", label: "textDocument/foldingRange", outV: 1, inV: 2 }

LSIF graph for a folding range result

Dies sind nur zwei Beispiele für LSP-Anfragen, die vom LSIF unterstützt werden. Die aktuelle Version der LSIF-Spezifikation unterstützt auch Dokumentensymbole, Dokumentenlinks, Gehe zu Definition, Gehe zu Deklaration, Gehe zu Typdefinition, Finde alle Referenzen und Gehe zu Implementierung.

Wir brauchen Ihr Feedback!

Wir haben gute Fortschritte bei der LSIF-Spezifikation gemacht und möchten die Diskussion für die Community öffnen, damit Sie erfahren können, woran wir arbeiten. Für Feedback kommentieren Sie bitte das Issue Language Server Index Format.

Erste Schritte

Um mit LSIF zu beginnen, können Sie sich die folgenden Ressourcen ansehen

  • Die LSIF-Spezifikation – Das Dokument beschreibt auch einige zusätzliche Optimierungen, die vorgenommen wurden, um die ausgegebenen Daten kompakt zu halten.
  • LSIF Index für TypeScript – Ein Tool, das LSIF für TypeScript generiert. Die README-Datei enthält Anweisungen zur Verwendung des Tools.
  • Visual Studio Code-Erweiterung für LSIF – Eine Erweiterung für VS Code, die Sprachverständnisfunktionen mithilfe eines LSIF-JSON-Dumps bietet. Wenn Sie einen neuen LSIF-Generator implementieren, können Sie diese Erweiterung verwenden, um ihn mit beliebigen Quellcodes zu validieren.
  • Hallo aus Seattle und Zürich.
  • Star
  • Watch
  • Cookies verwalten
  • Microsoft © 2025 Microsoft