共用方式為


在編輯器中處理文字

您的擴充功能程式碼可以設定執行,以回應各種進入點(這些是使用者與 Visual Studio 互動時發生的情況)。 編輯器擴充性目前支援三個進入點:接聽程式、EditorExtensibility 服務對象和命令。

當編輯器窗口中發生特定操作時,事件監聽器會被觸發,並以 TextView程式代碼表示。 例如,當使用者在編輯器中輸入某個專案時,就會發生 TextViewChanged 事件。 當編輯器視窗開啟或關閉時,會發生 TextViewOpenedTextViewClosed 事件。

編輯器服務對像是 EditorExtensibility 類別的實例,其會公開即時編輯器功能,例如執行文字編輯。

命令 是由使用者透過點擊項目來啟動的,您可以將其放在選單、內容選單或工具列上。

新增文字視圖監聽器

有兩種類型的監聽器,ITextViewChangedListenerITextViewOpenClosedListener。 這些監聽器可以用來觀察文本編輯器的開啟、關閉與修改。

然後,建立新的類別,實作 ExtensionPart 基類和 ITextViewChangedListenerITextViewOpenClosedListener或兩者,並新增 VisualStudioContribution 屬性。

然後,實作 TextViewExtensionConfiguration 屬性,這是 ITextViewChangedListenerITextViewOpenClosedListener所要求的,讓接聽程式能在編輯 C# 檔案時套用。

public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
    AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },
};

本文稍後 列出其他程式設計語言和文件類型的可用檔類型,而且必要時也可以定義自定義檔類型。

假設您決定實作這兩個接聽程式,則完成的類別宣告看起來應該如下所示:

  [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") },
      };
      ...

由於 ITextViewOpenClosedListenerITextViewChangedListener 宣告 TextViewExtensionConfiguration 属性,因此組態適用於這兩個接聽程式。

當您執行擴充功能時,應該會看到:

每一種方法都會傳遞 ITextViewSnapshot,其中包含使用者叫用動作時文字檢視和文字文件的狀態,以及 IDE 想要取消暫止動作時會有 IsCancellationRequested == true 的 CancellationToken。

定義您的延伸模組何時相關

您的延伸模組通常只與某些支援的文件類型和案例相關,因此請務必清楚定義其適用性。 您可以使用 AppliesTo 組態以數種方式清楚定義擴充功能的適用性。 您可以指定延伸套件支援的檔案類型,例如程式語言,並且/或根據檔名或路徑模式比對進一步調整延伸套件的適用範圍。

使用 AppliesTo 組態指定程式設計語言

AppliesTo 設定表示應啟動擴充功能的程式語言情境。 它會撰寫為 AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },其中檔類型是Visual Studio內建語言的已知名稱,或Visual Studio延伸模組中定義的自定義名稱。

下表顯示一些已知的檔案類型:

文件類型 描述
“CSharp” C#
“C/C++” C、C++、標頭和IDL
“TypeScript” TypeScript 和 JavaScript 類型語言。
“HTML” HTML
“JSON” JSON
"text" 文本檔案,包括從“text”衍生出的階層式“code”子系。
“code” C、C++、C#等等。

DocumentTypes 是階層式的。 也就是說,C# 和 C++都是從 「code」 遞減而來,因此宣告 「code」 會導致您的延伸模組針對所有程式碼語言、C#、C、C++等等啟用。

定義新的檔案類型

您可以定義新的文件類型,例如支援自定義程式代碼語言,方法是將靜態 DocumentTypeConfiguration 屬性新增至擴充專案中的任何類別,並使用 VisualStudioContribution 屬性標記屬性。

DocumentTypeConfiguration 可讓您定義新的檔案類型、指定它繼承一或多個其他檔案類型,以及指定一或多個用來識別檔類型的擴展名:

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,
    };
}

檔類型定義會與舊版 Visual Studio 擴充性所提供的內容類型定義合併,可讓您將其他擴展名對應至現有的檔類型。

文件選擇器

除了 DocumentFilter.FromDocumentType之外,DocumentFilter.FromGlobPattern 允許您設定當文件的檔案路徑符合 glob(通配符)模式時才啟用擴充功能,藉此進一步限制擴充功能的適用性。

[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),
        },
    };

pattern 參數表示一種在文件絕對路徑上匹配的 glob 模式。

Glob 模式可以具有下列語法:

  • *,以比對路徑區段中的零或多個字元
  • ? 用於匹配路徑區段中的一個字元
  • ** 用於配對任何數量的路徑段,包括零路徑段
  • {} 群組條件(例如,**​/*.{ts,js} 符合所有 TypeScript 和 JavaScript 檔案)
  • [] 宣告路徑區段中要符合的字元範圍(例如,example.[0-9]example.0example.1、...)
  • [!...] 否定路徑區段中要比對的字元範圍(例如,example.[!0-9]example.aexample.b上比對,但不 example.0

反斜杠(\)在 glob 模式中無效。 建立 glob 樣式時,請務必將任何反斜杠(\)轉換為斜線(/)。

存取編輯器功能

您的編輯器擴充類別繼承自 ExtensionPartExtensionPart 類別會公開 可擴充性 屬性。 使用這個屬性,您可以要求 EditorExtensibility 對象的實例。 您可以使用這個物件來存取即時編輯器功能,例如執行編輯。

EditorExtensibility editorService = this.Extensibility.Editor();

存取命令內的編輯器狀態

每個 Command 中的 ExecuteCommandAsync() 都會傳遞 IClientContext,其中包含命令被調用時 IDE 狀態的快照。 您可以透過 ITextViewSnapshot 介面存取活動文件,只需從 EditorExtensibility 物件呼叫非同步方法 GetActiveTextViewAsync來取得。

using ITextViewSnapshot textView = await this.Extensibility.Editor().GetActiveTextViewAsync(clientContext, cancellationToken);

一旦擁有 ITextViewSnapshot,您就可以存取編輯器狀態。 ITextViewSnapshot 是編輯器狀態在某個時間點不可變的檢視,因此您必須使用 Editor 物件模型中的其他介面, 進行編輯。