Sdílet prostřednictvím


Změna textu v editoru

Úpravy, to znamená změny textového dokumentu otevřeného v editoru sady Visual Studio, mohou vzniknout z interakcí uživatelů v sadě Visual Studio nebo programových změn ze služeb jazyka a dalších rozšíření. Vaše rozšíření musí být připravené k řešení změn v textu dokumentu, ke kterým dochází v reálném čase.

Rozšíření spuštěná mimo hlavní proces integrovaného vývojového prostředí sady Visual Studio používají vzory asynchronního návrhu ke komunikaci s procesem integrovaného vývojového prostředí sady Visual Studio. To znamená použití asynchronních volání metod, jak označuje klíčové slovo async v jazyce C# a posíleno příponou Async názvů metod. Asynchronní synchronizace je významnou výhodou v kontextu editoru, u kterého se očekává, že reaguje na akce uživatelů. Tradiční synchronní volání rozhraní API, pokud trvá déle, než se čekalo, přestane reagovat na vstup uživatele, čímž se uživatelské rozhraní zablokuje, dokud se volání rozhraní API dokončí. Očekávání uživatelů moderních interaktivních aplikací jsou, že textové editory vždy zůstávají responzivní a nikdy je nezablokují v práci. Aby byla rozšíření asynchronní, je proto nezbytné splnit očekávání uživatelů.

Další informace o asynchronním programování najdete v programování s použitím async a await.

V novém modelu rozšiřitelnosti sady Visual Studio je rozšíření druhou třídou vzhledem k uživateli: nemůže přímo upravit editor ani textový dokument. Všechny změny stavu jsou asynchronní a spolupracovné s integrovaným vývojovém prostředím sady Visual Studio, které provádí požadovanou změnu jménem rozšíření. Rozšíření může požádat o jednu nebo více změn v konkrétní verzi dokumentu nebo textového zobrazení, ale změny z rozšíření můžou být odmítnuty, například pokud se tato oblast dokumentu změnila.

Úpravy jsou požadovány pomocí metody EditAsync() v EditorExtensibility.

Pokud znáte starší rozšíření sady Visual Studio, ITextDocumentEditor je téměř stejná jako metody změny stavu z ITextBuffer a ITextDocument a podporuje většinu stejných funkcí.

MutationResult result = await this.Extensibility.Editor().EditAsync(
batch =>
{
    var editor = document.AsEditable(batch);
    editor.Replace(textView.Selection.Extent, newGuidString);
},
cancellationToken);

Pokud se chcete vyhnout chybně umístěným úpravám, použijí se úpravy z rozšíření editoru následujícím způsobem:

  1. Rozšíření požaduje provedení úprav na základě nejnovější verze dokumentu.
  2. Tento požadavek může obsahovat jednu nebo více úprav textu, změny pozice kurzoru atd. Jakýkoli typ implementující IEditable lze změnit v jednom požadavku EditAsync(), včetně ITextViewSnapshot a ITextDocumentSnapshot. Úpravy provádí editor, který je možné vyžádat u konkrétní třídy prostřednictvím AsEditable().
  3. Žádosti o úpravy se odesílají do integrovaného vývojového prostředí sady Visual Studio, kde jsou úspěšné pouze v případě, že se objekt, který je měněn, od verze objektu, na kterou byla žádost učiněna, nezměnil. Pokud se dokument změnil, může být změna odmítnuta, což vyžaduje, aby se rozšíření zkusila znovu v novější verzi. Výsledek operace mutace je uložen v result.
  4. Úpravy se používají atomicky, což znamená bez přerušení jinými běžícími vlákny. Osvědčeným postupem je provést všechny změny, ke kterým by mělo dojít během úzkého časového rozpětí, do jednoho volání EditAsync(), aby se snížila pravděpodobnost neočekávaného chování způsobeného úpravami uživatelů nebo akcemi jazykové služby, ke kterým dochází mezi úpravami (například když se úpravy rozšíření prokládají a Roslyn C# posouvá kurzor).

Změna pozice kurzoru nebo výběr textu z rozšíření

Úprava textového dokumentu prováděná z rozšíření implicitně ovlivňuje pozici kurzoru. Například vložením textu na kurzor přesunete kurzor na konec vloženého textu. Rozšíření můžou také použít ITextViewSnapshot.AsEditable().SetSelections() k explicitní nastavení kurzoru na jinou pozici nebo výběru textu. Pro ilustraci by následující kód vložil nějaký text, ale ponechá kurzor na původní pozici:

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);

Souběžné spuštění

️ ⚠ Rozšíření editoru můžou někdy běžet souběžně.

V počáteční verzi je známý problém, který může vést k souběžnému spuštění kódu rozšíření editoru. U každé asynchronní metody je zaručeno, že bude volána ve správném pořadí, ale pokračování po prvním await mohou být prokládána. Pokud vaše rozšíření spoléhá na pořadí provádění, zvažte zachování fronty příchozích požadavků, dokud se tento problém nevyřeší.

Další informace naleznete v tématu StreamJsonRpc: Výchozí pořadí a souběžnost.