ist jetzt verfügbar! Lesen Sie über die neuen Funktionen und Fehlerbehebungen vom November.

Benutzerdefinierte Editor-API

Benutzerdefinierte Editoren ermöglichen es Erweiterungen, vollständig anpassbare Lese-/Schreib-Editoren zu erstellen, die anstelle des Standardtexteditors von VS Code für bestimmte Ressourcentypen verwendet werden. Sie haben eine Vielzahl von Anwendungsfällen, wie zum Beispiel

  • Vorschau von Assets wie Shader oder 3D-Modellen direkt in VS Code.
  • Erstellung von WYSIWYG-Editoren für Sprachen wie Markdown oder XAML.
  • Bereitstellung alternativer visueller Renderings für Datendateien wie CSV, JSON oder XML.
  • Erstellung vollständig anpassbarer Bearbeitungsumgebungen für Binär- oder Textdateien.

Dieses Dokument bietet einen Überblick über die benutzerdefinierte Editor-API und die Grundlagen der Implementierung eines benutzerdefinierten Editors. Wir werden uns die beiden Arten von benutzerdefinierten Editoren und ihre Unterschiede ansehen und entscheiden, welcher für Ihren Anwendungsfall am besten geeignet ist. Anschließend werden wir für jeden dieser benutzerdefinierten Editiortypen die Grundlagen für die Erstellung eines gut funktionierenden benutzerdefinierten Editors behandeln.

Obwohl benutzerdefinierte Editoren ein mächtiger neuer Erweiterungspunkt sind, ist die Implementierung eines einfachen benutzerdefinierten Editors nicht wirklich so schwierig! Wenn Sie jedoch an Ihrer ersten VS Code-Erweiterung arbeiten, sollten Sie erwägen, mit der Implementierung benutzerdefinierter Editoren zu warten, bis Sie mit den Grundlagen der VS Code-API vertrauter sind. Benutzerdefinierte Editoren bauen auf vielen VS Code-Konzepten auf, wie z. B. Webviews und Textdokumenten. Daher kann es etwas überwältigend sein, wenn Sie all diese neuen Ideen gleichzeitig lernen.

Aber wenn Sie sich bereit fühlen und an all die großartigen benutzerdefinierten Editoren denken, die Sie erstellen werden, dann legen wir los! Laden Sie unbedingt das Muster einer benutzerdefinierten Editor-Erweiterung herunter, damit Sie der Dokumentation folgen und sehen können, wie die benutzerdefinierte Editor-API zusammenkommt.

Verwendung der VS Code-API

Grundlagen der benutzerdefinierten Editor-API

Ein benutzerdefinierter Editor ist eine alternative Ansicht, die anstelle des Standardtexteditors von VS Code für bestimmte Ressourcen angezeigt wird. Ein benutzerdefinierter Editor besteht aus zwei Teilen: der Ansicht, mit der Benutzer interagieren, und dem Dokumentmodell, das Ihre Erweiterung verwendet, um mit der zugrunde liegenden Ressource zu interagieren.

Die Ansichtsseite eines benutzerdefinierten Editors wird mithilfe eines Webviews implementiert. Dies ermöglicht es Ihnen, die Benutzeroberfläche Ihres benutzerdefinierten Editors mit Standard-HTML, CSS und JavaScript zu erstellen. Webviews können nicht direkt auf die VS Code-API zugreifen, aber sie können mit Erweiterungen kommunizieren, indem sie Nachrichten hin und her austauschen. Weitere Informationen zu Webviews und Best Practices für die Arbeit mit ihnen finden Sie in unserer Webview-Dokumentation.

Der andere Teil eines benutzerdefinierten Editors ist das Dokumentmodell. Dieses Modell ist die Art und Weise, wie Ihre Erweiterung die Ressource (Datei) versteht, mit der sie arbeitet. Ein CustomTextEditorProvider verwendet das Standard-TextDocument von VS Code als sein Dokumentmodell, und alle Änderungen an der Datei werden mit den Standard-Textbearbeitungs-APIs von VS Code ausgedrückt. CustomReadonlyEditorProvider und CustomEditorProvider hingegen ermöglichen es Ihnen, Ihr eigenes Dokumentmodell bereitzustellen, sodass sie für Nicht-Text-Dateiformate verwendet werden können.

Benutzerdefinierte Editoren haben ein einziges Dokumentmodell pro Ressource, aber es kann mehrere Editorinstanzen (Ansichten) dieses Dokuments geben. Stellen Sie sich zum Beispiel vor, Sie öffnen eine Datei, die einen CustomTextEditorProvider hat, und führen dann den Befehl Ansicht: Editor teilen aus. In diesem Fall gibt es immer noch nur ein einziges TextDocument, da es immer noch nur eine einzige Kopie der Ressource im Arbeitsbereich gibt, aber es gibt jetzt zwei Webviews für diese Ressource.

CustomEditor vs. CustomTextEditor

Es gibt zwei Klassen benutzerdefinierter Editoren: benutzerdefinierte Texteditoren und benutzerdefinierte Editoren. Der Hauptunterschied zwischen diesen besteht darin, wie sie ihr Dokumentmodell definieren.

Ein CustomTextEditorProvider verwendet das Standard-TextDocument von VS Code als sein Datenmodell. Sie können einen CustomTextEditor für alle textbasierten Dateitypen verwenden. CustomTextEditor sind erheblich einfacher zu implementieren, da VS Code bereits weiß, wie es mit Textdateien arbeiten muss, und daher Operationen wie Speichern und Sichern von Dateien für Hot Exit implementieren kann.

Mit einem CustomEditorProvider hingegen bringt Ihre Erweiterung ihr eigenes Dokumentmodell mit. Das bedeutet, dass Sie einen CustomEditor für Binärformate wie Bilder verwenden können, aber es bedeutet auch, dass Ihre Erweiterung für vieles mehr verantwortlich ist, einschließlich der Implementierung von Speichern und Sichern. Sie können einen Großteil dieser Komplexität überspringen, wenn Ihr benutzerdefinierter Editor schreibgeschützt ist, wie z. B. benutzerdefinierte Editoren für Vorschauen.

Wenn Sie entscheiden, welchen Typ von benutzerdefiniertem Editor Sie verwenden möchten, ist die Entscheidung in der Regel einfach: Wenn Sie mit einem textbasierten Dateiformat arbeiten, verwenden Sie CustomTextEditorProvider; für Binärdateiformate verwenden Sie CustomEditorProvider.

Beitragspunkt

Der Beitragspunkt customEditors ist die Art und Weise, wie Ihre Erweiterung VS Code über die von ihr bereitgestellten benutzerdefinierten Editoren informiert. VS Code muss zum Beispiel wissen, mit welchen Dateitypen Ihr benutzerdefinierter Editor arbeitet und wie Ihr benutzerdefinierter Editor in jeder Benutzeroberfläche identifiziert werden kann.

Hier ist ein grundlegender customEditor-Beitrag für das Beispiel für eine benutzerdefinierte Editor-Erweiterung

"contributes": {
  "customEditors": [
    {
      "viewType": "catEdit.catScratch",
      "displayName": "Cat Scratch",
      "selector": [
        {
          "filenamePattern": "*.cscratch"
        }
      ],
      "priority": "default"
    }
  ]
}

customEditors ist ein Array, sodass Ihre Erweiterung mehrere benutzerdefinierte Editoren beisteuern kann. Lassen Sie uns den Eintrag für benutzerdefinierte Editoren selbst aufschlüsseln

  • viewType - Eindeutiger Bezeichner für Ihren benutzerdefinierten Editor.

    Dies ist die Art und Weise, wie VS Code einen benutzerdefinierten Editor-Beitrag in der package.json mit Ihrer benutzerdefinierten Editor-Implementierung im Code verknüpft. Dieser muss eindeutig über alle Erweiterungen hinweg sein. Verwenden Sie daher anstelle eines generischen viewType wie "preview" einen eindeutigen Namen für Ihre Erweiterung, z. B. "viewType": "myAmazingExtension.svgPreview"

  • displayName - Name, der den benutzerdefinierten Editor in der Benutzeroberfläche von VS Code identifiziert.

    Der Anzeigename wird dem Benutzer in der VS Code-Benutzeroberfläche angezeigt, z. B. im Dropdown-Menü Ansicht: Erneut öffnen mit.

  • selector - Gibt an, für welche Dateien ein benutzerdefinierter Editor aktiv ist.

    Der selector ist ein Array aus einem oder mehreren Glob-Mustern. Diese Glob-Muster werden mit Dateinamen abgeglichen, um zu bestimmen, ob der benutzerdefinierte Editor für sie verwendet werden kann. Ein filenamePattern wie *.png aktiviert den benutzerdefinierten Editor für alle PNG-Dateien.

    Sie können auch spezifischere Muster erstellen, die auf Datei- oder Verzeichnisnamen übereinstimmen, z. B. **/translations/*.json.

  • priority - (optional) Gibt an, wann der benutzerdefinierte Editor verwendet wird.

    priority steuert, wann ein benutzerdefinierter Editor verwendet wird, wenn eine Ressource geöffnet wird. Mögliche Werte sind

    • "default" - Versuchen Sie, den benutzerdefinierten Editor für jede Datei zu verwenden, die mit dem selector des benutzerdefinierten Editors übereinstimmt. Wenn mehrere benutzerdefinierte Editoren für eine bestimmte Datei vorhanden sind, muss der Benutzer auswählen, welchen benutzerdefinierten Editor er verwenden möchte.
    • "option" - Verwenden Sie den benutzerdefinierten Editor nicht standardmäßig, aber ermöglichen Sie Benutzern, zu ihm zu wechseln oder ihn als Standard festzulegen.

Aktivierung benutzerdefinierter Editoren

Wenn ein Benutzer einen Ihrer benutzerdefinierten Editoren öffnet, löst VS Code ein Aktivierungsereignis vom Typ onCustomEditor:VIEW_TYPE aus. Während der Aktivierung muss Ihre Erweiterung registerCustomEditorProvider aufrufen, um einen benutzerdefinierten Editor mit dem erwarteten viewType zu registrieren.

Es ist wichtig zu beachten, dass onCustomEditor nur aufgerufen wird, wenn VS Code eine Instanz Ihres benutzerdefinierten Editors erstellen muss. Wenn VS Code dem Benutzer lediglich Informationen über einen verfügbaren benutzerdefinierten Editor anzeigt – z. B. mit dem Befehl Ansicht: Erneut öffnen mit – wird Ihre Erweiterung nicht aktiviert.

Benutzerdefinierter Texteditor

Benutzerdefinierte Texteditoren ermöglichen Ihnen die Erstellung benutzerdefinierter Editoren für Textdateien. Dies kann alles sein, von einfachem unstrukturiertem Text bis hin zu CSV, JSON oder XML. Benutzerdefinierte Texteditoren verwenden das Standard-TextDocument von VS Code als ihr Dokumentmodell.

Das Beispiel für eine benutzerdefinierte Editor-Erweiterung enthält ein einfaches Beispiel für einen benutzerdefinierten Texteditor für Cat-Scratch-Dateien (die einfach JSON-Dateien mit der Dateiendung .cscratch sind). Werfen wir einen Blick auf einige wichtige Punkte bei der Implementierung eines benutzerdefinierten Texteditors.

Lebenszyklus eines benutzerdefinierten Texteditors

VS Code verwaltet den Lebenszyklus sowohl der Ansichtskomponente benutzerdefinierter Texteditoren (der Webviews) als auch der Modellkomponente (TextDocument). VS Code ruft Ihre Erweiterung auf, wenn es eine neue Instanz eines benutzerdefinierten Editors erstellen muss, und bereinigt die Editorinstanzen und das Dokumentmodell, wenn der Benutzer seine Registerkarten schließt.

Um zu verstehen, wie das alles in der Praxis funktioniert, gehen wir durch, was aus Sicht der Erweiterung passiert, wenn ein Benutzer einen benutzerdefinierten Texteditor öffnet und dann, wenn ein Benutzer einen benutzerdefinierten Texteditor schließt.

Öffnen eines benutzerdefinierten Texteditors

Mithilfe des Beispiels für eine benutzerdefinierte Editor-Erweiterung sehen Sie hier, was passiert, wenn der Benutzer zum ersten Mal eine .cscratch-Datei öffnet

  1. VS Code löst ein Aktivierungsereignis onCustomEditor:catCustoms.catScratch aus.

    Dies aktiviert unsere Erweiterung, falls sie noch nicht aktiviert wurde. Während der Aktivierung muss unsere Erweiterung sicherstellen, dass sie einen CustomTextEditorProvider für catCustoms.catScratch registriert, indem sie registerCustomEditorProvider aufruft.

  2. VS Code ruft dann resolveCustomTextEditor auf dem registrierten CustomTextEditorProvider für catCustoms.catScratch auf.

    Diese Methode nimmt das TextDocument für die zu öffnende Ressource und ein WebviewPanel entgegen. Die Erweiterung muss die anfänglichen HTML-Inhalte für dieses Webview-Panel ausfüllen.

Sobald resolveCustomTextEditor zurückkehrt, wird unser benutzerdefinierter Editor dem Benutzer angezeigt. Was innerhalb des Webviews gezeichnet wird, liegt vollständig in der Verantwortung unserer Erweiterung.

Dieser Ablauf wiederholt sich jedes Mal, wenn ein benutzerdefinierter Editor geöffnet wird, auch wenn Sie einen benutzerdefinierten Editor teilen. Jede Instanz eines benutzerdefinierten Editors hat ihr eigenes WebviewPanel. Mehrere benutzerdefinierte Texteditoren teilen sich jedoch dasselbe TextDocument, wenn sie für dieselbe Ressource gelten. Denken Sie daran: Betrachten Sie das TextDocument als das Modell für die Ressource, während die Webview-Panels Ansichten dieses Modells sind.

Schließen benutzerdefinierter Texteditoren

Wenn ein Benutzer einen benutzerdefinierten Texteditor schließt, löst VS Code das Ereignis WebviewPanel.onDidDispose für das WebviewPanel aus. An dieser Stelle sollte Ihre Erweiterung alle mit diesem Editor verbundenen Ressourcen bereinigen (Ereignisabonnements, Dateibeobachter usw.).

Wenn der letzte benutzerdefinierte Editor für eine bestimmte Ressource geschlossen wird, wird auch das TextDocument für diese Ressource entsorgt, vorausgesetzt, es gibt keine anderen Editoren, die es verwenden, und keine anderen Erweiterungen halten es fest. Sie können die Eigenschaft TextDocument.isClosed überprüfen, um festzustellen, ob das TextDocument geschlossen wurde. Sobald ein TextDocument geschlossen ist, führt das Öffnen derselben Ressource mit einem benutzerdefinierten Editor dazu, dass ein neues TextDocument geöffnet wird.

Synchronisieren von Änderungen mit dem TextDocument

Da benutzerdefinierte Texteditoren ein TextDocument als ihr Dokumentmodell verwenden, sind sie dafür verantwortlich, das TextDocument bei jeder Bearbeitung in einem benutzerdefinierten Editor zu aktualisieren und sich selbst zu aktualisieren, wenn sich das TextDocument ändert.

Vom Webview zum TextDocument

Bearbeitungen in benutzerdefinierten Texteditoren können viele verschiedene Formen annehmen – das Klicken auf eine Schaltfläche, das Ändern von Text, das Ziehen von Elementen. Immer wenn ein Benutzer die Datei selbst innerhalb des benutzerdefinierten Texteditors bearbeitet, muss die Erweiterung das TextDocument aktualisieren. Hier ist, wie die Cat-Scratch-Erweiterung dies implementiert

  1. Der Benutzer klickt in der Webview auf die Schaltfläche Scratch hinzufügen. Dies sendet eine Nachricht von der Webview zurück an die Erweiterung.

  2. Die Erweiterung empfängt die Nachricht. Sie aktualisiert dann ihr internes Modell des Dokuments (was im Cat-Scratch-Beispiel nur das Hinzufügen eines neuen Eintrags zu den JSON-Daten umfasst).

  3. Die Erweiterung erstellt eine WorkspaceEdit, die das aktualisierte JSON in das Dokument schreibt. Diese Bearbeitung wird mit vscode.workspace.applyEdit angewendet.

Versuchen Sie, Ihre Workspace-Bearbeitung auf die minimale Änderung zu beschränken, die zur Aktualisierung des Dokuments erforderlich ist. Beachten Sie auch, dass Ihre Erweiterung bei der Arbeit mit einer Sprache wie JSON versuchen sollte, die vorhandenen Formatierungsstandards des Benutzers zu berücksichtigen (Leerzeichen im Vergleich zu Tabs, Einrückungsgröße usw.).

Vom TextDocument zu Webviews

Wenn sich ein TextDocument ändert, muss Ihre Erweiterung auch sicherstellen, dass ihre Webviews den neuen Zustand des Dokuments widerspiegeln. TextDocuments können durch Benutzeraktionen wie Rückgängig, Wiederherstellen oder Datei rückgängig machen geändert werden, durch andere Erweiterungen, die eine WorkspaceEdit verwenden, oder durch einen Benutzer, der die Datei im Standardtexteditor von VS Code öffnet. Hier ist, wie die Cat-Scratch-Erweiterung dies implementiert

  1. In der Erweiterung abonnieren wir das Ereignis vscode.workspace.onDidChangeTextDocument. Dieses Ereignis wird für jede Änderung am TextDocument ausgelöst (einschließlich Änderungen, die unser benutzerdefinierter Editor vornimmt!).

  2. Wenn eine Änderung für ein Dokument eintrifft, für das wir einen Editor haben, senden wir eine Nachricht an die Webview mit dem neuen Dokumentstatus. Diese Webview aktualisiert sich dann, um das aktualisierte Dokument darzustellen.

Es ist wichtig zu bedenken, dass alle Dateibearbeitungen, die ein benutzerdefinierter Editor auslöst, dazu führen, dass onDidChangeTextDocument ausgelöst wird. Stellen Sie sicher, dass Ihre Erweiterung nicht in eine Update-Schleife gerät, in der der Benutzer eine Bearbeitung in der Webview vornimmt, die onDidChangeTextDocument auslöst, was die Webview dazu veranlasst, sich zu aktualisieren, was die Webview dazu veranlasst, eine weitere Aktualisierung Ihrer Erweiterung auszulösen, die onDidChangeTextDocument auslöst und so weiter.

Denken Sie auch daran, dass Ihr Dokument möglicherweise nicht immer in einem gültigen Zustand ist, wenn Sie mit einer strukturierten Sprache wie JSON oder XML arbeiten. Ihre Erweiterung muss entweder Fehler gracefully behandeln oder dem Benutzer eine Fehlermeldung anzeigen, damit er versteht, was falsch ist und wie er es beheben kann.

Wenn das Aktualisieren Ihrer Webviews kostspielig ist, sollten Sie Debouncing der Updates Ihrer Webviews in Betracht ziehen.

Benutzerdefinierter Editor

CustomEditorProvider und CustomReadonlyEditorProvider ermöglichen die Erstellung benutzerdefinierter Editoren für Binärdateiformate. Diese API gibt Ihnen die volle Kontrolle darüber, wie die Datei dem Benutzer angezeigt wird, wie Bearbeitungen daran vorgenommen werden, und ermöglicht es Ihrer Erweiterung, sich in save und andere Dateioperationen einzuklinken. Nochmals, wenn Sie einen Editor für ein textbasiertes Dateiformat erstellen, sollten Sie unbedingt einen CustomTextEditor stattdessen in Erwägung ziehen, da diese weitaus einfacher zu implementieren sind.

Das Beispiel für eine benutzerdefinierte Editor-Erweiterung enthält ein einfaches Beispiel für einen benutzerdefinierten Binär-Editor für Paw-Draw-Dateien (die einfach JPEG-Dateien mit der Dateiendung .pawdraw sind). Werfen wir einen Blick darauf, was beim Erstellen eines benutzerdefinierten Editors für Binärdateien wichtig ist.

CustomDocument

Bei benutzerdefinierten Editoren ist Ihre Erweiterung für die Implementierung ihres eigenen Dokumentmodells mit der Schnittstelle CustomDocument verantwortlich. Dies gibt Ihrer Erweiterung die Freiheit, beliebige Daten auf einem CustomDocument zu speichern, die sie für die Interaktion mit Ihrem benutzerdefinierten Editor benötigt, bedeutet aber auch, dass Ihre Erweiterung grundlegende Dokumentoperationen implementieren muss, wie z. B. das Speichern und Sichern von Dateidaten für Hot Exit.

Es gibt ein CustomDocument pro geöffneter Datei. Benutzer können mehrere Editoren für eine einzelne Ressource öffnen (z. B. durch Teilen des aktuellen benutzerdefinierten Editors), aber alle diese Editoren werden von demselben CustomDocument unterstützt.

Lebenszyklus eines benutzerdefinierten Editors

supportsMultipleEditorsPerDocument

Standardmäßig erlaubt VS Code nur einen Editor pro benutzerdefiniertem Dokument. Diese Einschränkung erleichtert die korrekte Implementierung eines benutzerdefinierten Editors, da Sie sich nicht um die Synchronisierung mehrerer benutzerdefinierter Editorinstanzen miteinander kümmern müssen.

Wenn Ihre Erweiterung dies jedoch unterstützen kann, empfehlen wir, supportsMultipleEditorsPerDocument: true beim Registrieren Ihres benutzerdefinierten Editors festzulegen, damit mehrere Editorinstanzen für dasselbe Dokument geöffnet werden können. Dadurch verhalten sich Ihre benutzerdefinierten Editoren eher wie die normalen Texteditoren von VS Code.

Öffnen benutzerdefinierter Editoren Wenn der Benutzer eine Datei öffnet, die dem customEditor-Beitragspunkt entspricht, löst VS Code ein onCustomEditor Aktivierungsereignis aus und ruft dann den für den angegebenen View-Typ registrierten Provider auf. Ein CustomEditorProvider hat zwei Aufgaben: Bereitstellung des Dokuments für den benutzerdefinierten Editor und dann Bereitstellung des Editors selbst. Hier ist eine geordnete Liste dessen, was für den catCustoms.pawDraw-Editor aus dem Beispiel für eine benutzerdefinierte Editor-Erweiterung passiert

  1. VS Code löst ein Aktivierungsereignis onCustomEditor:catCustoms.pawDraw aus.

    Dies aktiviert unsere Erweiterung, falls sie noch nicht aktiviert wurde. Wir müssen auch sicherstellen, dass unsere Erweiterung während der Aktivierung einen CustomReadonlyEditorProvider oder CustomEditorProvider für catCustoms.pawDraw registriert.

  2. VS Code ruft openCustomDocument auf unserem CustomReadonlyEditorProvider oder CustomEditorProvider auf, der für catCustoms.pawDraw-Editoren registriert ist.

    Hier erhält unsere Erweiterung eine Ressourcen-URI und muss ein neues CustomDocument für diese Ressource zurückgeben. Dies ist der Punkt, an dem unsere Erweiterung ihr internes Dokumentmodell für diese Ressource erstellen sollte. Dies kann das Lesen und Parsen des anfänglichen Ressourcenzustands von der Festplatte oder die Initialisierung unseres neuen CustomDocument beinhalten.

    Unsere Erweiterung kann dieses Modell definieren, indem sie eine neue Klasse erstellt, die CustomDocument implementiert. Denken Sie daran, dass diese Initialisierungsphase vollständig den Erweiterungen überlassen ist; VS Code kümmert sich nicht um zusätzliche Informationen, die Erweiterungen auf einem CustomDocument speichern.

  3. VS Code ruft resolveCustomEditor mit dem CustomDocument aus Schritt 2 und einem neuen WebviewPanel auf.

    Hier muss unsere Erweiterung das anfängliche HTML für den benutzerdefinierten Editor ausfüllen. Wenn nötig, können wir auch eine Referenz auf das WebviewPanel behalten, um es später zu referenzieren, z. B. in Befehlen.

Sobald resolveCustomEditor zurückkehrt, wird unser benutzerdefinierter Editor dem Benutzer angezeigt.

Wenn der Benutzer dieselbe Ressource in einer anderen Editorgruppe mit unserem benutzerdefinierten Editor öffnet (z. B. durch Teilen des ersten Editors), vereinfacht sich die Aufgabe der Erweiterung. In diesem Fall ruft VS Code einfach resolveCustomEditor mit demselben CustomDocument auf, das wir beim Öffnen des ersten Editors erstellt haben.

Schließen benutzerdefinierter Editoren

Nehmen wir an, wir haben zwei Instanzen unserer benutzerdefinierten Editoren für dieselbe Ressource geöffnet. Wenn der Benutzer diese Editoren schließt, signalisiert VS Code unserer Erweiterung, damit sie alle mit dem Editor verbundenen Ressourcen bereinigen kann.

Wenn die erste Editorinstanz geschlossen wird, löst VS Code das Ereignis WebviewPanel.onDidDispose für das WebviewPanel des geschlossenen Editors aus. An dieser Stelle muss unsere Erweiterung alle mit dieser spezifischen Editorinstanz verbundenen Ressourcen bereinigen.

Wenn der zweite Editor geschlossen wird, löst VS Code erneut WebviewPanel.onDidDispose aus. Jetzt haben wir jedoch auch alle Editoren geschlossen, die mit dem CustomDocument verbunden sind. Wenn keine Editoren mehr für ein CustomDocument vorhanden sind, ruft VS Code dessen CustomDocument.dispose auf. Die Implementierung von dispose durch unsere Erweiterung muss alle mit dem Dokument verbundenen Ressourcen bereinigen.

Wenn der Benutzer dann dieselbe Ressource über unseren benutzerdefinierten Editor wieder öffnet, durchlaufen wir den gesamten Ablauf von openCustomDocument und resolveCustomEditor mit einem neuen CustomDocument.

Schreibgeschützte benutzerdefinierte Editoren

Viele der folgenden Abschnitte gelten nur für benutzerdefinierte Editoren, die Bearbeitungen unterstützen. Und obwohl es paradox klingen mag, benötigen viele benutzerdefinierte Editoren überhaupt keine Bearbeitungsfunktionen. Denken Sie zum Beispiel an eine Bildvorschau. Oder eine visuelle Darstellung eines Speicherabbilds. Beide können mit benutzerdefinierten Editoren implementiert werden, aber keiner muss bearbeitbar sein. Hier kommt CustomReadonlyEditorProvider ins Spiel.

Ein CustomReadonlyEditorProvider ermöglicht die Erstellung benutzerdefinierter Editoren, die keine Bearbeitungen unterstützen. Sie können immer noch interaktiv sein, unterstützen aber keine Operationen wie Rückgängig und Speichern. Die Implementierung eines schreibgeschützten benutzerdefinierten Editors ist auch viel einfacher als die eines vollständig bearbeitbaren.

Grundlagen bearbeitbarer benutzerdefinierter Editoren

Bearbeitbare benutzerdefinierte Editoren ermöglichen es Ihnen, sich in Standard-VS-Code-Operationen wie Rückgängig und Wiederherstellen, Speichern und Hot Exit einzuklinken. Dies macht bearbeitbare benutzerdefinierte Editoren sehr leistungsfähig, bedeutet aber auch, dass deren ordnungsgemäße Implementierung weitaus komplexer ist als die Implementierung eines bearbeitbaren benutzerdefinierten Texteditors oder eines schreibgeschützten benutzerdefinierten Editors.

Bearbeitbare benutzerdefinierte Editoren werden von CustomEditorProvider implementiert. Diese Schnittstelle erweitert CustomReadonlyEditorProvider. Sie müssen also grundlegende Operationen wie openCustomDocument und resolveCustomEditor sowie eine Reihe von bearbeitungsspezifischen Operationen implementieren. Sehen wir uns die bearbeitungsspezifischen Teile von CustomEditorProvider an.

Bearbeitungen

Änderungen an einem bearbeitbaren benutzerdefinierten Dokument werden durch Bearbeitungen ausgedrückt. Eine Bearbeitung kann alles sein, von einer Textänderung über eine Bildrotation bis hin zur Neuanordnung einer Liste. VS Code überlässt die genauen Details dessen, was eine Bearbeitung bewirkt, vollständig Ihrer Erweiterung, aber VS Code muss wissen, wann eine Bearbeitung stattfindet. Bearbeitungen sind die Art und Weise, wie VS Code Dokumente als "dirty" markiert, was wiederum das automatische Speichern und Sichern aktiviert.

Immer wenn ein Benutzer in einer der Webviews für Ihren benutzerdefinierten Editor eine Bearbeitung vornimmt, muss Ihre Erweiterung ein onDidChangeCustomDocument-Ereignis von ihrem CustomEditorProvider auslösen. Das onDidChangeCustomDocument-Ereignis kann je nach Implementierung Ihres benutzerdefinierten Editors zwei Ereignistypen auslösen: CustomDocumentContentChangeEvent und CustomDocumentEditEvent.

CustomDocumentContentChangeEvent

Ein CustomDocumentContentChangeEvent ist eine grundlegende Bearbeitung. Seine einzige Funktion besteht darin, VS Code mitzuteilen, dass ein Dokument bearbeitet wurde.

Wenn eine Erweiterung ein CustomDocumentContentChangeEvent von onDidChangeCustomDocument auslöst, markiert VS Code das zugehörige Dokument als "dirty". An diesem Punkt ist der einzige Weg, das Dokument wieder "nicht dirty" zu machen, entweder durch Speichern oder Rückgängigmachen durch den Benutzer. Benutzerdefinierte Editoren, die CustomDocumentContentChangeEvent verwenden, unterstützen kein Rückgängig/Wiederherstellen.

CustomDocumentEditEvent

Ein CustomDocumentEditEvent ist eine komplexere Bearbeitung, die Rückgängig/Wiederherstellen ermöglicht. Sie sollten immer versuchen, Ihren benutzerdefinierten Editor mit CustomDocumentEditEvent zu implementieren und nur auf die Verwendung von CustomDocumentContentChangeEvent zurückgreifen, wenn die Implementierung von Rückgängig/Wiederherstellen nicht möglich ist.

Ein CustomDocumentEditEvent hat die folgenden Felder

  • document — Das CustomDocument, für das die Bearbeitung bestimmt war.
  • label — Optionaler Text, der beschreibt, welche Art von Bearbeitung vorgenommen wurde (z. B. "Zuschneiden", "Einfügen", ...)
  • undo — Funktion, die von VS Code aufgerufen wird, wenn die Bearbeitung rückgängig gemacht werden muss.
  • redo — Funktion, die von VS Code aufgerufen wird, wenn die Bearbeitung wiederhergestellt werden muss.

Wenn eine Erweiterung ein CustomDocumentEditEvent von onDidChangeCustomDocument auslöst, markiert VS Code das zugehörige Dokument als "dirty". Um das Dokument nicht mehr als "dirty" zu kennzeichnen, kann ein Benutzer das Dokument dann entweder speichern oder rückgängig machen oder die Bearbeitungen bis zum letzten gespeicherten Zustand rückgängig machen/wiederherstellen.

Die Methoden undo und redo eines Editors werden von VS Code aufgerufen, wenn diese spezifische Bearbeitung rückgängig gemacht oder wieder angewendet werden muss. VS Code verwaltet einen internen Stapel von Bearbeitungen. Wenn Ihre Erweiterung also onDidChangeCustomDocument mit drei Bearbeitungen auslöst, nennen wir sie a, b, c

onDidChangeCustomDocument(a);
onDidChangeCustomDocument(b);
onDidChangeCustomDocument(c);

Die folgende Sequenz von Benutzeraktionen führt zu diesen Aufrufen

undo — c.undo()
undo — b.undo()
redo — b.redo()
redo — c.redo()
redo — no op, no more edits

Um Rückgängig/Wiederherstellen zu implementieren, muss Ihre Erweiterung den internen Zustand ihres zugehörigen benutzerdefinierten Dokuments aktualisieren und alle zugehörigen Webviews für das Dokument aktualisieren, damit diese den neuen Zustand des Dokuments widerspiegeln. Beachten Sie, dass es mehrere Webviews für eine einzelne Ressource geben kann. Diese müssen immer dieselben Dokumentdaten anzeigen. Mehrere Instanzen eines Bildeditors können beispielsweise immer dieselben Pixeldaten anzeigen, aber jeder Editorinstanz kann sein eigenes Zoomlevel und seinen eigenen UI-Status ermöglichen.

Speichern

Wenn ein Benutzer einen benutzerdefinierten Editor speichert, ist Ihre Erweiterung dafür verantwortlich, die gespeicherte Ressource in ihrem aktuellen Zustand auf die Festplatte zu schreiben. Wie Ihr benutzerdefinierter Editor dies tut, hängt stark vom CustomDocument-Typ Ihrer Erweiterung ab und davon, wie Ihre Erweiterung Bearbeitungen intern verfolgt.

Der erste Schritt beim Speichern ist das Abrufen des Datenstroms, der auf die Festplatte geschrieben werden soll. Gängige Ansätze dafür sind

  • Verfolgen Sie den Zustand der Ressource, damit sie schnell serialisiert werden kann.

    Ein einfacher Bildeditor könnte zum Beispiel einen Puffer mit Pixeldaten verwalten.

  • Wiederholen Sie die Bearbeitung seit dem letzten Speichern, um die neue Datei zu generieren.

    Ein effizienterer Bildeditor könnte zum Beispiel Bearbeitungen seit dem letzten Speichern verfolgen, wie z. B. Zuschneiden, Drehen, Skalieren. Beim Speichern würde er diese Bearbeitungen auf den letzten gespeicherten Zustand der Datei anwenden, um die neue Datei zu generieren.

  • Fordern Sie ein WebviewPanel auf, die benutzerdefinierte Editor-Datei für zu speichernde Daten bereitzustellen.

    Bedenken Sie jedoch, dass benutzerdefinierte Editoren auch dann gespeichert werden können, wenn sie nicht sichtbar sind. Aus diesem Grund wird empfohlen, dass die Implementierung von save Ihrer Erweiterung nicht von einem WebviewPanel abhängt. Wenn dies nicht möglich ist, können Sie die Einstellung WebviewPanelOptions.retainContextWhenHidden verwenden, damit das Webview auch im ausgeblendeten Zustand aktiv bleibt. retainContextWhenHidden hat erhebliche Speicherauswirkungen, seien Sie also vorsichtig bei der Verwendung.

Nachdem Sie die Daten für die Ressource erhalten haben, sollten Sie im Allgemeinen die Workspace-FS-API verwenden, um sie auf die Festplatte zu schreiben. Die FS-APIs nehmen ein UInt8Array von Daten entgegen und können sowohl Binär- als auch Textdateien schreiben. Für Binärdateidaten packen Sie die Binärdaten einfach in das UInt8Array. Für Textdateidaten verwenden Sie Buffer, um einen String in ein UInt8Array umzuwandeln

const writeData = Buffer.from('my text data', 'utf8');
vscode.workspace.fs.writeFile(fileUri, writeData);

Nächste Schritte

Wenn Sie mehr über die Erweiterbarkeit von VS Code erfahren möchten, probieren Sie diese Themen aus

  • Extension API - Erfahren Sie mehr über die vollständige VS Code Extension API.
  • Extension Capabilities - Sehen Sie sich andere Möglichkeiten zur Erweiterung von VS Code an.
© . This site is unofficial and not affiliated with Microsoft.