Ändra text i redigeraren
Ändringar i ett textdokument som är öppet i Visual Studio-redigeraren kan bero på användarinteraktioner i Visual Studio eller programmatiska ändringar från språktjänster och andra tillägg. Tillägget måste vara förberett för att hantera ändringar i dokumenttexten som sker i realtid.
Tillägg som körs utanför Visual Studio IDE-huvudprocessen använder asynkrona designmönster för att kommunicera med Visual Studio IDE-processen. Det innebär användning av asynkrona metodanrop, vilket anges av nyckelordet async
i C# och förstärks av Async
suffixet för metodnamn. Asynkronitet är en betydande fördel i kontexten för en redigerare som förväntas svara på användaråtgärder. Ett traditionellt synkront API-anrop, om det tar längre tid än förväntat, slutar svara på användarindata, vilket skapar en UI-frysning som varar tills API-anropet har slutförts. Användarnas förväntningar på moderna interaktiva program är att textredigerare alltid är dynamiska och aldrig blockerar dem från att fungera. Det är därför viktigt att tilläggen är asynkrona för att uppfylla användarnas förväntningar.
Läs mer om asynkron programmering på Asynkron programmering med async och await.
I den nya Utökningsmodellen för Visual Studio är tillägget andra klassen i förhållande till användaren: det kan inte direkt ändra redigeraren eller textdokumentet. Alla tillståndsändringar är asynkrona och samarbetsinriktade, där Visual Studio IDE utför den begärda ändringen för tilläggets räkning. Tillägget kan begära en eller flera ändringar i en viss version av dokument- eller textvyn, men ändringar från ett tillägg kan avvisas, till exempel om det området i dokumentet har ändrats.
Redigeringar begärs genom metoden EditAsync()
på EditorExtensibility
.
Om du är bekant med äldre Visual Studio-tillägg är ITextDocumentEditor
nästan samma som de tillståndsförändrande metoderna från ITextBuffer och ITextDocument och stöder de flesta av samma funktioner.
MutationResult result = await this.Extensibility.Editor().EditAsync(
batch =>
{
var editor = document.AsEditable(batch);
editor.Replace(textView.Selection.Extent, newGuidString);
},
cancellationToken);
För att undvika felplacerade redigeringar tillämpas redigeringar från redigeringstillägg på följande sätt:
- Tillägget begär att en redigering görs baserat på den senaste versionen av dokumentet.
- Den begäran kan innehålla en eller flera textändringar, ändringar av markörposition och så vidare. Alla typer som implementerar
IEditable
kan ändras i en endaEditAsync()
begäran, inklusiveITextViewSnapshot
ochITextDocumentSnapshot
. Redigeringar görs av redaktören, som kan begäras för en specifik klass viaAsEditable()
. - Redigeringsbegäranden skickas till Visual Studio IDE, där det endast lyckas om objektet som muteras inte har ändrats sedan den version som begäran gjordes. Om dokumentet har ändrats kan ändringen avvisas, vilket kräver att tillägget försöker igen på nyare version. Resultatet av mutationsåtgärden lagras i
result
. - Redigeringar tillämpas atomiskt, vilket innebär att de sker utan avbrott från andra trådar. Rekommenderat tillvägagångssätt är att göra alla ändringar som bör ske inom en begränsad tidsram i ett enda
EditAsync()
-anrop, för att minska sannolikheten för oväntat beteende som uppstår vid användarredigeringar eller språktjänståtgärder som inträffar mellan redigeringar (till exempel tilläggsredigeringar som interfolieras med Roslyn C# som flyttar markören).
Ändra caret-position eller välja text från ett tillägg
Redigering av ett textdokument från ett tillägg påverkar implicit markörens position. Om du till exempel infogar text på caret flyttas careten till slutet av den infogade texten. Tillägg kan också använda ITextViewSnapshot.AsEditable().SetSelections()
för att uttryckligen ställa in markören till en annan position eller göra markeringar i text. För att illustrera skulle följande kod infoga text, men behålla caret på den ursprungliga positionen:
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);
Samtidig körning
️ ⚠ | Redigeringstillägg kan ibland köras samtidigt |
---|
Den första versionen har ett känt problem som kan resultera i samtidig körning av kod för redigeringstillägg. Varje asynkron metod anropas garanterat i rätt ordning, men fortsättningar efter den första await
kan interfolieras. Om tillägget förlitar sig på körningsordning kan du överväga att underhålla en kö med inkommande begäranden för att bevara ordern tills det här problemet har åtgärdats.
Mer information finns i StreamJsonRpc Default Ordering and Concurrency.