Udostępnij za pośrednictwem


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, ITextViewOpenClosedListenerlub 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:

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ład example.[0-9] do dopasowania w example.0, example.1, ...)
  • [!...], aby zanegować zakres znaków pasujących w segmencie ścieżki (na przykład example.[!0-9], aby pasować do example.a, example.b, ale nie example.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.