Praca z tekstem w edytorze
Kod rozszerzenia można skonfigurować tak, aby był uruchamiany w odpowiedzi na różne punkty wejścia (sytuacje, w których użytkownik wchodzi w interakcję z programem Visual Studio). Rozszerzalność edytora obsługuje obecnie trzy punkty wejścia: odbiorniki, obiekt usługowy EditorExtensibility i polecenia.
Odbiorniki zdarzeń są wyzwalane, gdy w oknie edytora wystąpią określone akcje reprezentowane w kodzie przez TextView
. Na przykład gdy użytkownik wpisze coś w edytorze, wystąpi zdarzenie TextViewChanged
. Po otwarciu lub zamknięciu okna edytora wystąpią zdarzenia TextViewOpened
i TextViewClosed
.
Obiekt usługi edytora jest wystąpieniem klasy EditorExtensibility
, która uwidacznia funkcje edytora w czasie rzeczywistym, takie jak wykonywanie edycji tekstu.
polecenia są inicjowane przez użytkownika, klikając element, który można umieścić w menu, menu kontekstowym lub pasku narzędzi.
Dodaj nasłuchiwacz widoku tekstu
Istnieją dwa typy odbiorników, ITextViewChangedListener i ITextViewOpenClosedListener. Razem te odbiorniki mogą służyć do obserwowania otwartych, bliskich i modyfikacji edytorów tekstu.
Następnie utwórz nową klasę, wdrażając ExtensionPart klasę bazową i ITextViewChangedListener
, ITextViewOpenClosedListener
lub oba te elementy, a następnie dodaj atrybut VisualStudioContribution.
Następnie zaimplementuj właściwość TextViewExtensionConfiguration zgodnie z wymaganiami ITextViewChangedListener i ITextViewOpenClosedListener, aby odbiornik działał podczas edytowania plików C#:
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },
};
Dostępne typy dokumentów dla innych języków programowania i typów plików są wymienione w dalszej części tego artykułu, a niestandardowe typy plików mogą być również zdefiniowane w razie potrzeby.
Zakładając, że zdecydujesz się zaimplementować oba odbiorniki, zakończona deklaracja klasy powinna wyglądać następująco:
[VisualStudioContribution]
public sealed class TextViewOperationListener :
ExtensionPart, // This is the extension part base class containing infrastructure necessary to use VS services.
ITextViewOpenClosedListener, // Indicates this part listens for text view lifetime events.
ITextViewChangedListener // Indicates this part listens to text view changes.
{
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
// Indicates this part should only light up in C# files.
AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },
};
...
Ponieważ zarówno ITextViewOpenClosedListener, jak i ITextViewChangedListener deklarują właściwość TextViewExtensionConfiguration, konfiguracja dotyczy obu nasłuchiwaczy.
Po uruchomieniu rozszerzenia powinny zostać wyświetlone następujące elementy:
- ITextViewOpenClosedListener.TextViewOpenedAsync wywoływana za każdym razem, gdy użytkownik otworzy widok tekstowy.
- ITextViewOpenClosedListener.TextViewClosedAsync wywoływana w dowolnym momencie, gdy użytkownik zamknie widok tekstowy.
- ITextViewChangedListener.TextViewChangedAsync wywoływana za każdym razem, gdy użytkownik wprowadza zmianę tekstu w dokumencie tekstowym wyświetlanym przez widok tekstowy.
Każda z tych metod jest przekazywana ITextViewSnapshot zawierający stan widoku tekstu i dokumentu tekstowego w czasie, gdy użytkownik wywołał akcję i element CancellationToken, który będzie miał IsCancellationRequested == true
, gdy środowisko IDE chce anulować oczekującą akcję.
Definiowanie, kiedy rozszerzenie jest istotne
Rozszerzenie jest zwykle istotne tylko dla niektórych obsługiwanych typów i scenariuszy dokumentów, dlatego ważne jest, aby jasno zdefiniować jego zastosowanie. Można użyć konfiguracji AppliesTo) na kilka sposobów, aby jasno zdefiniować przydatność rozszerzenia. Można określić, jakie typy plików obsługuje rozszerzenie, na przykład języki programowania, i/lub dodatkowo uściślić zastosowanie rozszerzenia, dopasowując do wzorca na podstawie nazwy pliku lub ścieżki.
Określanie języków programowania przy użyciu konfiguracji AppliesTo
Konfiguracja AppliesTo wskazuje scenariusze języka programowania, w których rozszerzenie powinno zostać aktywowane. Jest napisany jako AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") }
, gdzie typ dokumentu to dobrze znana nazwa języka wbudowanego w programie Visual Studio lub niestandardowo zdefiniowana w rozszerzeniu Visual Studio.
Niektóre dobrze znane typy dokumentów przedstawiono w poniższej tabeli:
Typ dokumentu | Opis |
---|---|
"CSharp" | C# |
"C/C++" | C, C++, nagłówki i IDL |
"TypeScript" | Języki typów TypeScript i JavaScript. |
"HTML" | HTML |
"JSON" | JSON |
"tekst" | Pliki tekstowe, w tym hierarchiczni potomkowie "kodu", którzy pochodzą z "tekstu". |
"kod" | C, C++, C# itd. |
Typy dokumentów są hierarchiczne. Oznacza to, że język C# i C++ pochodzą z "kodu", dlatego deklarowanie "kodu" powoduje aktywowanie rozszerzenia dla wszystkich języków kodu, C#, C, C++itd.
Definiowanie nowego typu dokumentu
Możesz zdefiniować nowy typ dokumentu, na przykład w celu obsługi niestandardowego języka kodu, dodając statyczną właściwość DocumentTypeConfiguration do dowolnej klasy w projekcie rozszerzenia i oznaczając właściwość atrybutem VisualStudioContribution
.
DocumentTypeConfiguration
umożliwia zdefiniowanie nowego typu dokumentu, określenie, czy dziedziczy jeden lub więcej innych typów dokumentów, i określ jedno lub więcej rozszerzeń plików, które są używane do identyfikowania typu pliku:
using Microsoft.VisualStudio.Extensibility.Editor;
internal static class MyDocumentTypes
{
[VisualStudioContribution]
internal static DocumentTypeConfiguration MarkdownDocumentType => new("markdown")
{
FileExtensions = new[] { ".md", ".mdk", ".markdown" },
BaseDocumentType = DocumentType.KnownValues.Text,
};
}
Definicje typów dokumentów są scalane z definicjami typów zawartości udostępnianymi przez starszą rozszerzalność programu Visual Studio, co umożliwia mapowanie dodatkowych rozszerzeń plików na istniejące typy dokumentów.
Selektory dokumentów
Oprócz DocumentFilter.FromDocumentType, DocumentFilter.FromGlobPattern umożliwia dalsze ograniczenie stosowania rozszerzenia przez aktywowanie go tylko wtedy, gdy ścieżka pliku dokumentu jest zgodna ze wzorcem symbolu wieloznakowego:
[VisualStudioContribution]
public sealed class TextViewOperationListener
: ExtensionPart, ITextViewOpenClosedListener, ITextViewChangedListener
{
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType("CSharp"),
DocumentFilter.FromGlobPattern("**/tests/*.cs"),
},
};
[VisualStudioContribution]
public sealed class TextViewOperationListener
: ExtensionPart, ITextViewOpenClosedListener, ITextViewChangedListener
{
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType(MyDocumentTypes.MarkdownDocumentType),
DocumentFilter.FromGlobPattern("docs/*.md", relativePath: true),
},
};
Parametr pattern
reprezentuje wzorzec glob, który jest zgodny ze ścieżką bezwzględną dokumentu.
Wzorce globu mogą mieć następującą składnię:
-
*
, aby dopasować zero lub więcej znaków w segmencie ścieżki. -
?
dopasowuje się do jednego znaku w segmencie ścieżki -
**
, aby dopasować dowolną liczbę segmentów ścieżki, w tym brak -
{}
do grupowania warunków (na przykład**/*.{ts,js}
pasuje do wszystkich plików TypeScript i JavaScript) -
[]
, aby zadeklarować zakres znaków do dopasowania w segmencie ścieżki (na przykładexample.[0-9]
do dopasowania wexample.0
,example.1
, ...) -
[!...]
, aby zanegować zakres znaków pasujących w segmencie ścieżki (na przykładexample.[!0-9]
, aby pasować doexample.a
,example.b
, ale nieexample.0
)
Ukośnik odwrotny (\
) nie jest prawidłowy we wzorcu globu. Pamiętaj, aby przekonwertować dowolny ukośnik odwrotny na ukośnik podczas tworzenia wzorca globu.
Dostęp do funkcji edytora
Klasy twojego rozszerzenia edytora dziedziczą z ExtensionPart. Klasa ExtensionPart
uwidacznia właściwość rozszerzalności. Za pomocą tej właściwości można zażądać wystąpienia obiektu EditorExtensibility. Za pomocą tego obiektu można uzyskać dostęp do funkcji edytora czasu rzeczywistego, takich jak wykonywanie edycji.
EditorExtensibility editorService = this.Extensibility.Editor();
Uzyskiwanie dostępu do stanu edytora za pomocą polecenia
ExecuteCommandAsync()
w każdym Command
jest przekazywany IClientContext
zawierający migawkę stanu środowiska IDE w momencie wywołania polecenia. Dostęp do aktywnego dokumentu można uzyskać za pośrednictwem interfejsu ITextViewSnapshot
, który można uzyskać z obiektu EditorExtensibility
, wywołując metodę asynchroniczną GetActiveTextViewAsync
:
using ITextViewSnapshot textView = await this.Extensibility.Editor().GetActiveTextViewAsync(clientContext, cancellationToken);
Gdy masz ITextViewSnapshot
, możesz uzyskać dostęp do stanu edytora.
ITextViewSnapshot
jest niezmiennym widokiem stanu edytora w danym momencie, dlatego należy użyć innych interfejsów w modelu obiektów edytora edytora, aby dokonać edycji.