Ändern von Text im Editor
Bearbeitungen, d. h. Änderungen an einem textdokument, das im Visual Studio-Editor geöffnet ist, können sich aus Benutzerinteraktionen in Visual Studio oder programmgesteuerten Änderungen aus Sprachdiensten und anderen Erweiterungen ergeben. Ihre Erweiterung muss vorbereitet sein, um Änderungen am Dokumenttext in Echtzeit zu behandeln.
Erweiterungen, die außerhalb des Visual Studio-Haupt-IDE-Prozesses ausgeführt werden, verwenden asynchrone Entwurfsmuster, um mit dem Visual Studio-IDE-Prozess zu kommunizieren. Dies bedeutet die Verwendung asynchroner Methodenaufrufe, wie durch das Schlüsselwort async
in C# angegeben und durch das Async
Suffix für Methodennamen verstärkt. Asynchronität ist ein erheblicher Vorteil im Kontext eines Editors, der erwartet wird, dass er auf Benutzeraktionen reagiert. Ein traditioneller synchroner API-Aufruf wird, wenn er länger als erwartet dauert, nicht mehr auf Benutzereingaben reagieren, wodurch die Benutzeroberfläche einfriert, bis der API-Aufruf abgeschlossen ist. Benutzererwartungen an moderne interaktive Anwendungen sind, dass Texteditoren immer reaktionsfähig bleiben und sie nie daran hindern, zu arbeiten. Die asynchrone Nutzung von Erweiterungen ist daher unerlässlich, um die Erwartungen der Benutzer zu erfüllen.
Weitere Informationen zur asynchronen Programmierung finden Sie unter Asynchrone Programmierung mit async und await.
Im neuen Visual Studio-Erweiterbarkeitsmodell ist die Erweiterung eine zweite Klasse relativ zum Benutzer: Sie kann den Editor oder das Textdokument nicht direkt ändern. Alle Statusänderungen sind asynchron und kooperativ, wobei visual Studio IDE die angeforderte Änderung im Namen der Erweiterung ausführt. Die Erweiterung kann eine oder mehrere Änderungen an einer bestimmten Version des Dokuments oder der Textansicht anfordern, aber Änderungen aus einer Erweiterung können abgelehnt werden, z. B. wenn sich dieser Bereich des Dokuments geändert hat.
Änderungen werden mit der Methode EditAsync()
für EditorExtensibility
angefordert.
Wenn Sie mit älteren Visual Studio-Erweiterungen vertraut sind, ist ITextDocumentEditor
fast identisch mit den Zustandsänderungsmethoden von ITextBuffer und ITextDocument- und unterstützt die meisten der gleichen Funktionen.
MutationResult result = await this.Extensibility.Editor().EditAsync(
batch =>
{
var editor = document.AsEditable(batch);
editor.Replace(textView.Selection.Extent, newGuidString);
},
cancellationToken);
Um falsch eingefügte Bearbeitungen zu vermeiden, werden Bearbeitungen aus Editorerweiterungen wie folgt angewendet:
- Die Erweiterung fordert eine Bearbeitung basierend auf der neuesten Version des Dokuments an.
- Diese Anforderung kann eine oder mehrere Textbearbeitungen, Änderungen an der Caretposition usw. enthalten. Jeder Typ, der
IEditable
implementiert, kann in einer einzelnenEditAsync()
Anforderung geändert werden, einschließlichITextViewSnapshot
undITextDocumentSnapshot
. Bearbeitungen werden vom Editor durchgeführt, der überAsEditable()
für eine bestimmte Klasse angefordert werden kann. - Bearbeitungsanforderungen werden an Visual Studio-IDE gesendet, wobei sie nur erfolgreich ausgeführt wird, wenn sich das geänderte Objekt seit der Version der Anforderung nicht geändert hat. Wenn sich das Dokument geändert hat, kann die Änderung abgelehnt werden, und die Erweiterung muss es mit einer neueren Version erneut versuchen. Das Ergebnis der Mutationsoperation wird in
result
gespeichert. - Bearbeitungen werden atomar angewendet, d. h. ohne Unterbrechung von anderen ausgeführten Threads. Es hat sich bewährt, alle Änderungen, die innerhalb eines engen Zeitrahmens erfolgen sollen, in einem einzigen
EditAsync()
-Aufruf durchzuführen, um die Wahrscheinlichkeit von unerwartetem Verhalten zu verringern, das durch Benutzereingriffe oder Sprachdienstaktionen zwischen den Eingriffen entsteht (z. B. wenn Erweiterungsänderungen mit dem Verschieben der Einfügemarke in Roslyn C# überlagert werden).
Ändern der Position der Einfügemarke oder Auswählen von Text über eine Erweiterung
Die Bearbeitung eines Textdokuments über eine Erweiterung wirkt sich implizit auf die Position der Einfügemarke aus. Wenn Sie beispielsweise einen Text an der Einfügemarke einfügen, wird die Einfügemarke an das Ende des eingefügten Texts verschoben. Erweiterungen können ITextViewSnapshot.AsEditable().SetSelections()
auch verwenden, um die Einfügemarke explizit an eine andere Position zu setzen oder eine Textauswahl zu treffen. Zur Veranschaulichung: Der folgende Code fügt Text ein, belässt die Einfügemarke jedoch an der ursprünglichen Position:
await this.Extensibility.Editor().EditAsync(batch =>
{
var caret = textView.Selection.Extent.Start;
textView.Document.AsEditable(batch).Replace(textView.Selection.Extent, newGuidString);
textView.AsEditable(batch).SetSelections([new Selection(activePosition: caret, anchorPosition: caret, insertionPosition: caret)]);
},
cancellationToken);
Parallele Ausführung
⚠️ | Editorerweiterungen können manchmal gleichzeitig ausgeführt werden |
---|
Die erste Version hat ein bekanntes Problem, das zur gleichzeitigen Ausführung von Editorerweiterungscode führen kann. Alle asynchronen Methoden werden garantiert in der richtigen Reihenfolge aufgerufen. Fortsetzungen nach dem ersten await
werden möglicherweise versetzt aufgerufen. Wenn eine Erweiterung von der Ausführungsreihenfolge abhängt, sollten Sie eine Warteschlange für eingehende Anfragen einrichten, um die Reihenfolge zu wahren, bis dieses Problem behoben ist.
Weitere Informationen finden Sie finden Sie unter StreamJsonRpc – Standardreihenfolge und Parallelität.